分身中心:API
将你的 SecondMe AI 分身集成到任意第三方应用中 —— 飞书机器人、客服系统,或任何自定义应用。
概述
分身开放 API 提供统一的鉴权入口。鉴权通过后,你将使用与 SecondMe App 完全相同的接口 —— 无需学习额外 API。
你的应用 → /open/avatar/auth(API Key → visitor token)
→ 标准 SecondMe 接口(与 App 一致)
→ WebSocket 实时接收 AI 回复
你可以构建什么
- 飞书 / 钉钉 / Slack 机器人 —— 用户通过即时通讯平台与你的分身对话
- 网页聊天组件 —— 在你的网站中嵌入分身对话
- 智能客服 —— 让分身 7×24 小时处理咨询
- 任意自定义集成 —— 任何能发起 HTTP 请求并连接 WebSocket 的应用
工作原理
- 你在 SecondMe App 中为分身创建 API Key
- 你的应用调用
/auth接口,使用 API Key 获取 visitor token - 你的应用使用 visitor token 调用标准 SecondMe 接口
- AI 回复通过 WebSocket 实时推送
- 你(分身所有者)可以在 App 中查看所有对话并随时接管
前提条件
- 拥有 SecondMe 账号并已创建至少一个分身
- 在分身中心 → 分身详情 → API Key 管理中创建 API Key
- 保存好你的 API Key(以
sk-开头,创建时仅显示一次 —— 请妥善保管)
环境
| 环境 | Base URL |
|---|---|
| 生产环境 | https://mindos.mindverse.ai/gate/in |
| 预发环境 | https://mindos-prek8s.mindverse.ai/gate/in |
快速开始
第 0 步:鉴权
用 API Key 换取 visitor token。每个终端用户需要一个唯一的 visitorId。
visitorId 格式:{platform}_{uuid}
示例:feishu_550e8400-e29b-41d4-a716-446655440000、web_6ba7b810-9dad-11d1-80b4-00c04fd430c8
为每个终端用户生成唯一的 visitorId 并持久化保存。相同的 visitorId = 同一个访客 = 可以复用已有会话。
curl -X POST $BASE_URL/rest/open/avatar/auth \
-H "Authorization: Bearer sk-your-api-key" \
-H "Content-Type: application/json" \
-d '{
"visitorId": "feishu_550e8400-e29b-41d4-a716-446655440000",
"visitorName": "John Doe",
"channel": "feishu"
}'
| 字段 | 必填 | 说明 |
|---|---|---|
visitorId | 是 | 格式:{platform}_{uuid} |
visitorName | 否 | 显示名称,展示给分身所有者。例如 "张三" |
channel | 否 | 渠道标识,附加在名称后显示为 "张三(feishu)"。例如 "feishu"、"dingtalk"、"web" |
响应:
{
"code": 0,
"data": {
"visitorToken": "bb857435f640c8b2...",
"visitorUserId": "del3p",
"visitorMindId": "487569763543990272",
"avatarShareCode": "ebe251793d69",
"avatarName": "My Assistant",
"ownerUserId": "de4fh"
}
}
| 字段 | 说明 | 用于 |
|---|---|---|
visitorToken | 后续所有请求的鉴权 token | token 请求头 |
visitorUserId | 编码后的访客用户 ID | ws/create、message/send |
visitorMindId | 访客的 mind ID(数字型) | session/create |
avatarShareCode | 分身的分享码 | chat/init |
ownerUserId | 分身所有者的编码 ID | session/create 的 memberUserIds |
后续所有请求需要携带两个请求头:
token: {visitorToken}Fp: {visitorId}
第 1 步:初始化对话
将分身的上下文(人设、素材)加载到缓存中。10 分钟后过期。
curl -X POST $BASE_URL/rest/os/avatar/chat/init \
-H "token: $VISITOR_TOKEN" \
-H "Fp: $VISITOR_ID" \
-H "Content-Type: application/json" \
-d '{"shareCode": "ebe251793d69"}'
响应:
{
"code": 0,
"data": {
"mindId": "3m24e99h3mbp",
"avatarName": "My Assistant",
"ownerUserId": "de4fh",
"opening": "Hello! 👋"
}
}
保存此响应中的 mindId —— 你将在第 6 步(发送消息)中使用它。这是一个编码字符串(不是第 0 步中的数字型 visitorMindId)。
第 2 步:创建 WebSocket
curl -X POST $BASE_URL/rest/general/ws/create \
-H "token: $VISITOR_TOKEN" \
-H "Fp: $VISITOR_ID" \
-H "Content-Type: application/json" \
-d '{
"userId": "del3p",
"channel": ["ALL"],
"apiVersion": "1.3.0",
"sdkVersion": "1.0.0"
}'
返回 WebSocket 地址。必须在 60 秒内连接。
第 3 步:创建会话
curl -X POST $BASE_URL/rest/general/session/create \
-H "token: $VISITOR_TOKEN" \
-H "Fp: $VISITOR_ID" \
-H "Content-Type: application/json" \
-d '{
"mindId": 487569763543990272,
"mindType": "shadow",
"mode": "PERSONAL",
"sessionType": "SHARE",
"memberUserIds": ["de4fh"]
}'
mindId 和 memberUserIds 都是必填的。缺少它们会导致:
- AI 无法识别分身的人设
- 分身所有者无法在 App 中回复("not a member" 错误)
| 参数 | 值 | 来源 |
|---|---|---|
mindId | 数字型 ID | 第 0 步 visitorMindId |
memberUserIds | ["ownerUserId"] | 第 0 步 ownerUserId |
sessionType | "SHARE" | 固定值 |
第 4 步:绑定会话到分身
使对话在分身所有者的分身中心中可见。
# 首先,获取分身的数字型 ID
curl -X GET "$BASE_URL/rest/os/avatar/public/ebe251793d69" \
-H "token: $VISITOR_TOKEN"
# 响应:data.id = avatarId(例如 67)
# 然后绑定
curl -X POST $BASE_URL/rest/os/avatar/chat/start \
-H "token: $VISITOR_TOKEN" \
-H "Fp: $VISITOR_ID" \
-H "Content-Type: application/json" \
-d '{"avatarId": 67, "sessionId": "your-session-id"}'
第 5 步:连接 WebSocket
连接到第 2 步获取的地址。每 15 秒发送一次心跳。
const ws = new WebSocket(address);
// 每 15 秒发送心跳
setInterval(() => {
ws.send(JSON.stringify({ type: 'ping', wsId: wsId }));
}, 15000);
第 6 步:发送消息
消息通过 HTTP 发送,AI 回复通过 WebSocket 推送。
curl -X POST $BASE_URL/rest/general/message/send \
-H "token: $VISITOR_TOKEN" \
-H "Fp: $VISITOR_ID" \
-H "Content-Type: application/json" \
-d '{
"timestamp": 1774580000000,
"seqId": "12345_____1774580000000",
"sessionId": "your-session-id",
"userId": "del3p",
"messageId": "12345_____1774580000000",
"mindId": "3m24e99h3mbp",
"index": 0,
"sendUserId": "del3p",
"dataType": "text",
"sender": "client",
"type": "msg",
"wsId": "ws:260327...",
"data": {"content": "你好,介绍一下你自己"}
}'
| 参数 | 值 | 来源 |
|---|---|---|
timestamp | 当前时间戳(毫秒) | Date.now() |
seqId | {random}_____${timestamp} | 每条消息唯一 |
sessionId | 会话 ID | 第 3 步响应 |
userId | 访客编码 ID | 第 0 步 visitorUserId |
messageId | 与 seqId 相同 | |
mindId | 编码字符串(非数字型) | 第 1 步响应的 mindId |
sendUserId | 与 userId 相同 | |
wsId | WebSocket ID | 第 2 步响应的 wsId |
data.content | 消息文本 |
第 6 步使用的 是第 1 步返回的编码字符串 mindId(例如 "3m24e99h3mbp")。
这与第 0 步中的数字型 visitorMindId(例如 "487569763543990272",用于第 3 步)不同。
WebSocket 消息
AI 回复
{
"sender": "umm",
"multipleData": [{ "modal": { "answer": "Hello! I'm..." } }]
}
所有者接管回复
当分身所有者在 SecondMe App 中手动回复时:
{
"sender": "client",
"sendUserId": "de4fh",
"multipleData": [{ "modal": { "answer": "你好,这是真人回复..." } }]
}
区分消息类型
sender | sendUserId | 含义 |
|---|---|---|
umm | — | AI 分身回复 |
client | 等于你的 visitorUserId | 你自己发送消息的回显(忽略) |
client | 不等于你的 visitorUserId | 所有者接管回复 |
错误码
| 错误码 | 说明 |
|---|---|
open.api.unauthorized | 缺少 Authorization 请求头 |
open.api.key.not.found | 无效的 API Key |
open.api.key.disabled | API Key 已禁用 |
open.api.rate.limited | 超出频率限制(每个 Key 每分钟 60 次) |
open.api.avatar.not.found | 分身未找到 |
open.api.invalid.visitor.id | 无效的 visitorId 格式 |
session.not.member | 非会话成员(检查 memberUserIds) |
注意事项
- 上下文缓存 10 分钟后过期 —— 请在第 1 步完成 后 10 分钟内完成第 3 步
- WebSocket 地址 60 秒后过期 —— 获取后请立即连接
- 必须发送心跳 —— 每 15 秒发送一次 ping,否则连接将断开
- 消息通过 HTTP 发送,回复通过 WebSocket 推送 —— 这是设计如此,与 App 行为一致
- 一个 visitorId 可以有多个会话 —— 每次调用
session/create都会创建新的对话 - 频率限制 —— 每个 API Key 每分钟 60 次请求