Appearance
AgentHub AI Agent 接入指引(孵化新 SaaS 用)
读者:AI coding agent(或人类工程师),正在孵化一款新 SaaS,需要把「AI 多轮会话 Agent + 多模态 + 计费」能力接到自己的产品上,而不是自建。 目的:一次读完即可顺畅衔接 AgentHub 的全部对外能力,避开所有已知坑(坑均带实证编号)。 契约事实源:本文只做导航与约束提示,端点契约以
openapi.yaml(SSOT)为准,两者冲突时以 openapi 为准并回报本文档勘误。 可复制执行版:逐条 curl 的完整配方见saas-integration-cookbook.md。 状态基准:2026-08-23,MM 四项多模态(语音转文字 / 语音播报 / 图片理解 / 文生图)已在 ECS-B 真栈全链闭环;已知欠账见task_package_list.md§ MM/MR 真栈落地欠账。
0. 心智模型(30 秒)
你的 SaaS = 业务壳(自己的前端 / 后端 / 用户体系);AgentHub = headless 会话 Agent 运行时:
你的 SaaS ──(API-Key + 影子用户委托)──► AgentHub
├── 模型网关(多供应商 vendor/路由/能力标记)
├── 会话 Agent(多轮 + SSE 流式 + 工具 + 护栏)
├── 多模态(STT / TTS / 附件 / vision / 文生图)
└── 积分计费(freeze→settle,按轮/按次)你不需要自己管模型 key 转发、提示词编排状态机、SSE 断连恢复、计费对账——这些 AgentHub 都有现成契约。
1. 环境与凭据(两条通道,别混)
| 通道 | 谁用 | 凭据 | 典型端点 |
|---|---|---|---|
| 管理面(builder) | 你的 SaaS 的运营者/开发 agent,建模与发布 | Keycloak JWT(client credentials 取 token) | /api/v1/builder/*(agents、models、model-vendors、routes、tools…) |
| 运行面(app/headless) | 你的 SaaS 的服务端,代表终端用户跑会话 | X-AgentHub-Api-Key: ahk_... + X-AgentHub-On-Behalf-Of: <shadow_user_id> | /api/v1/app/conversations*(会话/轮次/转写/合成/附件/文件) |
- API-Key 经管理面签发(
delivery:api_key:write),明文只返回一次,支持:rotate/:revoke; - 终端用户先映射为影子用户(幂等创建,username = 你侧不可变用户 ID),积分入账到你租户下的影子用户钱包;
- 会话运行面同时接受平台 JWT(ADR-0052 双凭据),但服务端对服务端集成建议统一走 API-Key 通道;
- scope 全集以 openapi
security段为准(当前 57 个)。
2. 一次性资源建模(管理面,按序)
完整 curl 级操作见 hello-agent 教程 §2 / §10.1。顺序与约束:
- Vendor(ADR-0057,租户级注册表):
POST /api/v1/builder/model-vendors——code/api_base/protocol_family(openai_compatible|dashscope)。解析顺序 租户表 > 服务器 env > 内置;重复 Set Route 类覆盖语义已就绪(#298)。 - 模型注册:
POST /api/v1/builder/models——model_type(llm/stt/tts/image_gen/embedding)+ vendor + vault key 引用(key 只入 OpenBao,永不回显)。约束:stt/tts的 vendor 必须 dashscope 协议族(ADR-0055,注册时主动拦截;火山等需先做 MM7-1 扩展);- 视觉模型 = 普通
llm+capabilities: ["vision"](qwen3-vl-plus/qwen-vl-max实测可用); - ⚠️ 欠账 MR4-1:表单暂缺非 LLM 模态单价字段,注册
stt/tts/image_gen后需补unit_price/price_unit(second/char/image),否则首次调用 500MODEL_USAGE_METADATA_MISSING。
- 路由:
POST /api/v1/builder/routes(按组 upsert)——chat 路由把 vision 模型放 fallback 位:主模型接纯文本(便宜快),带图轮次自动独占 vision 端点(MM4-1 路由分流)。 - 会话 Agent + 发布:
agent_type=conversation;发布快照conversation块必须含:points_per_turn+guardrails(强制配对,缺一发布 409);- speech 组:
points_per_transcription/points_per_speech/voice(与计价配对,XOR 拒绝); guardrails.max_images_per_turn(启用文生图的前置 cap,缺席则generate_image工具不注册);- ⚠️
turn_timeout_seconds默认 60s 对画图/SOP 类 Agent 太紧(qwen-image 实测 30~90s),建议显式 ≥180s(欠账 MM6-2)。
- 发布前冒烟:
POST /api/v1/builder/agents/{id}/chat-dry-run——零计费零落库,拿回显 + 配置读数(单价/护栏/KB/工具数)。
3. 运行时:会话与轮次(运行面)
bash
# 开会话(client_conversation_key 可选幂等键)
POST /api/v1/app/conversations {"agent_id": "..."} # → 201 data.id
# 一轮(SSE)
POST /api/v1/app/conversations/{id}/turns {"content_blocks":[...]}
# 帧序:turn_started → turn_delta* → [turn_card] → [turn_file*] → turn_completed- 输入块:
text/file/page_ref/activity(后三类服务端以<data>注入防御包裹);卡片选择回传choice_selection块; - 断连重拉:凭首帧
turn_idGET .../turns/{turn_id},不重跑不重复扣费; - 版本冻结:会话在打开时钉死
agent_version;Agent 发新版本后既有会话永远跑旧版,需开新会话(欠账 CU-UX1:暂无「有新版本」引导); client_conversation_key重放语义:同 key 再开会话返回既有会话(无状态过滤)——想要新会话就换 key 或不复用;- 结束:
POST .../{id}:end→ 编制链(转写/画像/笔记/记忆入用户空间)→closed只读;空闲超时自动闭合。
4. 多模态四件套(均已真栈实证)
| 能力 | 端点 | 关键约束 / 已知坑 |
|---|---|---|
| 语音→文字 | POST .../transcriptions(multipart audio) | MIME 规范化后校验(audio/webm;codecs=opus 这类带参已接受,#295);上游高峰单次 85s+ 属正常,等终态再离开页面;返回 data.text 由你的前端回填、用户可修正后再作为普通 text 轮次发送 |
| 文字→语音 | POST .../messages/{message_id}/speech | (message_id, voice) 缓存,重放零扣点;voice 快照级(longanyang 实证可用;longwan_v2 被引擎拒,#293);返回签名 URL,浏览器直接可播(#294 修内网 base) |
| 附件 + 图片理解 | POST .../attachments:authorize → PUT <upload_url> → POST .../attachments:commit | txt/md/csv 直读、pdf 服务端抽取;图片:chat 路由含 vision 端点时以原生 image_url parts 随轮(7MB/图),否则降级 vision_deferred 占位(非 fail-closed)。fid 读取链已修(#297)。发轮时 content_blocks 带 {"type":"file","file_id":...} |
| 文生图 | 会话内自然语言触发(模型调 generate_image 内置工具) | 前提:快照带 max_images_per_turn + 已注册 image_gen 模型且路由可达;出图为 assistant file 块 + SSE turn_file 帧,经 GET .../files/{file_id} 取签名 URL 下载;注意轮次墙钟(见 §2 第 4 条);计费并入轮次价零额外扣点 |
工具协议说明(对接入方透明,但影响模型行为预期):会话工具走桥内文本 JSON 协议,解析器已容忍裸 JSON / markdown fence / <tool_call> 标签 / 散文包裹四种形态(#299)。
5. 计费与配额语义
- 轮次:
freeze(operation_id=turn:{turn_id})→settle(失败unfreeze全额退);余额不足开轮 →402 POINTS_INSUFFICIENT零副作用;结清后可用余额 < 3×单价 →turn_completed附balance_warning:true; - 按次:
stt:(秒,向上取整)/tts:(字符);文生图并入轮次; - 归因:全部经
ModelUsageEvent→cost_records(task_id=turn_id),points_ledger流水与你侧对账; - 影子用户入账:管理面
billing:points:tenant_grant(operation_id幂等,两侧对账键)。
6. 已知坑速查(全部实证,编号 = 修复 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 位 |
| Set Route 二次提交 500 | 唯一约束撞 INSERT(#298 已修) | 已修 |
模型首次调用 500 MODEL_USAGE_METADATA_MISSING | 注册缺单价(欠账 MR4-1) | 补 unit_price/price_unit |
语音/画图 url error | Token Plan 网关仅服务 chat,key 两把不可混用 | 语音/画图走经典 DashScope 网关 |
| 新版本不生效 | 会话版本冻结(设计) | 开新会话 |
7. 建议接入顺序(冒烟阶梯)
chat-dry-run冒烟(零成本验证发布配置);- 最小会话:开 conversation → 1 轮 text → SSE 三帧齐 →
:end; - 逐项多模态:先附件(文本类)→ STT → TTS → 图片附件(vision)→ 文生图;
- 计费对账:
points_ledger与你侧流水核对(freeze/settle/unfreeze 三态); - 工程化:断连重拉、402 兜底、
balance_warning提示接到你的产品 UX。
8. 事实源指针
| 主题 | 位置 |
|---|---|
| 端点契约 SSOT | docs/design/2.technical/api-spec/openapi.yaml |
| curl 级全流程教程(SOP 任务 + 会话 + 多模态 + 界面) | docs/guides/tutorial/hello-agent.md §5.5 / §10 / §11 |
| 影子用户 / API-Key 委托模型 | ADR-0044、ADR-0052 |
| 计费配对原则 | ADR-0050 |
| 语音/附件红线 | ADR-0055 |
| vision content parts | ADR-0056 |
| 租户 vendor 注册表 | ADR-0057 |
| 已知欠账 | task_package_list.md § MM/MR 真栈落地欠账 |
给 AI agent 的纪律:① 端点形状永远抄 openapi,不要凭记忆构造;② 上游延迟(STT 高峰 / T2I 30~90s)要纳入你的超时与 UX 设计;③ 遇到与本文不符的行为,先查欠账清单再查 openapi,仍无解则在 AgentCollab_MessageBoard.md 留言(若你运行在 AgentHub 仓库生态内)或提 issue。