A1 · 工具调度 · 蓝皮书 · 东方屹腾执行型 Agent
| 字段 | 值 |
|---|---|
| 主模式 | A1 工具调度 Tool Dispatch(行动 × 路由) |
| 结合模式 | A4 最简工具集 · A2 规划执行 |
| 案例 | 上海东方屹腾科技 · HR/薪酬 SaaS · 服务 2 万+ 企业 · 执行型 Agent |
| 对应白皮书 | /zh/patterns/a1-tool-dispatch/ |
| 源 | 梁博 AICon 逐字稿 第三章 · PPT 14–15 页,第六章 · PPT 22 页 |
| 一句话 | 工具不在编排器层裸调,而是封装进行动能力里调用,调用规范统一到「每个工具声明自己依赖和产出哪个机械状态坐标」的注册协议上,原有 SaaS API 经网关暴露即可被感知调用、不需要改造。 |
场景:这一格在案例里解决什么
东方屹腾的执行型 Agent 要做的事,是把用户口语化的业务意图转成对一连串业务 API 的可靠编排调用。工具调用因此是这个系统的行动落点:搭薪资组、算薪、代发、入职办理,每一个场景最终都落到若干次真实的 SaaS 接口调用上。
这一格要解决的问题有两层。第一层是工具该怎么调——是让编排器直接拿到推理产出的工具名就裸调一次函数,还是把这次调用放进一个能观察、能续作的结构里。第二层是工具该怎么注册——几百个原有 SaaS API 怎么进入 Agent 的世界、怎么让 Agent 知道某个工具要哪个参数、这个参数又该从哪里取,而不是交给模型临场生成。前一层决定调用的运行形态,后一层决定调用的可靠性地基。
落地演进:问题怎么把它逼出来
最直接的写法是让推理直接产出工具调用信号,编排器拿到信号用对应函数承接一下就完事。逐字稿里梁博明确说过这条路在编码上没什么不可以,但不符合执行型 Agent 的实际形态。原因是推理每次只推出「下一步做什么」,不是一次推出全部步骤——因为一旦发生行动,世界状态就变了,下一步要看最新上下文再定。这意味着工具调用天然要嵌在一个「干一步、看一步、没到目标就再干」的循环里,而不是孤立的一次函数调用。
于是工具调用被收进了行动能力。ReAct 里每一轮有 Thought、Action、Observation 三件套,作为一个 block 追加到 scratchpad 草稿纸看板上,后面的步骤读 scratchpad 的 block 链就能接着之前已完成的事继续推理。工具调用是这条链里 Action 的一种具体形态,所以它不在编排器层裸调,而是封装在行动能力中——一次调用其实有环绕它的很多能力和场景要进行:要先读看板知道前面干了啥、要把调用结果观察进看板、要比对用户目标判断要不要再来一轮。把工具从这个上下文里拎出来单独裸调,等于丢掉了它周围的这一整套机制。
注册侧的演进更曲折。一开始团队按 MCP 那套思路设想:把 API 全描述成工具,参数交给 LLM 从对话上下文里解析生成、绑定到下游调用。这条路在内容生成型场景里能走通,但东方屹腾的参数大量是雪花算法生成的 64 位甚至 128 位随机 id(如 template_id)。LLM 是无状态概率模型,每次调用都是一次新生成,它只能尝试生成参数、不能本质意义上原样取用你给它的参数,让它原样吐出一个 64 位随机串,出错概率极大。id 缺一位会校验失败、错一位更糟——Agent 执行成功,却破坏了业务数据。把参数交给模型生成这条路在本质上行不通,问题逼出了一套机械状态平面,以及配套的工具注册协议。
关键设计:数据结构 / 控制信号 / 机制
工具调用封装在行动能力里。 工具不是编排器的直接被调方,编排器只负责按控制信号把控制权交给行动能力,由行动能力在 ReAct 循环里发起这次调用。调用的输入、结果、对目标的比对,都在 scratchpad 这个数据结构里串起来。技能、工具、知识库检索在这一层是同构的——它们都是 Action 的可选形态,由推理产出的控制信号选中哪一种。
工具与技能的统一注册协议。 这是这一格最实的部分。因为系统是一套企业级封闭体系,所有工具都由团队自己管理注册,不接外部不可信工具,所以 Agent 启动时就能把它感知的世界里所有可能的状态键字典确定下来。注册协议要求每个工具声明自己的机械状态参数依赖坐标:它需要哪个参数、这个参数的 key 是什么、应该由哪个工具在哪个运行层级上产出。每个工具因此既是机械状态平面的生产者,也是消费者。
机械状态平面只管坐标的唯一性和最新值。 它不替工具决定谁该读谁该写,只负责两件事:用「键名 + 作用域」确定出的键坐标的唯一性,以及每个键在会话时间轴上的最新状态维护。哪个消费者要取哪个坐标上的参数,由消费者自己声明和校验。运行态里每个参数对应一个 Provenance 结构体,由各项注册描述解析组装而成,是这个坐标的唯一身份。可以想象成 Agent 启动时就砌好了一整墙小格子,一格一个机械状态参数,格子按会话时间轴维护最新值,消费者要哪个就去哪个格子读。系统级参数(如用户登录会话里的身份、权限)在关键事件处写入,比如用户登录时。
原有 SaaS API 经网关暴露即可。 有了统一状态平面和注册协议,原有的所有 SaaS API 只要通过网关暴露出来就能直接被 Agent 感知使用,按场景编排组合任意数量的连贯调用,而不会发生参数写入、读取、绑定的错误。API 本身不需要任何改造。这是这套设计落到存量系统上的关键收益——两万多家企业背后那套成熟的 SaaS 接口矩阵不用为了上 Agent 而重写。
踩过的坑与取舍
-
不要让编排器裸调工具。 看上去最省事,但工具调用一旦脱离行动能力的循环,就没有看板上下文、没有观察、没有「看一步再走」的续作能力。执行型 Agent 的每次调用都需要它周围这一整套环绕能力,裸调省下的代码会在可靠性上加倍还回来。
-
不要让 LLM 生成机械状态参数。 这是团队真踩过的坑。把上游调用结果追加进上下文、让模型解析生成下游参数,在内容型参数(像「上海」「中雨」变「有雨」这种语义不变形即可的)上能容忍偏差,但在 64 位随机 id 上是灾难。机械状态必须从概率模型里彻底拿出来,交给确定性的数据结构和程序维护。
-
唯一性坐标要靠「键名 + 作用域 + 产出环节」一起确定,不能只靠 key 名。 同名参数可能在不同运行层级被不同工具产出,光有 key 名定不出唯一坐标。Provenance 把供给者和产出运行环节一起编进坐标,才保证消费者读到的是对的那一个。
-
封闭体系是这套注册协议成立的前提。 团队明确不接外部任意工具,所以才能在启动时枚举出全部状态键、才能在注册环节一次性把坐标注册齐。如果你的场景要热插拔不可信的外部工具,这条前提不成立,机械状态平面的封闭枚举就得另想办法。
边界与指标
这套工具调度的重量不在「挑哪个工具」的算法上,而在注册协议和机械状态坐标的工程纪律上。它只在「多步 API 调用之间有严格的状态参数绑定传递、且参数是不可由模型生成的机械值」时才值得上。要盯的是几条:工具注册时机械状态依赖坐标是否声明完整、机械状态平面里每个键坐标是否唯一、写操作绑定的参数是不是从坐标里取的真实值而非模型生成值、以及连贯多步调用里上游产出的 id 能否被下游准确读到。任何一处让模型重新生成了机械参数,就是这格失守的信号。
对应白皮书的哪几节
这是 A1 工具调度(行动 × 路由)的一个企业落地实例。它对应白皮书「核心机制」里「靠元数据和工程契约而非更聪明的提示来选工具」这条总判断——东方屹腾把工具元数据扩成了带机械状态依赖坐标的注册协议,正是把工程师对参数从哪来的判断编码成机器可读的契约。它也对应白皮书「容易出错的地方」里「副作用工具没配套」与「元数据太薄」两条,案例给出的解法是用 Provenance 坐标把每个参数的来源和作用域钉死。与白皮书略有不同的是,案例的语境是封闭企业体系,所以「工具中毒」「外部来源不可信」那一类外部威胁不是它的主战场,它的主战场是机械状态参数的确定性绑定。
可迁移判据:别的 SaaS 什么条件下照搬
满足这几条就该照搬这套工具调度:工具调用要嵌在「干一步看一步」的循环里而非一次到底、多步调用之间有严格的入参出参绑定传递、且传递的是机械值(数据库 id、流水号、不可由模型重新生成的随机串)。这种场景下,把工具封装进行动能力 + 用注册协议声明机械状态坐标 + 经网关暴露存量 API,是一套能直接复用的骨架。
反过来,如果你的工具调用之间传递的主要是内容型文本(城市名、天气描述、可容忍语义偏差的参数),像旅行助手、投研报告生成那一类,那 MCP 那套让 LLM 从上下文生成参数的玩法本来就够用,没必要引入机械状态平面和坐标协议这套重机制。判别点很干脆:你下游绑定的参数错一位会不会破坏业务数据。会,就上这套。不会,就别上。
另外有个顺带的红利:一旦工具调用统一封装进行动能力、参数统一走机械状态坐标,多步任务的整体编排(见 A2 规划执行切片)就能直接复用同一套调用基座,每个任务节点内部仍是一次走协议的 dispatch,不用再为规划执行单独造一套工具调用机制。
一句话
工具调度在这个案例里的价值,是把「调哪个工具、用哪个参数」这件事从模型的临场生成里收回工程层——工具封装进行动能力调用,参数靠注册协议声明的机械状态坐标确定性传递,存量 SaaS API 经网关一暴露就能被可靠编排,一行接口改造都不用动。