Skip to main content

P4.7 — 业务 tool 统一分发:两方向完整对比

决策文档。2026-07-08。给用户定 P4.7"统一 tool 分发层建在哪"。基于亲验事实(非设计文档转述)。不是实施计划——定了方向后才写实施计划。

✅ 决策(2026-07-08,用户拍板):方向 A —— 复用现有 gateway 作统一层 + 一层薄 MCP 适配把业务 tool 暴露给 Hermes。理由见下方决策矩阵与推荐段:最简充分、不碰活 gateway、直达 draft-tool 目标;E2 主 draft pipeline 迁移不临近(phase-4.5 明确不迁),AI SDK 统一 tool 层的债短期不触发,留到 E2 真迁主 pipeline 时再建(那时才有真实消费者)。

一句话问题

Specialist 在客户 chat 里现在调不了任何业务 toolorder_lookup 等)。P4.7 要接通。核实发现"统一分发"有两种建法,本文对比。用户方案锚点:"Hermes 基础 tool 不碰,业务 tool 统一管理+分发,再分发给 Hermes agent"——两方向都遵守这个正交分离,区别只在统一层建在哪、复用多少

亲验事实(两方向共同的地基,不可推翻)

  1. 业务 tool 执行链已存在且是活的ToolGatewayService(policy+approval+manifest 校验)→ RuntimeToolExecutor 手写 switch dispatcher(executeOrderLookup/executeShopify/executeJumio/… 真实 HTTP+凭证俱全)。共享 agent 经 agent/tool_gateway_client.pyPOST /v1/runtime/tool-gateway/execute(RunnerTokenGuard)真实调用。不走 AI SDK
  2. AI SDK 统一 tool 层零实现LlmService(AI SDK v7)签名预留 tools?/stopWhen? 透传字段,但零业务调用点、没 import tool()、没多步循环generateObject 是 structured output ≠ tool calling。
  3. Hermes 不认 AI SDK:Hermes 是独立 Python 二进制,tool 机制是 OpenAI-function-calling 兼容 + MCP(stdio/HTTP/SSE 一等公民)。AI SDK 的 execute 回调(NestJS TS 进程内)物理上进不了 Hermes 循环。
  4. Hermes 进程内执行 tool,不吐回 tool_callhermes chat 单次子进程自己跑完 function-calling 循环。要让 Hermes 调外部 tool,只能让 tool"住进 Hermes 看得见的地方"——即 MCP server(mcp_servers: 里的 server 成 -t 可选 toolset)。
  5. 真 bugmain.py:699 现把 json.dumps(tools_manifest)(tool 定义数组)传给只接 toolset 名的 -t → 静默失败。gateway 目前任何路径够不到 Hermes。两方向都要修这个
  6. 凭证铁律(ADR-036/R6-AC3):credentialRef 绝不进 agent context。执行必须 server-side(gateway 已满足)。
  7. E2 phase-4.5 边界(已亲验):只迁 expert-consult chatStream 到 LlmService,主 draft pipeline runAgentPipeline 明确列 non-goal——短期仍 Hermes。

关键洞察:无论哪个方向,"分发给 Hermes"这座桥都是 MCP

因为事实 3+4:Hermes 只认 MCP。所以"业务 tool 分发给 Hermes agent"这一段,两方向的出口都是一个 MCP 适配层。差别不在这座桥,而在桥的另一头(统一层)是什么


方向 A:复用现有 gateway 作统一层 + MCP 适配出口

业务 tool 真相源 = tool_binding(config-asset) + TOOL_CATALOG/AGENT_TOOL_REGISTRY
│ (统一管理:Ops 配 binding,P2.5 schema 已就绪)

ToolGatewayService(已活)——policy / 审批 / manifest / dispatcher

│ HTTP (POST /v1/runtime/tool-gateway/execute,已活)

┌─────┴──────┐
│ MCP 适配层 │ ← P4.7 新建的唯一组件:一个 MCP server,
│ (薄) │ 暴露业务 tool 定义,handler 转调上面的 gateway
└─────┬──────┘
│ MCP (stdio 或 HTTP)

Hermes(mcp_servers: 配置 → -t 选中 → 循环里调)

P4.7 = 建一层薄 MCP 适配 + 修 main.py:699 + 交集/审批 wire。

  • 统一层:就是已活的 gateway(dispatcher+policy+审批+凭证 server-side)。不重建。
  • 新建组件:一个 MCP server(薄),只做"把 gateway 的业务 tool 暴露成 MCP tool",handler 转调 /v1/runtime/tool-gateway/execute。凭证不进它(只知 gateway URL + runner token)。
    • 形态待运行时 spike:stdio(Hermes spawn 本地进程,最轻,无独立部署)vs HTTP(独立服务)。stdio 优先——无新长期服务。
  • 交集active skills.tools ∩ bindings.toolSlug(R6.3)决定这次 chat 把哪些 MCP tool 名放进 -t
  • write 审批:gateway 已有 require_expert_approval 枝 → 落 ExpertQueueItem(已锁)。MCP handler 对 write-class 返 "queued for approval",真副作用等 Expert 释放。
  • P4.6 吸收:MCP 就是载体,tool_binding.kind 加 mcp 值在这里自然发生。

