3.12 外部接口
外部接口(/api/external/*)是 MoAI 把团队资源开放给外部系统的唯一通道:知识库、知识图谱、应用对话从这里出,MCP / ACP / A2A 三种标准协议端点也在这里。调用方通常是业务后端、MCP 客户端、外部 agent,或嵌入官网的悬浮组件(见 3.7)。
本文讲访问方式:鉴权、范围、端点地图与调用示例。接口全集不逐条罗列——外部接口单独生成 OpenAPI 文档,生成客户端工具即可。
接口文档
| 入口 | 地址 |
|---|---|
| 原始文档(OpenAPI) | http://127.0.0.1:5000/openapi/external.json |
| Scalar 浏览 | http://127.0.0.1:5000/scalar,左上角下拉切换 AI External API;或直达 /scalar/external |
- 内部接口在
AI API(v1)文档,与外部接口互不混编; - 文档仅在 Development 环境暴露,生产环境关闭;
- 给业务系统生成客户端:把 external.json 喂给 OpenAPI 生成器(Kiota、openapi-generator 等),不要手拼 HTTP 请求。
鉴权
外部接口只认两类凭证,都来自「应用接入 key」(创建与管理见 3.10),按调用语义二选一。
方式一:key 直连(系统身份)
适合无「用户」语义的系统级调用——同步图谱、拉取知识库文档:
curl http://127.0.0.1:5000/api/external/wiki/list \
-H "Authorization: Bearer moai-ac-xxxxxxxx"
# 与 Bearer 等价的 x-api-key 头,二选一
curl http://127.0.0.1:5000/api/external/wiki/list \
-H "x-api-key: moai-ac-xxxxxxxx"
方式二:外部用户 token(人的身份)
对话、会话记录等场景需要「这是谁」的语义,先换 token 再调用:
curl -X POST http://127.0.0.1:5000/api/external/token \
-H "Content-Type: application/json" \
-d '{
"accessAppKey": "moai-ac-xxxxxxxx",
"appId": "9f2b0000-0000-0000-0000-000000000000",
"externalUserId": "erp-user-1001",
"nickname": "小明"
}'
返回 accessToken / refreshToken。三种参数组合对应三种 token:
| 传参 | 换到 | 能做什么 |
|---|---|---|
只传 accessAppKey | 应用 token | 资源类调用(读写知识库/图谱等),不能创建会话对话 |
accessAppKey + appId + externalUserId | 外部用户 token | 全部能力:以这个「外部用户」的身份建会话、对话、查自己的历史(nickname 可选) |
只传 appId | 匿名 token | 仅「免授权」应用,悬浮组件游客场景(见 3.7) |
要点:
- access token 有效期 2 小时(Debug 环境 7 天),refresh token 7 天;
POST /api/external/token/refresh(body 传refreshToken)续期; - 刷新按 key 当前勾选的范围重新校验:收窄范围后,旧 token 下一次刷新即降级;
- 会话与消息归属外部用户(
externalUserId),同一 key 可为任意多个外部用户换 token,用户只能看到自己的会话。
能力范围与读写分档
每个范围勾选对应一组端点,范围调整实时生效(范围含义见 3.10):
| 范围 | 端点 | 深入文档 |
|---|---|---|
| 知识库读 / 写 | /api/external/wiki/* | 3.5.4 |
| 知识库 MCP | /api/external/wiki/{wikiId}/mcp | 3.5.7 |
| 知识图谱读 / 写 | /api/external/knowledge-graph/* | 3.6 |
| 知识图谱 MCP | /api/external/knowledge-graph/{kgId}/mcp | 3.6 |
| 应用对话 | /api/external/agent/*、/api/external/session/* | 见下文 |
| 应用 ACP | /api/external/app/{appId}/acp | 见下文 |
| 应用 A2A | /api/external/app/{appId}/a2a | 见下文 |
| 模型网关 | /api/aigateway/{teamId}/v1/*(不在 /api/external 下) | 3.11 |
读写分档口径:GET 与 */list 结尾的请求算读档,其余算写档。知识库、知识图谱各有只读/可写两档,只勾只读时写请求一律 403 insufficient_scope。
团队隔离是硬边界:key 只能触达本团队的知识库、图谱与应用,跨团队资源一律 404(而非 403,不暴露资源存在性)。
端点地图:对话与协议
应用对话
| 端点 | 说明 |
|---|---|
POST /api/external/agent/{appId}/session | 创建会话 |
GET /api/external/agent/{appId}/session/list | 会话列表 |
GET /api/external/session/{sessionId}/messages | 会话历史消息 |
POST /api/external/agent/{appId}/chat | 流式对话(AG-UI 协议,SSE) |
对话走 AG-UI 协议:请求体携带 threadId(即会话 id)与本轮用户消息,历史由服务端管理,每轮只发最新一条;响应为 SSE 事件流(文本增量、工具调用等)。前端对话页与悬浮组件用的就是这套协议。
curl -N -X POST http://127.0.0.1:5000/api/external/agent/{appId}/chat \
-H "Authorization: Bearer <外部用户 accessToken>" \
-H "Content-Type: application/json" \
-d '{
"threadId": "上一步创建的会话 id",
"messages": [{ "id": "m1", "role": "user", "content": "帮我查一下最近的订单" }]
}'
ACP / A2A(对接外部 agent)
把团队应用(Agent 应用、流程应用,须已发布)以标准协议暴露给外部 agent 框架,分别由「应用 ACP」「应用 A2A」范围控制,不要求应用对话范围:
| 协议 | 端点 | 方法面 |
|---|---|---|
| ACP(Agent Client Protocol,JSON-RPC 2.0) | POST /api/external/app/{appId}/acp | initialize / session/new / session/load / session/prompt(SSE)/ session/cancel |
| A2A(Google Agent2Agent,JSON-RPC 2.0) | POST /api/external/app/{appId}/a2a | message/send / message/stream(SSE)/ tasks/get / tasks/cancel;Agent Card 见 GET …/a2a/agent.json |
两个协议的会话都归属外部用户;A2A 的 contextId 承载 MoAI 会话 id,缺省自动建会话,携带即续聊。
辅助端点
| 端点 | 鉴权 | 说明 |
|---|---|---|
POST /api/external/token、/token/refresh | 匿名(凭证在 body) | 换 token / 续期 |
GET /api/external/app/list | 任意外部凭证 | 当前团队可对话的应用列表 |
GET /api/external/app/{appId}/access-point | 匿名 | 应用访问点信息(悬浮组件引导) |
常见问题
403 insufficient_scope?
key 未勾选对应范围,或只勾了读档却在调写接口。团队管理员在「应用接入」里编辑 key 勾选范围,实时生效。
资源明明存在却 404?
跨团队隔离:key 只认自己团队的资源。确认用的是目标团队管理员签发的 key。
建会话 403?
应用 token 不能对话。用 accessAppKey + appId + externalUserId 换外部用户 token 再操作。
token 刷新 401?
refresh token 已过期(7 天),或来源 key 已删除、范围收窄后不再满足条件。重新用 key 换 token。
Scalar 里找不到外部接口?
打开 /scalar 后左上角文档下拉切换到 AI External API,或直达 /scalar/external;文档仅在 Development 环境暴露。