猿媒BOT OpenAPI 功能只能使用平台余额
基础配置
baseUrl: "https://bot.apetd.com/api/openapi"
headers: {
apikey: "yuanmei-r5lbdhot32hvcfd1wg12"
}
接口
应用
V1应用对话(将于7月18日弃用,请更换V2版)
通过 api 形式去请求应用进行对话。目前 gpt 模型需要完整传入 prompts,claude可以只传 chatId。
请求
curl --location 'https://bot.apetd.com/api/openapi/chat/chat' \
--header 'apikey: 63f9a12228d2a638d839e11b-r5lbdhot32h33fd1wg12' \
--header 'Content-Type: application/json' \
--data '{
"chatId": "可选,claude才有效",
"modelId": "642989b537d6e4b98e4a1037",
"isStream": false,
"prompts": [
{
"obj": "System",
"value": "下面是 AI 和 Human 的对话,讨论 laf 的内容。"
},
{
"obj": "Human",
"value": "什么是 laf"
},
{
"obj": "AI",
"value": "laf 是云开发平台...."
},
{
"obj": "Human",
"value": "laf 可以做什么?"
},
]
}'
响应
{
"code": 200,
"statusText": "",
"data": "laf是********"
}
V2 应用对话
V2 对话完全兼容 openai 的接口!如果你有第三方项目,可以直接通过修改 BaseUrl 和 Authorization 来访问 猿媒BOT 应用
请求
- Authorization: 由 3 部分组成: Bearer ,apikey 和 appId。
例如: ‘Bearer yuanmei-z51pkjqm9nrk03a1rx2funoy-642adec15f04d67d4613efdb’。Bearer需手动添加,apiKey 直接在应用页生成,appId 在应用也 API 栏取。
- chatId: string | undefined 。
- 为 undefined 时(不传入),不使用 猿媒BOT 提供的上下文功能,完全通过传入的 messages 构建上下文。
- 为空字符 ” 时,表示新窗口第一次对话。响应值会有一个 newChatId
- 为非空字符串时,意味着使用 chatId 进行对话,自动从 猿媒BOT 数据库取历史记录。
- messages: 与 openai gpt 接口完全一致。
curl --location --request POST 'https://bot.apetd.com/api/openapi/v1/chat/completions' \
--header 'Authorization: Bearer apikey-appId' \
--header 'User-Agent: Apifox/1.0.0 (https://www.apifox.cn)' \
--header 'Content-Type: application/json' \
--data-raw '{
"chatId":"",
"stream":false,
"messages": [
{
"content": "导演是谁",
"role": "user"
}
]
}'
响应特殊参数说明:
- quoteLen: 当次请求引用知识库的数量(查询具体引用接口后面再补)
- newChatId(string | null): 新对话的ID,下次只需要传入这个 id,就会拥有上下文
Stream 响应
event: chatResponse
data: {"newChatId": "648f0fc12e0d47315f3bc30e","quoteLen":5}
event: answer
data: {"id":"","object":"","created":0,"choices":[{"delta":{"content":""},"index":0,"finish_reason":null}]}
event: answer
data: {"id":"","object":"","created":0,"choices":[{"delta":{"content":"电"},"index":0,"finish_reason":null}]}
event: answer
data: {"id":"","object":"","created":0,"choices":[{"delta":{"content":"影"},"index":0,"finish_reason":null}]}
event: answer
data: {"id":"","object":"","created":0,"choices":[{"delta":{"content":"《"},"index":0,"finish_reason":null}]}
event: answer
data: {"id":"","object":"","created":0,"choices":[{"delta":{"content":"铃"},"index":0,"finish_reason":null}]}
event: answer
data: [DONE]
非 Stream 响应
{
"rawSearch": [
{
"id": "19339",
"q": "电影《铃芽之旅》的导演是谁?",
"a": "电影《铃芽之旅》的导演是新海诚。",
"source": ""
},
{
"id": "8099",
"q": "本作的主人公是谁?",
"a": "本作的主人公是名叫铃芽的少女。",
"source": "手动修改"
}
],
"newChatId": "648f0fc12e0d47315f3bc30e",
"id": "",
"model": "gpt-3.5-turbo-16k",
"usage": {
"prompt_tokens": 0,
"completion_tokens": 0,
"total_tokens": 373
},
"choices": [
{
"message": [
{
"role": "assistant",
"content": "电影《玲芽之旅》的导演是新海诚。"
}
],
"finish_reason": "stop",
"index": 0
}
]
}
应用搜索(Beta版,仅做测试,不要上生产)
仅搜索,不进行对话,会返回搜索的结果。目前仅支持搜索最后一个问题,即 prompts[prompts.length-1]
请求
- similarity – 向量距离,取值 0~1,越大表示越相似
- limit – 搜索多少条
curl --location --request POST 'https://bot.apetd.com/api/openapi/kb/appKbSearch' \
--header 'apikey: 222' \
--header 'Content-Type: application/json' \
--data-raw '{
"appId": "642adec15f01d67d4613efdb",
"similarity": 0.8,
"limit": 5,
"prompts": [
{
"obj": "Human",
"value": "导演是谁"
}
]
}'
响应
- rawSearch – 数据库原始数据
- userSystemPrompt- 提示词
- quotePrompt – 知识库相关的提示词
{
"code": 200,
"statusText": "",
"data": {
"code": 200,
"rawSearch": [
{
"id": "19339",
"q": "电影《铃芽之旅》的导演是谁?",
"a": "电影《铃芽之旅》的导演是新海诚。"
}
],
"userSystemPrompt": {
"obj": "System",
"value": "知识库:电影《铃芽之旅》的导演是谁?\n电影《铃芽之旅》的导演是新海诚。\n电影《铃芽之旅》的编剧是谁?\n新海诚是本片的编剧。\n本作的主人公是谁?\n本作的主人公是名叫铃芽的少女。\n电影《铃芽之旅》男主角是谁?\n电影《铃芽之旅》男主角是宗像草太,由松村北斗配音。\n电影《铃芽之旅》的制作团队中有哪位著名人士?\n川村元气是本片的制作团队成员之一。\n电影中的后门是指什么?\n后门是连接往生者世界“常世”与人类所处的“现世”的门扉,平常仰赖人们心中的重量和思绪镇定土地和门。若是人心的重量消失,等于从人们的记忆中消失或思绪减少,将会导致后门被打开。一个人一生中最多只能通过一道后门。\n谁担任电影《铃芽之旅》中草太的祖父宗像羊朗的声演人员?\n松本白鹦担任电影《铃芽之旅》中草太的祖父宗像羊朗的声演人员。\n电影中的关门师是指什么?\n关门师是为了防范“门”被打开延伸的灾难,负责将出现在世上的“门”封闭的特殊人群。关门师进行封闭“门”的过程中,会先想著曾在该土地上生活的人们,感受该土地过往的景色与人事物,借此打开“门”的钥匙孔,再咏唱归还土地予神明的咒文,使用特制的钥匙将“门”锁上。\n电影《铃芽之旅》的女主角是谁?\n电影的女主角是铃芽。\n电影《铃芽之旅》的女主角是谁?\n电影《铃芽之旅》的女主角是岩户铃芽,由原菜乃华配音。\n谁担任电影《铃芽之旅》中岩户环的配音?\n深津绘里担任电影《铃芽之旅》中岩户环的配音。\n谁担任电影《铃芽之旅》中海部千果的配音?\n花濑琴音担任电影《铃芽之旅》中海部千果的配音。\n谁负责了电影《铃芽之旅》的音乐创作?\n电影《铃芽之旅》的音乐由RADWIMPS和作曲家阵内一真共同创作。\n谁是《铃芽之旅》的女主角?\n岩户铃芽是《铃芽之旅》的女主角。\n电影里的哪个角色希望透过圣地巡礼促进当地活化?\n町政策企划科的川守田正人课长。"
},
"quotePrompt": {
"obj": "System",
"value": "知识库:电影《铃芽之旅》的导演是谁?\n电影《铃芽之旅》的导演是新海诚。\n电影《铃芽之旅》的编剧是谁?\n新海诚是本片的编剧。\n本作的主人公是谁?\n本作的主人公是名叫铃芽的少女。\n电影《铃芽之旅》男主角是谁?\n电影《铃芽之旅》男主角是宗像草太,由松村北斗配音。\n电影《铃芽之旅》的制作团队中有哪位著名人士?\n川村元气是本片的制作团队成员之一。\n电影中的后门是指什么?\n后门是连接往生者世界“常世”与人类所处的“现世”的门扉,平常仰赖人们心中的重量和思绪镇定土地和门。若是人心的重量消失,等于从人们的记忆中消失或思绪减少,将会导致后门被打开。一个人一生中最多只能通过一道后门。\n谁担任电影《铃芽之旅》中草太的祖父宗像羊朗的声演人员?\n松本白鹦担任电影《铃芽之旅》中草太的祖父宗像羊朗的声演人员。\n电影中的关门师是指什么?\n关门师是为了防范“门”被打开延伸的灾难,负责将出现在世上的“门”封闭的特殊人群。关门师进行封闭“门”的过程中,会先想著曾在该土地上生活的人们,感受该土地过往的景色与人事物,借此打开“门”的钥匙孔,再咏唱归还土地予神明的咒文,使用特制的钥匙将“门”锁上。\n电影《铃芽之旅》的女主角是谁?\n电影的女主角是铃芽。\n电影《铃芽之旅》的女主角是谁?\n电影《铃芽之旅》的女主角是岩户铃芽,由原菜乃华配音。\n谁担任电影《铃芽之旅》中岩户环的配音?\n深津绘里担任电影《铃芽之旅》中岩户环的配音。\n谁担任电影《铃芽之旅》中海部千果的配音?\n花濑琴音担任电影《铃芽之旅》中海部千果的配音。\n谁负责了电影《铃芽之旅》的音乐创作?\n电影《铃芽之旅》的音乐由RADWIMPS和作曲家阵内一真共同创作。\n谁是《铃芽之旅》的女主角?\n岩户铃芽是《铃芽之旅》的女主角。\n电影里的哪个角色希望透过圣地巡礼促进当地活化?\n町政策企划科的川守田正人课长。"
}
}
}
知识库
知识库添加数据
请求
mode: index | qa
index 模式: 直接将 q 转成向量存起来,a 直接入库。
qa 模式: 只关注 data 里的 q,将 q 丢给大模型,让其根据 prompt 拆分成 qa 问答对(已经默认加格式输出)。
token 限制:
index 模式: q + a 的总 token 最好不要超过 3000,否则对话时候容易超限制。
qa 模式: q 不要超过 3300 token
promot: 引导 qa 拆分的提示词,只需要告诉模型“这是什么”。
curl --location --request POST 'https://bot.apetd.com/api/openapi/kb/pushData' \
--header 'apikey: 22222' \
--header 'Content-Type: application/json' \
--data-raw '{
"kbId": "64663f451ba1676dbdef0499",
"mode": "index",
"prompt": "qa 拆分引导词,index 模式下可以忽略",
"data": [
{
"a": "test",
"q": "1111"
},
{
"a": "test2",
"q": "22222"
}
]
}'
响应
{
"code": 200,
"statusText": "",
"message": "共插入 2 条数据",
"data": 2
}
错误码
unAuthorization - api key鉴权错误、
insufficientQuota - 账号余额不足
unAuthModel - 无权使用模型
unAuthKb - 无权使用知识库
例子
V1 流响应例子
const streamFetch = ({ url, data, onMessage }) =>
new Promise(async (resolve, reject) => {
try {
const res = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
apikey: '63f9a12228d2a638d839e11b-r5l1dho132hvcfd1wg12'
},
body: JSON.stringify(data),
});
const reader = res.body?.getReader();
if (!reader) return;
const decoder = new TextDecoder();
let responseText = '';
const read = async () => {
const { done, value } = await reader?.read();
if (done) {
if (res.status === 200) {
resolve(responseText);
} else {
try {
const parseError = JSON.parse(responseText);
reject(parseError?.message || '请求异常');
} catch (err) {
reject('请求异常');
}
}
return;
}
const text = decoder.decode(value).replace(/<br\/>/g, '\n');
res.status === 200 && onMessage(text);
responseText += text;
read();
};
read();
} catch (err) {
console.log(err, '====');
reject(typeof err === 'string' ? err : err?.message || '请求异常');
}
});
async function test() {
const responseText = await streamFetch({
url: 'https://bot.apetd.com/api/openapi/chat/chat',
data: {
"modelId":"22222222",
"prompts": [{
"obj": "Human",
"value": "laf是什么"
}]
},
onMessage(e) {
// e为收到的消息,可以做拼接
resule += e
}
})
console.log(responseText )
}
V2 流响应例子
type YuanmeiBotWebChatProps = {
chatId?: string; // undefined: nonuse history, '': new chat, 'xxxxx': use history
appId?: string;
};
type yuanmeiShareChatProps = {
password?: string;
shareId?: string;
};
export type Props = CreateChatCompletionRequest &
YuanmeiBotWebChatProps &
YuanmeiShareChatProps & {
messages: MessageItemType[];
};
export type ChatResponseType = {
newChatId: string;
quoteLen?: number;
};
export enum sseResponseEventEnum {
error = 'error',
answer = 'answer',
chatResponse = 'chatResponse'
}
interface StreamFetchProps {
data: Props;
onMessage: (text: string) => void;
abortSignal: AbortController;
}
export const streamFetch = ({ data, onMessage, abortSignal }: StreamFetchProps) =>
new Promise<ChatResponseType & { responseText: string; errMsg: string }>(
async (resolve, reject) => {
try {
const response = await window.fetch('/api/openapi/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
signal: abortSignal.signal,
body: JSON.stringify({
...data,
stream: true
})
});
if (response.status !== 200) {
const err = await response.json();
return reject(err);
}
if (!response?.body) {
throw new Error('Request Error');
}
const reader = response.body?.getReader();
// response data
let responseText = '';
let newChatId = '';
let quoteLen = 0;
let errMsg = '';
const read = async () => {
try {
const { done, value } = await reader.read();
if (done) {
if (response.status === 200) {
return resolve({
responseText,
newChatId,
quoteLen,
errMsg
});
} else {
return reject('响应过程出现异常~');
}
}
const chunkResponse = parseStreamChunk(value);
chunkResponse.forEach((item) => {
// parse json data
const data = (() => {
try {
return JSON.parse(item.data);
} catch (error) {
return item.data;
}
})();
if (item.event === sseResponseEventEnum.answer && data !== '[DONE]') {
const answer: string = data?.choices?.[0].delta.content || '';
onMessage(answer);
responseText += answer;
} else if (item.event === sseResponseEventEnum.chatResponse) {
const chatResponse = data as ChatResponseType;
newChatId = chatResponse.newChatId;
quoteLen = chatResponse.quoteLen || 0;
} else if (item.event === sseResponseEventEnum.error) {
errMsg = getErrText(data, '流响应错误');
}
});
read();
} catch (err: any) {
if (err?.message === 'The user aborted a request.') {
return resolve({
responseText,
newChatId,
quoteLen,
errMsg
});
}
reject(getErrText(err, '请求异常'));
}
};
read();
} catch (err: any) {
console.log(err);
reject(getErrText(err, '请求异常'));
}
}
);
//============================================================
// 流请求,获取数据
const { newChatId, quoteLen } = await streamFetch({
data: {
messages, // 问题, [{role:"user",content:"Laf 是什么?"}]
chatId, // 对话的 ID
appId: modelId, // 应用的 ID
model: '' // 固定填空
},
onMessage: (text: string) => {
console.log(text)
},
abortSignal // 中断请求,可选
});
在第三方应用中使用 猿媒BOT
使用 V2 版 chat 接口,可以轻松的在其他三方应用中使用 猿媒BOT。
- 获取秘钥(新建一个,记得复制出来,关了得新建了

- 组合秘钥
利用刚复制的 API 秘钥加上 AppId 组合成一个新的秘钥,格式为: Bearer API秘钥-AppId,例如:
Bearer yuanmei-z51pkjqm9nrk03a1rx2funoy-642adec15f04d67d4613efdb
注意:
- Bearer后面有一个空格
- 大部分项目自动会填Bearer ,你只需要粘贴后面部分即可:
yuanmei-z51pkjqm9nrk03a1rx2funoy-642adec15f04d67d4613efdb
- 复制接口地址
https://bot.apetd.com/api/openapi
一些问题
如何取 modelId / appId
V3.8之后的接口改成了 appId 。两者是同一个东西,主要看接口实际字段。
应用编辑页内点击API可获取


