Appearance
AgentHub 会话运行面协议(仅调用方 · 单页)
读者:只调用 AgentHub 会话能力(多轮流式对话 / 语音 / 附件 / 文生图)的开发者——Agent 的建模与发布由平台方或租户管理员完成,你拿到的是「地址 + API-Key + 已发布的 Agent ID」。 交付方式:本页随凭证一并交付,自包含;不需要访问 AgentHub 仓库。 契约事实源:
openapi.yaml(SSOT)——冲突时以 openapi 为准。深度接入(自建 Agent / 建模 / 计费对账全链)另见 SaaS 接入 Cookbook。 状态基准:2026-08-27。
1. 认证(两个请求头,全程不变)
X-AgentHub-Api-Key: ahk_... # 租户级 API-Key(服务端凭据)
X-AgentHub-On-Behalf-Of: <uuid> # 影子用户 ID(你的终端用户在平台侧的映射)- API-Key 是服务端到服务端凭据——不要放进浏览器 / 小程序等终端代码;
- 所有响应为
Envelope:{"code": "...", "message": "...", "data": {...}},code != "SUCCESS"即业务错误(SSE 流除外,见 §4); - 凭据丢失只能轮转(
POST /api/v1/delivery/api-keys/{id}:rotate),旧 Key 即时失效。
2. 端点总览(运行面)
| 端点 | 用途 |
|---|---|
POST /api/v1/app/conversations | 开会话(body:{"agent_id": "<uuid>", "client_conversation_key": "<可选幂等键>"})→ data.id = 会话 ID;命中幂等键返回 200 原会话 |
POST /api/v1/app/conversations/{id}/turns | 跑一轮,响应为 SSE 流(§4) |
GET /api/v1/app/conversations/{id}/turns/{turn_id} | 断连重拉:返回该轮完整结果,幂等不重跑不重复扣费(§5) |
GET /api/v1/app/conversations/{id}/messages?limit=&offset= | 历史分页(MessagePageOut{items, limit, offset}) |
POST /api/v1/app/conversations/{id}:end | 显式结束(幂等);闭合后只读。空闲超时也会自动闭合 |
会话状态机:active → closing → closed;closed 后所有写操作返回 409 CONVERSATION_CLOSED。会话钉死打开时的 Agent 版本——Agent 重新发布后需开新会话才生效。
3. 轮次请求体(content_blocks)
json
{"content_blocks": [
{"type": "text", "text": "帮我查退款政策"},
{"type": "file", "file_id": "<uuid>", "filename": "notes.txt", "excerpt": "<commit 返回的摘录>"},
{"type": "choice_selection", "card_message_id": "<uuid>", "selected": ["<option_id>"]}
]}text:普通文本轮;file:附件随轮(先走附件三步上传 authorize→直传→commit,excerpt以 commit 返回为准);choice_selection:回上一轮turn_card的选项。
4. SSE 帧目录(核心)
POST .../turns 成功时返回 200 text/event-stream(响应头 Cache-Control: no-cache、X-Accel-Buffering: no)。帧为标准 SSE 三行式:
id: 3:2 ← 帧号 = {轮次 seq}:{帧序号},单调递增
event: turn_delta
data: {"turn_id": "...", "seq": 2, "text": "退款政策如下"}(空行 = 帧边界;data 均为单行 JSON)
| 帧 | 次数 | data 负载 |
|---|---|---|
turn_started | 1 | {"turn_id", "seq", "status": "generating"} —— turn_id 是断连重拉的钥匙,首帧必到 |
turn_delta | 0..N | {"turn_id", "seq", "text"} —— 增量文本,按序拼接 |
turn_card | 0..1 | {"turn_id", "card": {"type": "choice_card", "card_schema_version": 1, "prompt", "options": [{"id", "label"}], "multi", "fallback_text"}} |
turn_file | 0..N | {"turn_id", "file": {"type": "file", "file_id", "filename", "mime_type", "size_bytes"}} —— 文生图/工件产物;取内容走 GET .../files/{file_id}(短 TTL 签名 URL) |
turn_completed | 1 | {"turn_id", "status": "succeeded", "points_charged": int|null, "message_ids": ["<user_msg_id>", "<assistant_msg_id>"]};低余额时附 "balance_warning": true(仅提示不阻断) |
三条协议性质(客户端实现必须知道):
- 先完结,后吐帧:服务端把轮次完整执行并落库后才投影为帧流。因此流一旦开始,结果已确定;流中不会再出现业务错误。
- 流前错误是普通 Envelope:所有校验失败(404/409/402/422…)发生在流开始之前,以标准 HTTP 状态码 + Envelope JSON 返回——客户端按
Content-Type区分:application/json= 错误,text/event-stream= 正常。 - 帧号支持 Last-Event-ID 记账:
id为{轮次 seq}:{帧序号};但权威的断连恢复路径是 §5 的 GET 重拉(幂等、不重跑、不重复扣费)。
5. 断连重拉(三条命令的协议)
① POST .../turns → 至少收到首帧 turn_started,记下 turn_id
② (连接断开,丢弃未完成的流)
③ GET .../turns/{turn_id} → TurnOut(该轮全部消息 + 计费,已持久化的最终结果)TurnOut:{"id", "conversation_id", "seq", "status", "operation_id", "points_charged", "messages": [...], "started_at", "ended_at", ...}。重复 GET 幂等。
6. 错误码目录
| HTTP | code | 含义 / 处置 |
|---|---|---|
| 401 | API_KEY_INVALID | Key 错误/吊销;检查请求头 |
| 402 | POINTS_INSUFFICIENT | 余额不足;零副作用,充值后原样重试 |
| 403 | AUTH_TENANT_MISMATCH | On-Behalf-Of 用户非本租户或非 active |
| 404 | CONVERSATION_NOT_FOUND / CONVERSATION_TURN_NOT_FOUND / CONVERSATION_MESSAGE_NOT_FOUND / CONVERSATION_ATTACHMENT_NOT_FOUND | 资源不存在或跨租户(同形防枚举) |
| 409 | CONVERSATION_CLOSED | 会话已闭合;开新会话 |
| 409 | CONVERSATION_ACTIVE_TURN_CONFLICT | 同会话已有进行中轮次;等它完成或直接 GET 重拉 |
| 409 | CONVERSATION_AGENT_NOT_PUBLISHED / CONVERSATION_AGENT_ARCHIVED | Agent 未发布/已归档;联系发布方 |
| 422 | VALIDATION_ERROR | 请求形状 / MIME / 字节数不过白名单 |
| 422 | CONVERSATION_SPEECH_NOT_ENABLED | 该 Agent 快照未启用语音;按「不可用」降级 |
| 500 | CONVERSATION_TURN_FAILED | 轮次执行异常(message 带 trace_id,找平台方) |
| 504 | CONVERSATION_GUARDRAIL_VIOLATION | 护栏拦截(墙钟超时等;message 有具体原因) |
7. 计费生命周期(你只需要关心四件事)
- 轮次:开轮先冻结
points_per_turn,成功结清(turn_completed.points_charged),失败全额解冻退回——试错成本只有成功轮次; - 语音:转写 / 合成各按次计费(快照价),TTS 缓存命中零扣点(同消息 + 同音色返回同一 URL);
- 余额不足:402
POINTS_INSUFFICIENT,零副作用,引导充值后重试; - 低余额提示:结清后可用余额 < 3×单价时
turn_completed附balance_warning: true(仅提示)。
对账键(流水 operation_id 前缀):轮次 turn:{turn_id}、转写 stt:{transcription_id}、合成 tts:{speech_id}、入账 grant:...。
8. 可运行示例
最小 Python 客户端(含断连重拉演示,零第三方依赖)+ 本地 mock 服务:AgentHub SDK 包 sdk/python/examples/——mock_conversation_server.py 起本地假服务,conversation_minimal.py 全流程跑通(开会话 → 流式 → 模拟断连 → GET 重拉 → 结束),不接触真实平台即可验证你的接入代码。
9. 事实源与联动
本页是 Cookbook 附录 A/B/C 的外部交付版:端点契约以 openapi.yaml 为准;帧负载 / 错误码与 Cookbook 附录 A/B 双源维护,变更需双改。语音(STT/TTS)、附件上传三步、图片理解、文生图的完整 curl 见 Cookbook §7~§11。