工作量:M-L。主要是 MCP 适配层(薄)+ main.py wire 修复 + 交集逻辑 + write 审批接 ExpertQueueItem + 4 项运行时验证。不碰 AI SDK、不重建执行层

代价/局限

  • 统一层是"手写 dispatcher"形态,不是 AI SDK 的声明式 tool。将来若 E2 把主 draft pipeline 迁到 NestJS LlmService,tool 分发要再迁一次到 AI SDK(技术债)。
  • 但 E2 phase-4.5 明确不迁主 pipeline(事实 7),这个债短期不触发。

方向 B:新建 AI SDK 统一 tool 层 + MCP 适配出口

业务 tool 真相源 = AI SDK tool({description, inputSchema, execute})
│ (P4.7 从零建:把业务 tool 定义成 AI SDK tool)

LlmService 统一 tool 分发(现在零实现,要建多步循环/execute 编排)
│ execute 回调 → 仍需调 gateway 的 dispatcher(凭证 server-side)
│ 或把 dispatcher 逻辑搬进 AI SDK execute

┌─────────────┐
│ MCP 适配层 │ ← 一样要,因为 Hermes 不认 AI SDK(事实 3)
└─────┬───────┘

Hermes

P4.7 = 建 AI SDK 统一 tool 层(新基础设施)+ 把现有 gateway 改造/包进来 + 一样要 MCP 适配 + 修 main.py:699。

  • 统一层:基于 AI SDK tool() 的声明式定义 + LlmService 多步循环。从零建(现在零实现)。
  • 和现有 gateway 的关系:两种子选择——(B1) execute 回调转调现有 gateway(gateway 保留,AI SDK 层套在外面);(B2) 把 dispatcher 逻辑搬进 AI SDK execute(gateway 逐步废弃)。都要动现有活代码。
  • 一样要 MCP 适配:Hermes 不认 AI SDK,所以 draft 路径(走 Hermes)仍需 MCP 桥——AI SDK 统一层对 Hermes 这条路径帮不上直接的忙,只对"将来走 LlmService 的路径"(如 E2 迁移后)有用。
  • write 审批 / 交集 / P4.6:同 A。

工作量:L-XL。方向 A 的全部 + 从零建 AI SDK tool 层 + 改造现有 gateway。

收益

  • 为将来 E2 迁主 draft pipeline 到 NestJS 铺路——那时 tool 分发已经是 AI SDK 原生,不用再迁。
  • 声明式 tool 比手写 switch dispatcher 更易维护、类型更安全。
  • 统一层真正统一(一处定义,chat/consult/未来路径都用)。

代价/风险

  • 对当下 draft-tool 目标,AI SDK 层是绕路:draft 走 Hermes,Hermes 要的是 MCP,AI SDK 层不在这条链上。等于为了 P4.7 先建一个 P4.7 当下用不到的基础设施。
  • 违反"最简充分方案"——除非 E2 迁移临近,否则是在没需求的地方先建抽象。
  • 动现有活 gateway = 回归风险。

决策矩阵

维度A:复用 gateway + MCPB:新建 AI SDK 层 + MCP
统一层现状已活零实现
当下 draft-tool 目标直达绕路(AI SDK 不在 Hermes 链上)
工作量M-LL-XL
碰活代码回归风险低(只加 MCP 适配)中-高(改造 gateway)
为 E2 迁移铺路否(留债)
MCP 桥也要(躲不掉)
write 审批→ExpertQueueItem
符合第一性/最简充分是(当下)仅当 E2 临近才划算

我的推荐(供参考,你定)

方向 A。理由:

  1. 第一性原理 + 最简充分:P4.7 的真需求是"draft 能调业务 tool"。draft 走 Hermes,Hermes 要 MCP。A 直达;B 先建一个当下这条链用不到的 AI SDK 层。
  2. MCP 桥躲不掉:两方向都要它。B 的额外 AI SDK 层对"分发给 Hermes"零帮助(事实 3)。
  3. E2 债不紧迫:E2 phase-4.5 明确不迁主 draft pipeline(事实 7)。等 E2 真要迁主 pipeline 时再建 AI SDK tool 层,那时它有真实消费者,不是空建。
  4. 低回归:只加薄 MCP 适配,不动活着的 gateway。

唯一让 B 更优的情形:若你打算近期就推进 E2 迁主 draft pipeline 到 NestJS(把 draft 从 Hermes 搬到 LlmService)。那样 draft 不再走 Hermes,AI SDK tool 层就成了主路径,B 的"铺路"变成"当下就用"。这取决于 E2 主 pipeline 迁移的时间表——是我不知道、需要你/Franky 定的信息。

待运行时 spike(无论 A/B,选定后做)

  1. -t '<json>' 报 Unknown toolsets(证 main.py:699 bug)。
  2. 证 mcp_servers 里 server 成 -t-selectable + headless hermes chat -q -Q 能调其 tool。
  3. 证 write tool 在 gateway-approval 语义下的行为。
  4. 证 ToolGatewayService 怎么把 "pending approval" 状态返给 MCP handler。