记忆库支持通过 API 接口进行操作,在使用 API 接口之前,需要先完成以下操作。
已通过注册账号及开通服务页面操作完成注册账号及开通服务。
子账号授权参考子账号管理。
在调用记忆库的各个能力之前,确保您已生成访问密钥 Access Key。Access Key 包括 Access Key ID(简称为 AK) 和 Access Key Secret(简称为 SK),其中,Access Key ID 用于标识用户,Access Key Secret 用于验证用户的密钥,请您妥善保管。
AK/SK 密钥获取方式如下,更多详情请参考 Access Key(密钥)管理。
签名是 API 请求中的一串经过计算得到的编码字符串,它用于身份认证和防止数据被篡改。
签名不像 ak、sk,每个请求的签名都是独立且临时的,一个签名只能用于一次特定的请求,不能长期固定使用。
签名由签名生成函数 prepare_request 基于以下这些参数计算而来:
参数 | 作用 |
|---|---|
method(请求方法) | 影响签名计算,例如 GET、POST |
path(API 请求路径) | 例如 "/api/collection/create" |
ak(Access Key) | 标识 API 调用者 |
sk(Secret Key) | 用于 HMAC-SHA256 计算签名(需保密) |
params(查询参数) | 适用于 GET 请求等 |
data(请求体) | 适用于 POST、PUT 请求 |
doseq(查询参数的格式控制) | 影响 params 的格式 |
签名生成函数的各语言具体代码见下方说明。(如需了解通过源码生成签名的详情请参考签名源码示例,如需了解通过 SDK 生成签名的详情请参考 SDK 概览)。
安装火山引擎程序包。
pip install volcengine
生成签名。
import json import sys import requests from volcengine.auth.SignerV4 import SignerV4 from volcengine.base.Request import Request from volcengine.Credentials import Credentials def prepare_request(method, path, ak, sk, params=None, data=None, doseq=0): if params: for key in params: if ( type(params[key]) == int or type(params[key]) == float or type(params[key]) == bool ): params[key] = str(params[key]) # elif sys.version_info[0] != 3: # 在 Python 3.x 中,不需要这部分代码 # if type(params[key]) == unicode: # params[key] = params[key].encode("utf-8") elif type(params[key]) == list: if not doseq: params[key] = ",".join(params[key]) r = Request() r.set_shema("https") r.set_method(method) r.set_connection_timeout(10) r.set_socket_timeout(10) mheaders = { "Accept": "application/json", "Content-Type": "application/json", } r.set_headers(mheaders) if params: r.set_query(params) r.set_path(path) if data is not None: r.set_body(json.dumps(data)) # 生成签名 credentials = Credentials(ak, sk, "air", "cn-north-1") SignerV4.sign(r, credentials) return r
安装火山引擎程序包。
go get -u github.com/volcengine/volc-sdk-golang
生成签名。
package main import ( "bytes" "fmt" "net/http" "net/url" "strings" "io/ioutil" "github.com/volcengine/volc-sdk-golang/base" ) const ( testAk = "***" testSk = "***" ) func PrepareRequest(method string, path string, ak string, sk string, query url.Values, body []byte) *http.Request { u := url.URL{ Scheme: "https", Host: "api-knowledgebase.mlp.cn-beijing.volces.com", Path: "/api/knowledge/collection/search", } if query != nil { u.RawQuery = query.Encode() } req, _ := http.NewRequest(strings.ToUpper(method), u.String(), bytes.NewReader(body)) req.Header.Add("Accept", "application/json") req.Header.Add("Content-Type", "application/json") req.Header.Add("Host", "api-knowledgebase.mlp.cn-beijing.volces.com") credential := base.Credentials{ AccessKeyID: ak, SecretAccessKey: sk, Service: "air", Region: "cn-north-1", } req = credential.Sign(req) return req }
安装火山引擎程序包。
<dependency> <groupId>com.volcengine</groupId> <artifactId>volc-sdk-java</artifactId> <version>最新版本</version> </dependency>
“最新版本”的版本号可以在 GitHub 仓库的 README 文件的 “获取与安装” 部分找到,如下图所示。
直接用版本号代码覆盖原“最新版本”即可,比如 1.0.206。
生成签名。
package javaTest; import java.util.List; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.utils.URIBuilder; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import com.volcengine.auth.ISignerV4; import com.volcengine.auth.impl.SignerV4Impl; import com.volcengine.model.Credentials; import com.volcengine.service.SignableRequest; public class sign { public static SignableRequest prepareRequest(String host, String path, String method, List<NameValuePair> params, String body, String ak, String sk) throws Exception { SignableRequest request = new SignableRequest(); request.setMethod(method); request.setHeader("Accept", "application/json"); request.setHeader("Content-Type", "application/json"); request.setHeader("Host", "api-knowledgebase.mlp.cn-beijing.volces.com"); request.setEntity(new StringEntity(body, "utf-8")); URIBuilder builder = request.getUriBuilder(); builder.setScheme("https"); builder.setHost(host); builder.setPath(path); if (params != null) { builder.setParameters(params); } RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(2000).build(); request.setConfig(requestConfig); Credentials credentials = new Credentials("cn-north-1", "air"); credentials.setAccessKeyID(ak); credentials.setSecretAccessKey(sk); // 签名 ISignerV4 ISigner = new SignerV4Impl(); ISigner.sign(request, credentials); return request; }
安装火山引擎程序包。
pnpm add @volcengine/openapi
生成签名。
注:调用函数 signer 生成请求体 header 后,将生成好的 header 注入到用户请求函数中。
import { Signer } from '@volcengine/openapi'; import type { RequestObj } from '@volcengine/openapi/lib/base/types'; interface Options { pathname: string method: 'GET' | 'POST' body?: string // json 字符串,当且仅当 post 请求 region: 'cn-beijing' | 'cn-shanghai' params?: Record<string, any> // 当且仅当 get 请求 } function signer({ pathname, method, body, region, params }: Options) { const requestObj: RequestObj = { region, headers: { Accept: 'application/json', 'Content-type': 'application/json' }, method, body, pathname, params, } const signer = new Signer(requestObj, 'air') signer.addAuthorization({ accessKeyId: 'ak', // 替换为用户 ak secretKey: 'sk', // 替换为用户 sk }) return requestObj.headers }
C#和 PHP 语言目前未提供 SDK 生成签名的方式,可参考对应的源码来生成签名:
C#:https://github.com/volcengine/volc-openapi-demos/blob/main/signature/csharp/Program.cs
PHP:https://github.com/volcengine/volc-openapi-demos/blob/main/signature/php/sign.php
获取好 AK/SK 密钥后,可以将签名生成函数和具体接口调用写进同一个脚本文件中。这里给出将签名生成逻辑与创建记忆库接口对接的实践过程,以 Python 代码为例:
注:main 函数中的 'ak/sk' 参数即为您刚才申请到的 ak/sk
import json import requests from volcengine.base.Request import Request from volcengine.Credentials import Credentials from volcengine.auth.SignerV4 import SignerV4 AK = "your ak" SK = "your sk" Domain = "api-knowledgebase.mlp.cn-beijing.volces.com" def prepare_request(method, path, ak, sk, data=None): r = Request() r.set_shema("http") r.set_method(method) r.set_host(Domain) r.set_path(path) if data is not None: r.set_body(json.dumps(data)) credentials = Credentials(ak, sk, 'air', 'cn-north-1') SignerV4.sign(r, credentials) return r def internal_request(method, api, payload, params=None): req = prepare_request( method = method, path = api, ak = AK, sk = SK, data = payload) r = requests.request(method=req.method, url="{}://{}{}".format(req.schema, req.host, req.path), headers=req.headers, data=req.body, params=params, ) return r #创建记忆库逻辑 path = '/api/memory/collection/create' playload = { 'CollectionName': "my_first_memory_collection", 'Description': "test description", "CustomEventTypeSchemas": [ { "EventType": "english_study", "Description": "记录一次英语学习会话中助教与学生的问答及评分", "Properties": [ { "PropertyName": "knowledge_point_name", "PropertyValueType": "string", "Description": "当前对话涉及的知识点名称" }, { "PropertyName": "question", "PropertyValueType": "string", "Description": "助教提出的问题" }, { "PropertyName": "answer", "PropertyValueType": "string", "Description": "学生的回答" }, { "PropertyName": "rating_score", "PropertyValueType": "float32", "Description": "对学生回答的数值评分,满分为10分" } ] } ], 'CustomProfileTypeSchemas': [ { "ProfileType": "english_knowledge_point", "AssociatedEventTypes": ["english_study"], "Description": "用于追踪学生在特定英语知识点上的学习进展", "Properties": [ { "PropertyName": "id", "PropertyValueType": "int64", "Description": "知识点的唯一主键ID", "IsPrimaryKey": True, "UseProvided": True }, { "PropertyName": "knowledge_point_name", "PropertyValueType": "string", "Description": "知识点具体名称 (例如: \"天气相关词汇\")", "UseProvided": True }, { "PropertyName": "good_evaluation_criteria", "PropertyValueType": "string", "Description": "判断回答为好的评判标准", "UseProvided": True }, { "PropertyName": "rating_score_max", "PropertyValueType": "float32", "Description": "在该知识点上获得过的最高数值评分", "AggregateExpression": { "Op": "MAX", "EventType": "english_study", "EventPropertyName": "rating_score" } } ] } ] } rsp = internal_request('POST', path, playload) print(rsp.json())
鉴权
<dependency> <groupId>com.volcengine</groupId> <artifactId>volc-sdk-java</artifactId> <version>最新版本</version> </dependency>
“最新版本”的版本号可以在 GitHub 仓库的 README 文件的 “获取与安装” 部分找到,如下图所示。
直接用版本号代码覆盖原“最新版本”即可,比如 1.0.206。
创建记忆库
package org.example; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.ObjectMapper; import com.volcengine.auth.ISignerV4; import com.volcengine.auth.impl.SignerV4Impl; import com.volcengine.model.Credentials; import com.volcengine.service.SignableRequest; import lombok.Data; import org.apache.http.Header; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.utils.URIBuilder; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import java.net.URI; import java.util.*; public class Main { public static final String HOST = "api-knowledgebase.mlp.cn-beijing.volces.com"; // 域名 public static final String AK = "your ak"; public static final String SK = "your sk"; public static String toJson(Object obj) { try { // 创建 ObjectMapper 实例 ObjectMapper objectMapper = new ObjectMapper(); // 将对象转换为 JSON 字符串 return objectMapper.writeValueAsString(obj); } catch (Exception e) { e.printStackTrace(); } return null; } public static SignableRequest prepareRequest(String host, String path, String method, List<NameValuePair> params, String body, String ak, String sk) throws Exception { SignableRequest request = new SignableRequest(); request.setMethod(method); request.setHeader("Accept", "application/json"); request.setHeader("Content-Type", "application/json"); request.setHeader("Host", HOST); request.setEntity(new StringEntity(body, "utf-8")); URIBuilder builder = request.getUriBuilder(); builder.setScheme("https"); builder.setHost(host); builder.setPath(path); if (params != null) { builder.setParameters(params); } RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(120000).setConnectTimeout(12000).build(); request.setConfig(requestConfig); Credentials credentials = new Credentials("cn-north-1", "air"); credentials.setAccessKeyID(ak); credentials.setSecretAccessKey(sk); // 签名 ISignerV4 ISigner = new SignerV4Impl(); ISigner.sign(request, credentials); return request; } public static String CreateCollection(Map<String, Object> request) throws Exception { String requestJson = toJson(request); try { SignableRequest signableRequest = prepareRequest(HOST, "/api/memory/collection/create", "POST", null, requestJson, AK, SK); URI uri = new URIBuilder() .setScheme("https") .setHost(HOST) .setPath("/api/memory/collection/create") .build(); HttpPost httpPost = new HttpPost(uri); httpPost.setConfig(signableRequest.getConfig()); httpPost.setEntity(signableRequest.getEntity()); for (Header header : signableRequest.getAllHeaders()) { httpPost.setHeader(header.getName(), header.getValue()); } HttpClient httpClient = HttpClients.createDefault(); HttpResponse response = httpClient.execute(httpPost); int statusCode = response.getStatusLine().getStatusCode(); String responseBody = EntityUtils.toString(response.getEntity()); return responseBody; } catch (Exception e) { e.printStackTrace(); throw e; } } public static void main(String[] args) throws Exception { Map<String, Object> STUDY_MEMORY = new LinkedHashMap<>(); STUDY_MEMORY.put("EventType", "study_demo"); STUDY_MEMORY.put("Version", "1"); STUDY_MEMORY.put("Description", "assistant正在教user学习,记录下所有assistant的问题和user的回答,并给每个回答打分,如果知识点在knowledge_point_demo中不存在,就忽略这个问题,确保所有字段都有值"); List<Map<String, Object>> properties = new ArrayList<>(); properties.add(Map.of( "PropertyName", "knowledge_point_name", "PropertyValueType", "string", "Description", "收集到的知识点", "DefaultValue", "" )); properties.add(Map.of( "PropertyName", "question", "PropertyValueType", "string", "Description", "assistant的原始问题", "DefaultValue", "" )); properties.add(Map.of( "PropertyName", "answer", "PropertyValueType", "string", "Description", "user的原始回答", "DefaultValue", "" )); properties.add(Map.of( "PropertyName", "is_user_answered", "PropertyValueType", "bool", "Description", "user是否对问题做了回答", "DefaultValue", false )); properties.add(Map.of( "PropertyName", "rating", "PropertyValueType", "string", "Description", "给user的回答打分,值为'bad', 'good'中的一种", "DefaultValue", "good" )); properties.add(Map.of( "PropertyName", "rating_reasoning", "PropertyValueType", "string", "Description", "打分的依据", "DefaultValue", "" )); properties.add(Map.of( "PropertyName", "issues", "PropertyValueType", "list<string>", "Description", "需要关注的点,最多保留3个", "DefaultValue", new ArrayList<>() )); properties.add(Map.of( "PropertyName", "rating_score", "PropertyValueType", "int64", "Description", "值为0或1,表示给user的回答打分,分别对应0:bad, 1:good", "DefaultValue", 0 )); properties.add(Map.of( "PropertyName", "has_been_taught", "PropertyValueType", "int64", "Description", "是否给用户教学了该知识点,如果是,返回1,否则返回0", "DefaultValue", 0 )); properties.add(Map.of( "PropertyName", "is_answer_good", "PropertyValueType", "int64", "Description", "是否回答正确,如果是,返回1,否则返回0", "DefaultValue", 0 )); properties.add(Map.of( "PropertyName", "is_answer_bad", "PropertyValueType", "int64", "Description", "是否回答错误,如果是,返回1,否则返回0", "DefaultValue", 1 )); STUDY_MEMORY.put("Properties", properties); STUDY_MEMORY.put("ValidationExpression", "is_user_answered==True"); Map<String, Object> KNOWLEDGE_POINT_DEMO = new LinkedHashMap<>(); KNOWLEDGE_POINT_DEMO.put("ProfileType", "knowledge_point_demo"); KNOWLEDGE_POINT_DEMO.put("Version", "1"); KNOWLEDGE_POINT_DEMO.put("AssociatedEventTypes", List.of("study_demo")); KNOWLEDGE_POINT_DEMO.put("Role", "user"); KNOWLEDGE_POINT_DEMO.put("Description", "知识点"); List<Map<String, Object>> profileProperties = new ArrayList<>(); profileProperties.add(new LinkedHashMap<String, Object>() {{ put("PropertyName", "id"); put("PropertyValueType", "string"); put("Description", "主键"); put("IsPrimaryKey", true); put("UseProvided", true); put("AggregateExpression", null); put("DefaultValue", null); }}); profileProperties.add(new LinkedHashMap<String, Object>() {{ put("PropertyName", "knowledge_point_desc"); put("PropertyValueType", "string"); put("Description", "知识点的描述,必填"); put("IsPrimaryKey", false); put("UseProvided", true); put("AggregateExpression", null); put("DefaultValue", null); }}); profileProperties.add(new LinkedHashMap<String, Object>() {{ put("PropertyName", "knowledge_point_name"); put("PropertyValueType", "string"); put("Description", "知识点的名称"); put("IsPrimaryKey", true); put("UseProvided", true); put("AggregateExpression", null); put("DefaultValue", null); }}); profileProperties.add(new LinkedHashMap<String, Object>() {{ put("PropertyName", "difficulty_level"); put("PropertyValueType", "list<int64>"); put("Description", "知识点的难度级别1到5之间的一个数字,1最简单,5最难,必填"); put("IsPrimaryKey", false); put("UseProvided", false); put("AggregateExpression", null); put("DefaultValue", null); }}); profileProperties.add(new LinkedHashMap<String, Object>() {{ put("PropertyName", "knowledge_start_time"); put("PropertyValueType", "int64"); put("Description", "知识点第一次教学的时间,记录第一次教学的时间,时间为年月日时分秒"); put("DefaultValue", null); }}); profileProperties.add(new LinkedHashMap<String, Object>() {{ put("PropertyName", "rating_score_max"); put("PropertyValueType", "float32"); put("Description", "打分最高值"); put("IsPrimaryKey", false); put("UseProvided", false); put("AggregateExpression", Map.of( "Op", "MAX", "EventType", "study_demo", "EventPropertyName", "rating_score" )); put("DefaultValue", null); }}); profileProperties.add(new LinkedHashMap<String, Object>() {{ put("PropertyName", "has_been_taught"); put("PropertyValueType", "int64"); put("Description", "是否给用户讲解了该知识点"); put("IsPrimaryKey", false); put("UseProvided", false); put("AggregateExpression", Map.of( "Op", "MAX", "EventType", "study_demo", "EventPropertyName", "has_been_taught" )); put("DefaultValue", null); }}); profileProperties.add(new LinkedHashMap<String, Object>() {{ put("PropertyName", "answer_good_count"); put("PropertyValueType", "int64"); put("Description", "回答正确的数量"); put("IsPrimaryKey", false); put("UseProvided", false); put("AggregateExpression", Map.of( "Op", "SUM", "EventType", "study_demo", "EventPropertyName", "is_answer_good" )); put("DefaultValue", null); }}); profileProperties.add(new LinkedHashMap<String, Object>() {{ put("PropertyName", "answer_bad_count"); put("PropertyValueType", "int64"); put("Description", "回答错误的数量"); put("IsPrimaryKey", false); put("UseProvided", false); put("AggregateExpression", Map.of( "Op", "SUM", "EventType", "study_demo", "EventPropertyName", "is_answer_bad" )); put("DefaultValue", null); }}); profileProperties.add(new LinkedHashMap<String, Object>() {{ put("PropertyName", "rating_score_sum"); put("PropertyValueType", "float32"); put("Description", "打分总和"); put("IsPrimaryKey", false); put("UseProvided", false); put("AggregateExpression", Map.of( "Op", "SUM", "EventType", "study_demo", "EventPropertyName", "rating_score" )); put("DefaultValue", null); }}); profileProperties.add(new LinkedHashMap<String, Object>() {{ put("PropertyName", "issues"); put("PropertyValueType", "list<string>"); put("Description", "需要关注的点,最多保留5个"); put("IsPrimaryKey", false); put("UseProvided", false); put("AggregateExpression", Map.of( "Op", "LLM_MERGE", "EventType", "study_demo", "EventPropertyName", "issues" )); put("DefaultValue", null); }}); profileProperties.add(new LinkedHashMap<String, Object>() {{ put("PropertyName", "count"); put("PropertyValueType", "int64"); put("Description", "数量"); put("IsPrimaryKey", false); put("UseProvided", false); put("AggregateExpression", Map.of( "Op", "COUNT", "EventType", "study_demo", "EventPropertyName", "rating_score" )); put("DefaultValue", null); }}); KNOWLEDGE_POINT_DEMO.put("Properties", profileProperties); // 构建请求 payload Map<String, Object> payload = new LinkedHashMap<>(); payload.put("CollectionName", "test_memory"); payload.put("Description", "test description"); payload.put("BuiltinEventTypes", List.of("sys_event_v1")); payload.put("CustomEventTypeSchemas", List.of(STUDY_MEMORY)); payload.put("CustomProfileTypeSchemas", List.of(KNOWLEDGE_POINT_DEMO)); System.out.println(CreateCollection(payload)); } }