孟子生成式大模型
发送 POST 请求到:
澜舟科技孟子 GPT 服务所提供的 API 接口均通过 HTTPS 进行通信,提供高安全性的通信通道。
孟子 GPT 按实际调用服务的输入及输出 token 数的总和进行收费。
token 是模型用来处理自然语言的基本单位,一个 token 可以理解成一个汉语词组或者一个英文单词,一般情况下,澜舟孟子 GPT 模型 token 数量和字数的换算比例大概为 1:1.33 左右。
示例: 你知道牛顿吗
对应 token 数为 4。
请求头参数 | 是否必须 | 描述 |
---|---|---|
Accept | 是 | 固定值 application/json 。 |
Authorization | 是 | 用于验证请求合法性的认证信息,值为 AccessKey:signature 格式。 |
Content-Type | 是 | 固定值 application/json 。 |
Content-MD5 | 是 | HTTP 协议消息体的 128-bit MD5 散列值转换成 Base64 编码的结果。 |
Date | 是 | 请求时间,GMT 格式,如: Wed, 20 Apr. 2022 17:01:00 GMT。 |
x-langboat-signature-nonce | 是 | 唯一随机数,用于防止网络重放攻击。在不同请求中要使用不同的随机数值。 |
x-langboat-signature-method | 是 | 签名方法,目前只支持 HMAC-SHA256 。 |
Content-MD5
Header。计算示例:
{"model": "mengzi-lite","messages": [{"role": "user","content": "你知道牛顿吗"}],"n": 1,"max_tokens": 1024,"user": ""}
byte(05e24d61412c8cd0403be206f644e8dc)
BeJNYUEsjNBAO+IG9kTo3A=
Content-MD5 Header: Content-MD5: BeJNYUEsjNBAO+IG9kTo3A=
StringToSign =HTTP-Verb + "\n" + //HTTP-Verb只支持POSTAccept + “\n” + //Accept为application/jsonContent-MD5 + "\n" + //第1步中计算出来的MD5值Content-Type + "\n" + //Content-Type值为application/jsonDate + "\n" + //Date值为GMT时间x-langboat-signature-method + "\n" + // 只支持 HMAC-SHA256x-langboat-signature-nonce + "\n";
StringToSign 示例:
POSTapplication/jsonBeJNYUEsjNBAO+IG9kTo3A=application/jsonWed, 20 Apr 2022 02:50:21 GMTHMAC-SHA25653371
a=b&c=d
孟子GPT API 中 所有参数均放在 body,所以这里可以传空。
stringToSign = headerStringToSign + queryToSign;
Signature = Base64(HMAC-SHA256( AccessSecret, UTF-8-Encoding-Of(stringToSign)))Authorization = AccessKey + ":" + Signature
Signature 示例:po/vsPI0RcvY/eu4bohhxxADHyPj4/rcglLTQEBtHQM=
Authorization 示例:
Authorization: 7Bo9ByyiTWRC1Y8KJJQ9cWtNpZLmrgyb:po/vsPI0RcvY/eu4bohhxxADHyPj4/rcglLTQEBtHQM=
Body 参数 | 类型 | 是否必须 | 描述 |
---|---|---|---|
model | string | 是 | 模型名称,示例 mengzi-lite ,详细见模型列表。 |
messages | List(message) | 是 | 聊天上下文信息。 |
temperature | float | 否 | 基于温度系数的采样系数,值越大,输出越随机。有些模型不支持,详细见模型列表。 |
top_p | float | 否 | 核采样,功能类似 temperature,两个值最好不要同时修改。有些模型不支持,详细见模型列表。 |
n | int | 否 | 返回数量,取值范围 [1,3],默认 1。 |
stream | bool | 否 | 是否以流式接口的形式返回数据,默认 false,有些模型不支持,详细见模型列表。 |
max_tokens | int | 否 | 生成 tokens 最大数量,详细见模型列表。 |
user | string | 否 | 用户的标识,可用于检测滥用行为,以防止接口恶意调用。 |
模型 | 模型名称 | 最大content长度 | 是否支持 stream | 是否支持 temperature | 是否支持 top_p | 是否支持max_tokens |
---|---|---|---|---|---|---|
mengzi-lite | 孟子大模型-轻量 | 4000 字符 | 是 | 是,默认 0.1,取值范围 [0,1]。 | 是,默认 0.95,取值范围 [0,1]。 | 是,默认 4096,取值范围 [1,4096]。 |
mengzi-fin | 孟子大模型-金融 | 1500 字符 | 是 | 是,默认 0.2,取值范围 [0,1]。 | 是,默认 0.95,取值范围 [0,1]。 | 是,默认 2048,取值范围 [1,4096]。 |
mengzi-code | 孟子大模型-编程 | 5000 字符 | 是 | 是,默认 0.2,取值范围 [0,1]。 | 是,默认 0.95,取值范围 [0,1]。 | 是,默认 4096,取值范围 [1,4096]。 |
{"model": "mengzi-lite","messages": [{"role": "user","content": "你知道牛顿吗"}],"temperature": 0.1,"top_p": 0.05,"n": 1,"stream": false,"max_tokens": 4096,"user": ""}
请求示例:
POST https://open.langboat.com/chatContent-Type: application/jsonContent-MD5: BeJNYUEsjNBAO+IG9kTo3A==Date: Tue, 19 Apr 2022 10:03:46 GMTAccept: application/jsonx-langboat-signature-method: HMAC-SHA256x-langboat-signature-nonce: 43785Authorization: 7Bo9ByyiTWRC1Y8KJJQ9cWtNpZLmrgyb:po/vsPI0RcvY/eu4bohhxxADHyPj4/rcglLTQEBtHQM=
成功的响应体是一个 JSON, 示例:
{"id": "chatcmpl-1135c2751ec9c45ec5d525303500d548","object": "chat.completion","created": 1692865424,"model": "mengzi-lite","choices": [{"index": 0,"message": {"role": "assistant","content": "当然了!伊萨克·牛顿(Isaac Newton)是一位伟大的英国物理学家、数学家和自然哲学家,被认为是现代科学之父之一。他最著名的成就是发现了万有引力定律以及三大运动定律,这些理论对我们理解宇宙产生了深远影响。此外,他在光学、微积分等领域也做出了重要贡献。"},"finish_reason": "stop"}],"usage": {"prompt_tokens": 4,"completion_tokens": 99,"total_tokens": 103}}
名称 | 类型 | 描述 |
---|---|---|
id | string | 本次接口调用会话id |
object | string | 回包类型, 非 stream:chat.completion, stream:chat.chunk |
created | int | 时间戳 |
model | string | 模型名称 |
choices | List(choice) | 聊天详情 |
usage | usage | 本次调用统计信息 |
名称 | 类型 | 描述 |
---|---|---|
index | 索引 | 对应请求参数 n |
message | List(message) | 结构同输入 message |
finish_reason | string | 回答结束的原因 |
message
对应字段为delta
。名称 | 类型 | 描述 |
---|---|---|
prompt_tokens | int | 问题的 token 数 |
completion_tokens | int | 回答的 token 数 |
total_tokens | int | 总的 token 数 |
下面是可能的 HTTP 响应状态码、业务(错误)编码:
HTTP 状态码 | 业务编码 | 描述 |
---|---|---|
200 | 0 | 返回成功 |
400 | 10400 | 请求异常 |
401 | 10401 | 鉴权失败,核对 AccessKey 和 AccessSecret 是否正确 |
403 | 10403 | 权限不足,查看是否开通服务 |
422 | 10422 | 参数错误,核对请求参数 |
429 | 10429 | 超过请求限制(QPS,字符数,次数超过限制,当前排队人数过多) |
500 | 10500 | 服务异常 |
错误响应示例
{"error": {"code": 10403,"message": "AccessKey 不存在, 请检查 AccessKey 是否正确","requestId": "6f233f3e276bc1ba2ffb0069df62cd1b"}}
{"error": {"code": 10403,"message": "权限不足,查看是否开通服务","requestId": "6f233f3e276bc1ba2ffb0069df62cd1b"}}
stream 模式下,按照句子片段进行输出。如果生成结果比较短,可能只有一个片段。
curl 'http://open.langboat.com/chat' \--header 'Content-MD5: WkwTeY7YOwSSeyB09sF6ow==' \--header 'x-langboat-signature-method: HMAC-SHA256' \--header 'x-langboat-signature-nonce: 43785' \--header 'Authorization: mWve3ivAD1NljBkCj7Pk2eZQQB3PmMt6:MyJ/1mthTM51zHVXOr13+8RhjMAuGIhKttKFr+nb6hs=' \--header 'Date: Thu, 16 Jun 2022 13:09:33 GMT' \--header 'Content-Type: application/json' \--data '{"model": "mengzi-lite","messages": [{"role":"user","content":"你知道牛顿吗"}],"temperature": 1,"top_p": 0,"n": 1,"stream": true,"max_tokens": 4096,"user": ""}'
id: 0-0data: {"id":"chatcmpl-dac45d8d2fd528f46afdda15be6a4e63","object":"chat.completion.chunk","created":1692865308,"model":"mengzi-lite","choices":[{"index":0,"delta":{"content":"当然了!伊萨克·牛顿(Isaac Newton)是一位伟大的英国物理学家、数学家和自然哲学家,被认为是现代科学之父之一。"},"finish_reason":null}]}id: 0-1data: {"id":"chatcmpl-dac45d8d2fd528f46afdda15be6a4e63","object":"chat.completion.chunk","created":1692865309,"model":"mengzi-lite","choices":[{"index":0,"delta":{"content":"他最著名的成就是发现了万有引力定律以及三大运动定律,这些理论对我们理解宇宙产生了深远影响。"},"finish_reason":null}]}id: 0-2data: {"id":"chatcmpl-dac45d8d2fd528f46afdda15be6a4e63","object":"chat.completion.chunk","created":1692865309,"model":"mengzi-lite","choices":[{"index":0,"delta":{"content":"此外,他在光学、微积分等领域也做出了重要贡献。"},"finish_reason":null}]}data: [DONE]
curl 'http://open.langboat.com/chat' \--header 'Content-MD5: WkwTeY7YOwSSeyB09sF6ow==' \--header 'x-langboat-signature-method: HMAC-SHA256' \--header 'x-langboat-signature-nonce: 43785' \--header 'Authorization: mWve3ivAD1NljBkCj7Pk2eZQQB3PmMt6:MyJ/1mthTM51zHVXOr13+8RhjMAuGIhKttKFr+nb6hs=' \--header 'Date: Thu, 16 Jun 2022 13:09:33 GMT' \--header 'Content-Type: application/json' \--data '{"model": "mengzi-lite","messages": [{"role":"user","content":"你好"}],"temperature": 0.1,"top_p": 0.05,"n": 1,"stream": true,"max_tokens": 4096,"user": ""}'
id: 0-0data: {"id":"chatcmpl-dac45d8d2fd528f46afdda15be6a4e63","object":"chat.completion.chunk","created":1692865308,"model":"mengzi-lite","choices":[{"index":0,"delta":{"content":"你好,有什么需要帮助的吗?"},"finish_reason":null}]}data: [DONE]
Dependencies:
<dependencies><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.14.0</version></dependency></dependencies>
Code:
package com.langboat.client;import com.fasterxml.jackson.databind.ObjectMapper;import javax.crypto.Mac;import javax.crypto.spec.SecretKeySpec;import java.net.URI;import java.net.http.HttpClient;import java.net.http.HttpRequest;import java.net.http.HttpResponse;import java.security.MessageDigest;import java.text.SimpleDateFormat;import java.time.Duration;import java.util.*;import java.util.stream.Stream;/*** 澜舟开放平台 chat 客户端*/public class LangboatOpenChatClient {private final String accessKey;private final String accessSecret;private final String url;private final ObjectMapper objMapper = new ObjectMapper();public LangboatOpenChatClient(String accessKey, String accessSecret) {this.accessKey = accessKey;this.accessSecret = accessSecret;this.url = "https://open.langboat.com";}public LangboatOpenChatClient(String accessKey, String accessSecret, String url) {this.accessKey = accessKey;this.accessSecret = accessSecret;this.url = url;}/** 计算 MD5 + Base64*/private String MD5Base64(String s) {if (s == null)return null;String encodeStr = "";byte[] utfBytes = s.getBytes();MessageDigest mdTemp;try {mdTemp = MessageDigest.getInstance("MD5");mdTemp.update(utfBytes);byte[] md5Bytes = mdTemp.digest();encodeStr = Base64.getEncoder().encodeToString(md5Bytes);} catch (Exception e) {throw new Error("Failed to generate MD5 : " + e.getMessage());}return encodeStr;}/** 计算 HMAC-SHA256 + Base64 编码*/private String HMACSha256Base64(String data, String key) {String result;try {SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), "HmacSHA256");Mac mac = Mac.getInstance("HmacSHA256");mac.init(signingKey);byte[] rawHmac = mac.doFinal(data.getBytes());result = Base64.getEncoder().encodeToString(rawHmac);} catch (Exception e) {throw new Error("Failed to generate HMAC : " + e.getMessage());}return result;}/** 获取时间*/private String toGMTString(Date date) {SimpleDateFormat df = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH);df.setTimeZone(new java.util.SimpleTimeZone(0, "GMT"));return df.format(date);}public Object chat(Map<String, String> queries, Map<String, Object> data) throws Exception {String body = this.objMapper.writeValueAsString(data);String method = "POST";String accept = "application/json";String contentType = "application/json";String date = toGMTString(new Date());// 1.对body做MD5+BASE64加密String bodyMd5 = MD5Base64(body);String nonce = "" + (int) (Math.random() * 65535);String headerToSign = method + "\n" + accept + "\n" + bodyMd5 + "\n"+ contentType + "\n" + date + "\n"+ "HMAC-SHA256\n"+ nonce + "\n";// 2.计算 queryToSignList<String> queriesList = new ArrayList<>();queries.forEach((k, v) -> queriesList.add(k + "=" + v));Collections.sort(queriesList);String queryToSign = String.join("&", queriesList);// 3.计算 stringToSignString stringToSign = headerToSign + queryToSign;// 4.计算 HMAC-SHA256 + Base64String signature = HMACSha256Base64(stringToSign, this.accessSecret);// 5.得到 authorization header 值String authorization = this.accessKey + ":" + signature;HttpRequest request = HttpRequest.newBuilder().uri(URI.create(this.url + "/chat")).timeout(Duration.ofSeconds(60)).header("Accept", accept).header("Content-Type", contentType).header("Content-MD5", bodyMd5).header("Date", date).header("Authorization", authorization).header("x-langboat-signature-nonce", nonce).header("x-langboat-signature-method", "HMAC-SHA256").POST(HttpRequest.BodyPublishers.ofString(body)).build();HttpClient client = HttpClient.newHttpClient();if ((boolean) data.get("stream")) {final HttpResponse<Stream<String>> response = client.send(request, HttpResponse.BodyHandlers.ofLines());if (response.statusCode() == 200) {response.body().forEach(System.out::println);return response.body();} else {System.out.println(response.body());throw new RuntimeException("请求失败");}} else {final HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());if (response.statusCode() == 200) {System.out.println(response.body());return response.body();} else {System.out.println(response.statusCode());System.out.println(response.body());throw new RuntimeException("请求失败");}}}public static void main(String[] args) throws Exception {LangboatOpenChatClient client = new LangboatOpenChatClient("YourAccessKey", "YourAccessSecret");// 通用中英翻译Map<String, String> queries = Map.of();Map<String, Object> data = Map.of("model", "mengzi-lite","stream", true,"messages", List.of(Map.of("role", "user","content", "你知道牛顿吗")),"max_tokens", 1024,"user", "");Object o = client.chat(queries, data);System.out.println(o);}}
# -*- coding: utf-8 -*-import base64import datetimeimport hashlibimport hmacimport jsonimport randomimport requestsclass LangboatOpenClient:"""澜舟开放平台客户端"""def __init__(self,access_key: str,access_secret: str,url: str = "https://open.langboat.com"):self.access_key = access_keyself.access_secret = access_secretself.url = urldef _build_header(self, query: dict, data: dict) -> dict:accept = "application/json"# 1. body MD5 加密content_md5 = base64.b64encode(hashlib.md5(json.dumps(data).encode("utf-8")).digest()).decode()content_type = "application/json"gmt_format = '%a, %d %b %Y %H:%M:%S GMT'date = datetime.datetime.utcnow().strftime(gmt_format)signature_method = "HMAC-SHA256"signature_nonce = str(random.randint(0, 65535))header_string = f"POST\n{accept}\n{content_md5}\n{content_type}\n" \f"{date}\n{signature_method}\n{signature_nonce}\n"# 2. 计算 queryToSignqueries_str = []for k, v in sorted(query.items(), key=lambda item: item[0]):if isinstance(v, list):for i in v:queries_str.append(f"{k}={i}")else:queries_str.append(f"{k}={v}")queries_string = '&'.join(queries_str)# 3.计算 stringToSignsign_string = header_string + queries_string# 4.计算 HMAC-SHA256 + Base64secret_bytes = self.access_secret.encode("utf-8")# 5.计算签名signature = base64.b64encode(hmac.new(secret_bytes, sign_string.encode("utf-8"), hashlib.sha256).digest()).decode()res = {"Content-Type": content_type,"Content-MD5": content_md5,"Date": date,"Accept": accept,"X-Langboat-Signature-Method": signature_method,"X-Langboat-Signature-Nonce": signature_nonce,"Authorization": f"{self.access_key}:{signature}"}return resdef inference(self, queries: dict, data: dict) -> (int, dict):"""服务调用: POST https://open.langboat.com/chat:param queries: query 参数:param data: request body 数据:return: response status, response body to json"""headers = self._build_header(queries, data)response = requests.post(url=self.url + "/chat",headers=headers, params=queries, json=data)return response.status_code, response.json()if __name__ == '__main__':_access_key = '<Your access_key>'_access_secret = '<Your access_secret>'client = LangboatOpenClient(access_key=_access_key,access_secret=_access_secret)# 孟子GPT_queries = {}_data = {"model": "mengzi-lite","messages": [{"role": "user","content": "你知道牛顿吗"}],"n": 1,"max_tokens": 1024,"user": ""}status_code, result = client.inference(_queries, _data)print("response status:", status_code)print("response json:", json.dumps(result, ensure_ascii=False, indent=2))
package mainimport ("crypto/hmac""crypto/md5""crypto/sha256""encoding/base64""fmt""io/ioutil""log""math/rand""net/http""net/url""sort""strings""time")func main() {client := OpenClient{baseURL: "https://open.langboat.com",accessKey: "Your_Access_Key",accessSecret: "Your_Access_Secret",}reqBody := `{"model":"mengzi-lite","messages":[{"role":"user","content":"你知道牛顿吗"}],"temperature":1,"top_p":0,"n":1,"stream":false,"max_tokens":1024,"user":""}`resp := client.inference(reqBody)response, ok := resp.(*http.Response)if !ok {log.Fatal("fail to convert response")}body, err := ioutil.ReadAll(response.Body)if err != nil {log.Fatal("fail to read response body")}log.Println(string(body))}type OpenClient struct {baseURL stringaccessKey stringaccessSecret string}func (c *OpenClient) inference(body string) interface{} {targetURL := c.baseURL + "/chat"client := &http.Client{Timeout: 60 * time.Second,}// 构造headervar (payload = strings.NewReader(body)date = time.Now().UTC().Format(http.TimeFormat)nonce = fmt.Sprint(10000 + rand.Intn(89999)))// 签名signParam := SignParam{Body: body,DateGMT: date,Nonce: nonce,}contentMD5, signature := GenSignature(signParam, c.accessSecret)// 设置headerheaders := map[string]string{"Authorization": c.accessKey + ":" + signature,"Content-Type": "application/json","Accept": "application/json","Date": date,"Content-MD5": contentMD5,"x-langboat-signature-method": "HMAC-SHA256","x-langboat-signature-nonce": nonce,}req, _ := http.NewRequest("POST", targetURL, payload)for k, v := range headers {req.Header.Add(k, v)}resp, err := client.Do(req)if err != nil {log.Println(err.Error())}return resp}// SignParam 生成签名需要的参数type SignParam struct {Body string // body数据Query string // 原始queryDateGMT string // GTM时间Nonce string // 随机数}func getMD5(str string) []byte {h := md5.New()h.Write([]byte(str))return h.Sum(nil)}func hmacSha256(data string, secret string) []byte {h := hmac.New(sha256.New, []byte(secret))h.Write([]byte(data))return h.Sum(nil)}func resortQuery(src string) string {queries, _ := url.ParseQuery(src)keys := make([]string, 0)for k := range queries {keys = append(keys, k)}sort.Strings(keys)newQuery := url.Values{}for _, k := range keys {for _, value := range queries[k] {newQuery.Add(k, value)}}return newQuery.Encode()}// GenSignature 生成签名func GenSignature(src SignParam, accessSecret string) (string, string) {// 计算body的md5值md5str := getMD5(src.Body)// base64后得到contentMD5contentMD5 := base64.StdEncoding.EncodeToString(md5str)// query解析,并按照字典序重新排列query := resortQuery(src.Query)query, _ = url.QueryUnescape(query)// 需要做签名的字符串结构stringToSign := `POSTapplication/json%sapplication/json%sHMAC-SHA256%s%s`stringToSign = fmt.Sprintf(stringToSign, contentMD5, src.DateGMT, src.Nonce, query)hmac256 := hmacSha256(stringToSign, accessSecret)signature := base64.StdEncoding.EncodeToString(hmac256)return contentMD5, signature}