Appearance
AgentHub SaaS 接入 Cookbook
读者:要把 AgentHub 的「会话 Agent + 多模态 + 计费」能力接进自己 SaaS 的开发者(人或 AI coding agent)。 用法:每个 Recipe 自包含、可逐条复制执行;按 §0→§12 顺序走即完成一次完整接入。 契约事实源:本文所有端点/字段均对齐
openapi.yaml(SSOT)——冲突时以 openapi 为准并回报本文勘误。导航版总览见ai-agent-integration-guide.md。 状态基准:2026-08-23(MM 四项多模态真栈闭环;热修 #293~#299 已上线)。 通道仲裁(ADR-0058,2026-08-29):自营 / 孵化 SaaS 的唯一使能路线就是本 Cookbook 的 API 通道——身份用模式 B(共享 realm OIDC,ADR-0047;本文 §4 影子用户三件套属模式 A,面向自带存量用户体系的外部二开方)。代码级垂直通道(saas-factory-kit.md)已冻结,除非满足 ADR-0058 D2 解冻条件,不要走同仓/独立仓垂直路径。 浏览器前端薄壳(模式 B 前端形态):不自建后端、直接用平台 JWT 直连会话面的接入方式,见saas-mode-b-integration-guide.md(SM2-1:模板包 + bootstrap + ≤15 步 checklist);本文面向服务端集成(模式 A 视角)为主。
§0 入驻前置(先读,1 分钟)
| 你需要 | 怎么获得 |
|---|---|
一个租户 + M2M client(CLIENT_ID/CLIENT_SECRET,scopes 已配置) | 双通道(IE-5 起):① 自助——正式租户 tenant_admin 在 Builder「设置 → 租户控制台 → M2M 接入凭据」一键生成/轮转/吊销(scope 白名单内置,secret 仅显示一次);② 人工——联系 AgentHub 运维走 runbook Mode A §2 |
平台地址 BASE | 部署方提供,形如 https://<eip> |
| 供应商模型 key(如 DashScope) | 你自己在阿里云等供应商处申请;只经注册接口入 vault,永不回显 |
| 终端用户体系 | 完全在你侧——AgentHub 只需要「影子用户」映射(§4) |
全部响应为 Envelope:{"code": "...", "message": "...", "data": {...}};code != SUCCESS 即业务错误。
§1 环境变量 + 取管理面 token
bash
BASE="https://<eip>" # 平台地址
CLIENT_ID="..." # ops 发放的 M2M client
CLIENT_SECRET="..."
TOKEN=$(curl -sk -X POST "$BASE/auth/realms/agenthub/protocol/openid-connect/token" \
-d "grant_type=client_credentials&client_id=$CLIENT_ID" \
--data-urlencode "client_secret=$CLIENT_SECRET" \
| python3 -c 'import sys,json; print(json.load(sys.stdin)["access_token"])')- token 是 RS256 JWT;
CLIENT_ID需带本文用到的 scopes(builder:*/agent:create/billing:points:tenant_grant/delivery:api_key:write/billing:ledger:read); - 常见 401:直连 Keycloak
:8080取 token(iss 不匹配)、secret 轮换未同步。
§2 建模:vendor → 模型组 → 模型 → 路由
一次性操作;也可在 web-builder「资源建模」界面完成,API 路径为自动化基线。以下以 DashScope 为例。
bash
# 2.1 租户 vendor(协议族:openai_compatible | dashscope;解析顺序 租户表 > env > 内置)
curl -sk -X POST "$BASE/api/v1/builder/model-vendors" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"code":"dashscope-ws","api_base":"https://dashscope.aliyuncs.com/compatible-mode/v1","protocol_family":"dashscope"}'
# → data.id = VENDOR_ID(code 可覆盖内置同名 vendor)
# 2.2 模型组
curl -sk -X POST "$BASE/api/v1/builder/model-groups" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"name":"LLM-chat"}' # → data.id = GROUP_ID
# 2.3 注册模型(key 只入 vault 引用;api_url 仅连通性探针不落库)
curl -sk -X POST "$BASE/api/v1/builder/models" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{
"group_id":"'$GROUP_ID'","vendor":"dashscope-ws","name":"qwen3-vl-plus",
"model_type":"llm","context_max_tokens":32000,"api_key":"sk-...",
"pricing_input_per_1m_cents":1,"pricing_output_per_1m_cents":1,
"capabilities":["vision"]}'
# → data.id = VL_MODEL_ID
# · 视觉模型 = 普通 llm + capabilities:["vision"];语音(stt/tts)模型 vendor 必须 dashscope 协议族
# · 非 LLM 模态必填 unit_price/price_unit(second/char/image)——表单缺字段是已知欠账 MR4-1,API 侧直接带上即可
# 2.4 路由(按组 upsert;vision 模型放 fallback 位:带图轮次独占走它,纯文本走主模型)
curl -sk -X POST "$BASE/api/v1/builder/routes" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"group_id":"'$GROUP_ID'","primary_model_id":"'$CHAT_MODEL_ID'","fallback_model_id":"'$VL_MODEL_ID'"}'语音/画图模型同法注册到各自组(model_type:stt/tts/image_gen,带 unit_price/price_unit),并为每组设路由。
§3 会话 Agent:创建 + 发布 + 免费冒烟
bash
# 3.1 创建(agent_type=conversation 是硬约束)
curl -sk -X POST "$BASE/api/v1/builder/agents" -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"project_id":"'$PROJECT_ID'","code":"chat-hello","name":"会话助手","agent_type":"conversation"}'
# → data.id = AGENT_ID
# 3.2 发布(多模态全开的最小快照;单价↔护栏强制配对,缺一 409)
curl -sk -X POST "$BASE/api/v1/builder/agents/$AGENT_ID/publish" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{
"agent_id":"'$AGENT_ID'","expected_agent_version":0,
"role_card":{"persona_prompt":"你是耐心的客服助手。"},
"bindings":{"primary_model_group_id":"'$GROUP_ID'","knowledge_base_ids":[],"skill_ids":[],"tool_ids":[]},
"conversation":{
"points_per_turn":1,
"guardrails":{"max_input_tokens":8000,"max_attachments":3,"max_tool_calls":5,
"max_images_per_turn":4,"turn_timeout_seconds":240},
"points_per_transcription":1,"points_per_speech":1,"voice":"longanyang",
"space_permissions":{"user_space":"read_write","project_space":"read"},
"sop_allowlist":[],"card_types_enabled":["choice_card"]
}
}'要点:turn_timeout_seconds 对含画图/SOP 的 Agent 建议 ≥180(qwen-image 实测 30~90s,默认 60 会掐断在跑工具——欠账 MM6-1/MM6-2);max_images_per_turn 缺席则文生图工具不注册;speech 组价与护栏配对(XOR 拒绝)。
bash
# 3.3 免费冒烟(零计费零落库)
curl -sk -X POST "$BASE/api/v1/builder/agents/$AGENT_ID/chat-dry-run" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"message":"你能做什么?"}'
# → data.assistant_text + 配置读数(points_per_turn / guardrails / tool_count ...)§4 终端用户三件套:影子用户 → 入账 → API-Key
bash
# 4.1 影子用户(username = 你侧不可变用户 ID;幂等)
curl -sk -X POST "$BASE/api/v1/identity/users:provision" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"username":"saas-user-10086"}'
# → data.id = SHADOW_USER_ID
# 4.2 积分入账(operation_id 幂等 = 两侧对账键;重放返回 idempotent_replay:true)
curl -sk -X POST "$BASE/api/v1/billing/points:tenant-grant" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"user_id":"'$SHADOW_USER_ID'","project_id":"'$PROJECT_ID'","amount":1000,
"operation_id":"grant:order-20260711-0001","expires_at":"2027-07-11T00:00:00Z",
"reason":"用户充值订单 20260711-0001"}'
# ⚠ expires_at 为必填(长效积分到期时间,ISO-8601)——漏带会 422(DX4-1 冷启动走读揪出,已回填)
# 4.3 领 API-Key(明文只返回一次;支持 :rotate 轮转 / :revoke 吊销)
curl -sk -X POST "$BASE/api/v1/delivery/api-keys" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"name":"saas-prod"}'
# → data.api_key = "ahk_..."(妥善保存)此后你的 SaaS 服务端调运行面,统一带两个头:
X-AgentHub-Api-Key: ahk_...
X-AgentHub-On-Behalf-Of: <SHADOW_USER_ID>§5 开会话 + 第一轮流式对话
bash
# 开会话(幂等键可选;命中既有会话返回 200 原会话体,不新建)
curl -sk -X POST "$BASE/api/v1/app/conversations" \
-H "X-AgentHub-Api-Key: $API_KEY" -H "X-AgentHub-On-Behalf-Of: $SHADOW_USER_ID" \
-H 'Content-Type: application/json' \
-d '{"agent_id":"'$AGENT_ID'","client_conversation_key":"saas-u10086-20260824"}'
# → 201 data.id = CONVERSATION_ID(注意:会话从此钉死当前 agent_version,见附录 C)
# 一轮对话(SSE 流式)
curl -sk -N -X POST "$BASE/api/v1/app/conversations/$CONVERSATION_ID/turns" \
-H "X-AgentHub-Api-Key: $API_KEY" -H "X-AgentHub-On-Behalf-Of: $SHADOW_USER_ID" \
-H 'Content-Type: application/json' \
-d '{"content_blocks":[{"type":"text","text":"帮我查退款政策"}]}'SSE 原始输出长这样(帧负载全形状见附录 A):
id: 1
event: turn_started
data: {"turn_id":"65598f67-...","seq":1,"status":"generating"}
id: 2
event: turn_delta
data: {"turn_id":"65598f67-...","seq":1,"text":"退款政策如下"}
id: 3
event: turn_completed
data: {"turn_id":"65598f67-...","status":"succeeded","points_charged":1,
"message_ids":["<user_msg_uuid>","<assistant_msg_uuid>"]}服务端消费(Python / httpx)——浏览器可用 EventSource,你的后端这样接:
python
import json, httpx
def consume_turn(conv_id: str, text: str):
url = f"{BASE}/api/v1/app/conversations/{conv_id}/turns"
headers = {"X-AgentHub-Api-Key": API_KEY, "X-AgentHub-On-Behalf-Of": SHADOW_USER_ID}
event, data = None, None
with httpx.stream("POST", url, headers=headers, timeout=300,
json={"content_blocks": [{"type": "text", "text": text}]}) as r:
r.raise_for_status()
for line in r.iter_lines():
if line.startswith("event:"):
event = line.split(":", 1)[1].strip()
elif line.startswith("data:"):
data = line.split(":", 1)[1].strip()
elif line == "": # 帧边界
if event == "turn_delta":
yield json.loads(data)["text"]
elif event == "turn_completed":
return json.loads(data) # 含 points_charged / balance_warning
event, data = None, None服务端消费(Node 18+ / fetch):
js
const resp = await fetch(`${BASE}/api/v1/app/conversations/${CONV_ID}/turns`, {
method: "POST",
headers: { "X-AgentHub-Api-Key": API_KEY, "X-AgentHub-On-Behalf-Of": SHADOW_USER_ID,
"Content-Type": "application/json" },
body: JSON.stringify({ content_blocks: [{ type: "text", text }] }),
});
let event = "", data = "";
for await (const chunk of resp.body) {
for (const line of chunk.toString().split("\n")) {
if (line.startsWith("event:")) event = line.slice(6).trim();
else if (line.startsWith("data:")) data = line.slice(5).trim();
else if (line === "" && event) { /* 同 Python:delta 累积 / completed 结束 */ event = ""; data = ""; }
}
}§6 断连重拉 / 历史 / 结束会话
bash
# 断连重拉:轮次在 SSE 开始前已完整落库,凭首帧 turn_id 重拉,不重跑不重复扣费
curl -sk "$BASE/api/v1/app/conversations/$CONVERSATION_ID/turns/$TURN_ID" \
-H "X-AgentHub-Api-Key: $API_KEY" -H "X-AgentHub-On-Behalf-Of: $SHADOW_USER_ID"
# → TurnOut(status / points_charged / messages)
# 历史分页
curl -sk "$BASE/api/v1/app/conversations/$CONVERSATION_ID/messages?limit=50&offset=0" \
-H "X-AgentHub-Api-Key: $API_KEY" -H "X-AgentHub-On-Behalf-Of: $SHADOW_USER_ID"
# → MessagePageOut{items:[MessageOut(role: user|assistant|tool, content_blocks)], limit, offset}
# 结束会话(→ closing → 编制链把转写/画像/笔记/记忆写用户空间 → closed 只读;空闲超时也会自动闭合)
curl -sk -X POST "$BASE/api/v1/app/conversations/$CONVERSATION_ID:end" \
-H "X-AgentHub-Api-Key: $API_KEY" -H "X-AgentHub-On-Behalf-Of: $SHADOW_USER_ID"§7 语音输入(STT)
bash
# multipart 直传(不转码);转写结果回填你的输入框,用户可修正,再作为普通 text 轮次发送
curl -sk -X POST "$BASE/api/v1/app/conversations/$CONVERSATION_ID/transcriptions" \
-H "X-AgentHub-Api-Key: $API_KEY" -H "X-AgentHub-On-Behalf-Of: $SHADOW_USER_ID" \
-F "audio=@speech.mp3;type=audio/mpeg" -F "language=zh"
# → TranscriptionOut: {"transcription_id":"...","text":"今天天气很好","duration_seconds":3.0,"points_charged":1}- MIME 白名单:wav/mpeg/ogg/opus/webm/mp4/m4a 族(带参数如
audio/webm;codecs=opus已接受);超白名单 → 422VALIDATION_ERROR; - 上游高峰单次 85s+ 属正常——你的前端要按分钟级等待设计(欠账 MM6-3);
- 快照缺 speech 组价 → 422
CONVERSATION_SPEECH_NOT_ENABLED(优雅降级为不可用)。
§8 语音播报(TTS)
bash
# 助手消息按需合成;(message_id, voice) 缓存命中零扣点返回同 URL
curl -sk -X POST "$BASE/api/v1/app/conversations/$CONVERSATION_ID/messages/$MESSAGE_ID/speech" \
-H "X-AgentHub-Api-Key: $API_KEY" -H "X-AgentHub-On-Behalf-Of: $SHADOW_USER_ID"
# → MessageSpeechOut: {"speech_id":"...","file_id":"...","url":"https://.../fs/...",
# "mime_type":"audio/mpeg","size_bytes":12345,"cached":false,"points_charged":1}url 是短 TTL 签名地址,浏览器直接可播;音色取快照 voice(longanyang 实证可用)。
§9 附件(文本类)三步上传 + 随轮提问
bash
# ① authorize(会话须 active)
curl -sk -X POST "$BASE/api/v1/app/conversations/$CONVERSATION_ID/attachments:authorize" \
-H "X-AgentHub-Api-Key: $API_KEY" -H "X-AgentHub-On-Behalf-Of: $SHADOW_USER_ID" \
-H 'Content-Type: application/json' \
-d '{"filename":"notes.txt","mime":"text/plain","size_bytes":123}'
# → {"fid":"3,abc123","upload_url":"https://<eip>/fs/3,abc123","bucket":"...","expires_at":"..."}
# ② 直传原始字节(PUT,无额外 token)
curl -sk -X PUT "$UPLOAD_URL" --data-binary @notes.txt
# ③ commit(sha256 为幂等键;服务端抽取摘录 ≤4000 字符)
curl -sk -X POST "$BASE/api/v1/app/conversations/$CONVERSATION_ID/attachments:commit" \
-H "X-AgentHub-Api-Key: $API_KEY" -H "X-AgentHub-On-Behalf-Of: $SHADOW_USER_ID" \
-H 'Content-Type: application/json' \
-d '{"fid":"3,abc123","mime":"text/plain","size_bytes":123,
"sha256":"<sha256-of-bytes>","filename":"notes.txt"}'
# → AttachmentCommitOut: {"attachment_id":"...","file_id":"...","kind":"text",
# "excerpt":"<服务端摘录>","extraction_status":"ok","reused":false}随轮发送(file 块的 excerpt 以服务端 commit 返回为准):
bash
curl -sk -N -X POST "$BASE/api/v1/app/conversations/$CONVERSATION_ID/turns" \
-H "X-AgentHub-Api-Key: $API_KEY" -H "X-AgentHub-On-Behalf-Of: $SHADOW_USER_ID" \
-H 'Content-Type: application/json' \
-d '{"content_blocks":[
{"type":"file","file_id":"<commit 的 file_id>","filename":"notes.txt","excerpt":"<服务端 excerpt>"},
{"type":"text","text":"根据附件回答:要点是什么?"}]}'支持:txt/md 直读、csv 列头+行摘要、pdf 文本层(pypdf);扫描版 pdf → extraction_status:"no_text_layer"。
§10 图片理解(vision)
上传同 §9(mime 用 image/png 等,commit 后 kind:"image"、extraction_status:"vision_deferred" 是正常占位),随后带图提问:
bash
curl -sk -N -X POST "$BASE/api/v1/app/conversations/$CONVERSATION_ID/turns" \
-H "X-AgentHub-Api-Key: $API_KEY" -H "X-AgentHub-On-Behalf-Of: $SHADOW_USER_ID" \
-H 'Content-Type: application/json' \
-d '{"content_blocks":[
{"type":"file","file_id":"$IMG_FILE_ID","filename":"photo.jpg","excerpt":"(图片附件)"},
{"type":"text","text":"描述这张图片"}]}'- 前提:chat 路由含
capabilities:["vision"]端点(§2.4 fallback 位)——否则图片降级为占位文本,助手会说「只收到注记」; - 图片以原生
image_urlparts 随轮(7MB/图守门,超限降级);服务端以附件行判图,不信客户端 mime。
§11 文生图
无需专门端点——自然语言触发,模型经内置工具 generate_image 出图:
bash
curl -sk -N -X POST "$BASE/api/v1/app/conversations/$CONVERSATION_ID/turns" \
-H "X-AgentHub-Api-Key: $API_KEY" -H "X-AgentHub-On-Behalf-Of: $SHADOW_USER_ID" \
-H 'Content-Type: application/json' \
-d '{"content_blocks":[{"type":"text","text":"画一张全新的 logo:金色沙漏 + 世界地图网格,深蓝背景"}]}'
# SSE 帧序:turn_started → [text_delta...] → turn_file → turn_completed
# turn_file: {"turn_id":"...","file":{"type":"file","file_id":"<uuid>",
# "filename":"image-1.png","mime_type":"image/png","size_bytes":12345}}
# 取图(短 TTL 签名 URL;closed 会话历史文件仍可读)
curl -sk "$BASE/api/v1/app/conversations/$CONVERSATION_ID/files/$FILE_ID" \
-H "X-AgentHub-Api-Key: $API_KEY" -H "X-AgentHub-On-Behalf-Of: $SHADOW_USER_ID"
# → data.url 浏览器直开即图前提:快照带 max_images_per_turn + 已注册可达的 image_gen 模型;计费并入轮次价零额外扣点;生成 30~90s,轮次墙钟要给够(§3 要点)。
§12 计费对账
bash
curl -sk "$BASE/api/v1/billing/points/ledger?user_id=$SHADOW_USER_ID" \
-H "Authorization: Bearer $TOKEN"
# 完整链可见 entry:manual_adjust(§4.2 入账)/ freeze / deduct / unfreeze- 轮次:
freeze(operation_id=turn:{turn_id})→settle(失败unfreeze全额退); - 语音:
stt:{transcription_id}按次 /tts:{speech_id}按次(缓存命中 0); - 余额不足开轮 → 402
POINTS_INSUFFICIENT(零副作用,你的产品接「前往充值」); - 结清后可用余额 < 3×单价 →
turn_completed附balance_warning:true(仅提示)。
附录 A:SSE 帧负载速查
外部交付副本:
conversation-runtime-protocol.md(仅调用方单页)——本附录与其双源维护,变更需双改。
| 帧 | 次数 | 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}};下一轮回传 {"type":"choice_selection","card_message_id","selected":[...]} |
turn_file | 0..N | {turn_id, file:{type:"file", file_id, filename, mime_type, size_bytes}} |
turn_completed | 1 | {turn_id, status:"succeeded", points_charged:int|null, message_ids:[...]};可选 balance_warning:true |
帧格式标准 SSE(id/event/data 三行),id 支持 Last-Event-ID 续传。
附录 B:错误码目录(对话接入域)
外部交付副本:
conversation-runtime-protocol.md§6——本附录与其双源维护,变更需双改。
| HTTP | code | 含义 / 处置 |
|---|---|---|
| 401 | API_KEY_INVALID | API-Key 错/吊销;检查头 |
| 403 | AUTH_TENANT_MISMATCH | On-Behalf-Of 用户非本租户或非 active;不降级 |
| 402 | POINTS_INSUFFICIENT | 余额不足;零副作用,引导充值后重试 |
| 404 | CONVERSATION_NOT_FOUND / _TURN_NOT_FOUND / _MESSAGE_NOT_FOUND / _ATTACHMENT_NOT_FOUND | 资源不存在或跨租户(防枚举同形) |
| 409 | CONVERSATION_CLOSED | 会话已闭合;开新会话 |
| 409 | CONVERSATION_ACTIVE_TURN_CONFLICT | 同会话已有非终态轮次;等完成或重拉 |
| 409 | CONVERSATION_AGENT_NOT_PUBLISHED / _AGENT_ARCHIVED | 发布 Agent / 恢复后重试 |
| 409 | AGENT_PUBLISH_VALIDATION_FAILED | 发布缺单价↔护栏配对;补齐字段 |
| 409 | MODEL_ROUTE_INVALID | 路由的模型不属于该组 |
| 422 | VALIDATION_ERROR | 请求形状/ MIME / 字节数不过白名单 |
| 422 | CONVERSATION_SPEECH_NOT_ENABLED | 快照缺 speech 组价;按不可用降级 |
| 500 | MODEL_USAGE_METADATA_MISSING | 模型注册缺 unit_price/price_unit(欠账 MR4-1;补数据) |
| 500 | CONVERSATION_TURN_FAILED | 轮次执行异常(带 trace_id 找平台) |
| 504 | CONVERSATION_GUARDRAIL_VIOLATION | 护栏拦截(墙钟超时等;message 有具体原因) |
附录 C:已知坑速查(实证,编号=修复 PR / 欠账)
| 症状 | 根因 | 处置 |
|---|---|---|
| STT 返回转写指令复读 | 旧线形纯文本调用(#296 已修) | 已修;勿引用 file_urls+prompt 形状 |
| 转写「转写中」很久 | 上游高峰排队 85s+ | 等;UX 提示属欠账 MM6-3 |
| 轮次 60s 后空白「成功」 | 墙钟掐断在跑工具被静默吞掉(欠账 MM6-1) | 规避:发布时 turn_timeout_seconds ≥ 180 |
| 助手回复一堆 JSON | 工具协议散文包裹泄漏(#299 已修) | 已修 |
| 图片「只传了注记」 | chat 路由无 vision 端点(fid 404 已由 #297 修) | vision 模型放路由 fallback 位 |
| 模型首次调用 500 | 注册缺单价(欠账 MR4-1) | 注册时带 unit_price/price_unit |
语音/画图 url error | Token Plan 网关仅服务 chat;两把 key 不可混用 | 语音/画图模型走经典 DashScope 网关 |
| 新版本不生效 | 会话钉死打开时的 agent_version(设计) | 开新会话(换 client_conversation_key 或不传) |
完整欠账清单:task_package_list.md § MM/MR 真栈落地欠账。
附录 D:事实源指针
| 主题 | 位置 |
|---|---|
| 端点契约 SSOT | openapi.yaml |
| curl 级教程(SOP 任务 / 会话 / 界面操作) | hello-agent-tutorial.md |
| 会话运行面协议一页(仅调用方,随凭证交付) | conversation-runtime-protocol.md |
| 最小客户端示例 + 本地 mock(SSE / 断连重拉) | sdk/python/examples/ |
| 能力总览(导航版) | ai-agent-integration-guide.md |
| 架构决策(语音/附件 ADR-0055 · vision ADR-0056 · vendor ADR-0057 · 计费 ADR-0050 · 委托 ADR-0044/0052) | adr/ |
| 部署与环境 | docs/ops/ |