Agent A 从贷款材料里读出一个错误的月收入数字,Agent B 相信了这个数字并算出高分,Agent C 基于这个前提直接放行——整条 3-Agent 贷款审批链路没有一层质疑前序输出,也没有状态检查点可以回滚。这是论文里那个让人印象深刻的失控案例,也正好解释了为什么越来越多团队开始重视「多 Agent 编排架构」的工程边界。我在把 AgentMaster 编排层接上统一模型通道时,用的是 TaoToken:先去 https://taotoken.net/?utm_source=taotoken_aicg_blog_end 创建一把 Key,再把每个 Agent 初始化时读取的 base_url 改成 https://taotoken.net/api。这样做的直接好处是,Agent A、B、C 三跳里真正反复调模型的那一段有了统一入口,出现幻觉或级联错误时也更容易定位是哪一跳的请求先偏了。
1. 3-Agent 贷款审批链路为什么会连续错三跳
1.1 幻觉、级联、错误前提:一条链路上的三种失效姿势
那条贷款审批链路的失效过程并不复杂,但每一个环节都踩到了多 Agent 系统的典型坑。Agent A 负责从申请材料里抽取关键字段,它把一份月收入看错了位;Agent B 拿到这个数字,按自己的评分策略算出一个高分,但它没有回头确认上游数字是否可信;Agent C 看到 B 给出的分数,直接进入了放行判断。三个 Agent 之间没有质量验证层,也没有任何一处停下来问一句「前一步的输入合理吗」。
这就是多 Agent 编排里最常被忽略的问题:单个 Agent 的输出看起来都正常,但整条链路合起来是错的。传统单 Agent 场景下,你只需要检查一次输出;多 Agent 场景下,错误会沿着消息传递路径逐级放大。论文把它总结成三类失效姿势——上游幻觉、中游级联、下游错误前提——这三类在贷款审批里恰好各占一个位置。
1.2 四层职责边界:planning / policy / memory / communication
论文给出的工程蓝图,是把编排层拆成四个职责边界清晰的组件。planning 负责把任务拆成可执行的子步骤,决定谁先谁后、依赖关系怎么排;policy 负责约束每个 Agent 能做什么、不能做什么,以及什么条件下必须停下来等待确认;memory 负责保存跨 Agent 的共享状态,包括任务进度、中间结果和检查点;communication 负责 Agent 之间的消息投递,包括格式、路由和签名校验。
这四层各管一段,边界划清楚之后,前面那条贷款链路就有救了:policy 层可以强制 Agent B 在评分前验证输入范围,memory 层可以在 Agent A 输出后打一个检查点,communication 层可以通过签名确保 Agent C 收到的分数确实来自 B 而不是被篡改。工具调用走 MCP,Agent 间通信走 A2A,这也是论文点名 AgentMaster(A2A+MCP 集成)与 ScaleMCP 的原因——它们是目前少数把这两条路径同时落在可用基础设施上的方案。
1.3 编排层四组件分工之后,Token 消耗点在哪里
职责边界划清楚之后,还有一件容易被忽略的事:这四层里真正持续消耗 Token 的,是每个 Agent 反复调模型的那一段。planning 需要模型来拆任务,policy 需要模型来判断条件,Agent A、B、C 各自需要模型来完成数据抽取、评分、放行判断。长会话、多工具、任务编排这三个特征叠加起来,模型请求的密度会比单 Agent 场景高不少。
所以我会把编排框架里模型 provider 的访问地址统一改到 https://taotoken.net/api。不是说官方通道不能用,而是当你同时跑 Worker、Service、Support 三类角色,每条链路都要独立发模型请求时,统一入口在排查和配额管理上省事得多。Key 从 https://taotoken.net/?utm_source=taotoken_aicg_blog_end 创建,填进编排层之后,A2A 审计日志与状态检查点仍然按论文的思路实现,只是每条模型请求多带了一个可追溯的来源。
2. 三类 Agent 角色表与 A2A 消息结构不动,动的是模型配置
2.1 Worker / Service / Support 三类角色的分工
论文里的三类 Agent 角色表,是整篇编排蓝图里最值得保留的部分之一。Worker 负责具体执行任务,比如数据抽取、格式转换、单点计算;Service 负责对外提供能力,比如评分服务、审批服务;Support 负责兜底和辅助,比如质检、日志归档、异常上报。这三类角色在贷款审批链路里的对应关系是:Agent A 是 Worker,Agent B 是 Service,Agent C 是另一个 Service。
| 角色 | 职责 | 贷款审批链路对应 | 典型调用频率 |
|---|---|---|---|
| Worker | 执行具体子任务,产出中间结果 | Agent A 数据抽取 | 高,每份材料一次 |
| Service | 对外提供可复用能力 | Agent B 评分、Agent C 放行 | 中,按需触发 |
| Support | 质检、日志、异常兜底 | 质检 Agent(论文建议补齐) | 低,按规则触发 |
这张表的核心价值在于,它把「谁干什么」和「谁检查谁」分开写清楚了。Worker 只对自己的子任务负责,Service 不替 Worker 做验证,Support 才有权限对前两者提出质疑。论文强调,正是因为没有 Support 这一层,贷款链路才没有人在 B 计算之前拦一下 A 的输出。
2.2 A2A 消息的 sender_role / recipient_role / signature
Agent 间通信走 A2A,消息结构里最关键的三个字段是 sender_role、recipient_role 和 signature。sender_role 标明这条消息从哪类角色发出,recipient_role 标明它要投递给哪类角色,signature 用来校验消息在传输过程中没有被篡改。这三个字段在论文里被反复强调,因为它们是多 Agent 编排里「可追溯」的最小单元。
我保留这套结构不动,原因是它和模型 provider 是谁没有关系。把 base_url 改到 https://taotoken.net/api 之后,A2A 消息照样按原格式投递,sender_role 照样是 worker / service / support,signature 照样在每个检查点校验。唯一变化的是每个 Agent 在生成消息内容时,模型请求走的是统一通道,而不是各配各的地址。这样做的好处是,排查链路错误时你只需要看两个地方:A2A 审计日志里的 sender/recipient/content/timestamp,以及编排层模型配置里那条 base_url。
2.3 MCP 管工具调用,A2A 管 Agent 间通信
工具调用走 MCP,Agent 间通信走 A2A,这是论文给出的分工原则,也是 AgentMaster 能在两种协议之间做集成的基础。MCP 负责让 Agent 拿到外部工具的能力,比如读取文件、查询数据库、调用内部服务;A2A 负责让 Agent 之间传递任务和结果,比如 Agent A 把抽取结果发给 Agent B,Agent B 把评分发给 Agent C。
这里有一个容易混淆的点:MCP 查数据库和 A2A 传消息是两条独立的路径。如果 Agent A 通过 MCP 查了一次内部记录,它拿到的结果要通过 A2A 发给 Agent B,而不是让 B 自己去查一遍。论文在四层职责边界里把这两条路径分开,就是为了避免每个 Agent 重复访问同一份数据,也避免链路中出现「谁都能查库」的权限模糊。
3. 在 AgentMaster 编排层把 provider 指到 https://taotoken.net/api
3.1 先创建 Key,再确认模型 ID
配置之前有两件事要做完。第一件是打开 TaoToken 注册并创建 API Key,Key 拿到之后先别急着填进多个地方,统一放在一个环境变量文件里,方便后面三个 Agent 共用。第二件是去模型广场确认当前可用的模型 ID,不要凭记忆写,也不要随手加日期后缀,具体以 https://taotoken.net/?utm_source=taotoken_aicg_blog_end 模型广场当时的列表为准。
准备材料这一段的顺序建议是:Key 先建好,模型 ID 先抄准,然后才动编排层的配置文件。很多人习惯先把文件改一半再回头找 Key,结果配置里留下了半截占位符,跑起来报 401 还要重新排查。把这两样东西准备好,后面的配置就是一次填完的事。
3.2 AgentMaster 模型配置文件里的 provider 段
AgentMaster 这类编排框架通常把模型 provider 的信息集中在编排层的一个配置文件里,三个 Agent 初始化时都读同一份。下面是按这个思路写的配置示例,文件路径以你自己的项目结构为准:
# orchestrator/config/model_provider.yaml provider: name: taotoken base_url: https://taotoken.net/api api_key: YOUR_API_KEY model: YOUR_MODEL_ID agents: - role: worker name: extrator provider_ref: taotoken - role: service name: scorer provider_ref: taotoken - role: service name: approver provider_ref: taotoken这段配置里,provider 段是核心,三个 Agent 通过 provider_ref 引用同一份通道信息。base_url 末尾不要加 /v1,也不要写成官网落地页的地址,接口地址和给人点的页面是两回事。api_key 一律用 YOUR_API_KEY 占位符,真实的 Key 从环境变量注入,不要直接提交进仓库。
如果项目更习惯用环境变量,也可以改成这种写法:
export TAOTOKEN_BASE_URL=https://taotoken.net/api export TAOTOKEN_API_KEY=YOUR_API_KEY export TAOTOKEN_MODEL=YOUR_MODEL_ID3.3 每个 Agent 初始化时读的就是这一份
编排层配置改好之后,Agent A、B、C 在初始化阶段都会读取同一份 provider 信息。这一步是论文四层职责边界里 planning 和 policy 之间的衔接点:planning 决定三个 Agent 的执行顺序,policy 决定它们各自能用哪个模型、走哪条通道。把 provider 统一之后,policy 层只需要维护一份白名单,而不是每个 Agent 配一套。
A2A 审计日志与状态检查点仍然按原文实现,这里的改动不影响那两块。日志里记的仍然是每条消息的 sender_role、recipient_role、content、timestamp,检查点里存的仍然是链路进度和中间结果。区别在于,当某条消息的内容看起来不对劲时,你可以顺着时间戳去编排层的模型请求记录里对一下,看看是不是那次模型返回本身就偏了。
4. 先放 Agent A 单跑:让数据提取这一跳先稳
4.1 单跳验证:请求成功、返回正常
整条链路一起跑,出错时你不知道是哪一跳先偏的。所以第一次验证建议只放 Agent A 单独跑一遍数据提取,先确认这一跳的模型请求调用成功、返回内容正常。具体做法是给编排层加一个 dry-run 开关,只让 worker 角色的 Agent 执行,service 角色的两个 Agent 暂时挂起。
跑完之后看两个地方:一是编排层模型请求日志里这次调用是否返回 200,二是 A2A 审计日志里 Agent A 是否产出了一条 sender_role 为 worker 的消息。两个都对上,说明通道这一层没问题,可以进入下一跳。如果模型请求失败,先回到第 3 节的配置文件检查 base_url 和 api_key,不要急着改 A2A 消息结构。
4.2 再放行 B、C 两跳
Agent A 单跑稳定之后,再把 B、C 两跳放出来。这一步不要一次全放开,先把 Agent A 的输出手动喂给 Agent B,确认评分逻辑对输入范围的校验生效,再把 B 的输出喂给 Agent C。论文建议的 Support 层质检,也可以在这一步先跑一遍——检查 A 的收入数字是否在合理区间、B 的评分是否依赖了未验证字段、C 的放行条件是否覆盖了边界情况。
放行两跳的过程中,A2A 消息的 signature 校验要保持开启。这一步是验证「消息没有被篡改」最直接的时机,如果 B 收到的 A 输出和 A 实际发出的不一致,signature 会先报错。这比等到 C 放行之后才发现问题要省事得多。
4.3 每条 A2A 消息按 sender/recipient/content/timestamp 落盘
最后一步是按原文要求,把每条 A2A 消息的 sender、recipient、content、timestamp 落盘。这一步看起来像例行公事,但在多 Agent 编排里,它是事后追溯的唯一依据。贷款审批链路的失控案例里,如果没有这份落盘记录,你根本没法判断是 A 读错了、B 算错了,还是 C 判断错了。
落盘的文件建议按链路 ID 分目录,每个目录下按时间戳排序。这样一条链路跑完之后,你能像读日志一样从头看到尾,哪一跳的输入和输出对不上,一眼就能找出来。编排层的模型请求记录和这份 A2A 落盘记录,是排查问题的两条并行线索,缺一条都会让定位变慢。
5. A2A 审计日志与状态检查点落盘之后怎么对账
5.1 检查点没写会导致重放时状态丢失
多 Agent 编排里,状态检查点的作用是让链路在中断之后能从最近一个点恢复,而不是从头重跑。如果检查点没写,或者写的位置不对,一旦某跳失败需要重放,整条链路就得从头开始,前面 Agent 已经消耗的模型请求全部白费。论文在 memory 层专门强调这一点,就是为了避免长会话场景下反复重跑带来的浪费。
落盘的检查点建议至少包含三样东西:当前执行到哪个 Agent、该 Agent 的输入是什么、上游已经产出的中间结果有哪些。这样重放时,编排层可以直接从检查点恢复,不需要重新问 Agent A 要一遍数据。
5.2 模型请求记录和 A2A 消息记录对不上怎么办
对账时最常见的现象是,A2A 消息记录里 Agent B 的输出看起来没问题,但编排层模型请求记录里那次调用的返回和落盘内容对不上。这种情况通常是消息在投递过程中被中间件改过,或者 signature 校验被跳过了。排查顺序建议是先看 signature,再看 content,最后看 timestamp 是否连续。
如果确认是模型返回本身就有问题,再回到编排层的模型配置检查 base_url 是否被某处覆盖成了别的地址,以及模型 ID 是否和模型广场当时列表一致。这类问题在统一通道下比较容易定位,因为三个 Agent 走的是同一个 provider,比较范围比各配一套要小很多。
6. 编排链路上常见的几类报错
6.1 base_url 被写成了官网落地页
这是配置阶段最容易犯的错:把给人点的页面地址和填进工具的接口地址混在一起。记住一个区分方法——注册、创建 Key、看模型广场、看用量时打开 https://taotoken.net/?utm_source=taotoken_aicg_blog_end ,填进编排层 provider 配置的 base_url 一律是 https://taotoken.net/api,末尾不要加 /v1,也不要带任何查询参数。两边混用的直接结果是模型请求 404,而 A2A 消息看起来一切正常,排查时容易绕远路。
6.2 模型 ID 和模型广场列表不一致
第二个常见报错是模型 ID 对不上。有人习惯用记忆里的名字,或者随手加个日期后缀,结果请求返回模型不存在。这类报错的处理方式很简单:回到 TaoToken 模型对话 用同一把 Key 发一条测试消息,确认模型 ID 能正常返回,再把它抄回编排层配置。模型 ID 以模型广场当时列表为准,不要自己编。
6.3 signature 校验失败但内容看起来正常
第三个报错出现在 A2A 层,signature 校验失败,但消息 content 肉眼看起来没问题。这种情况通常不是模型通道的问题,而是消息在投递过程中经过了某个中间件,或者签名用的密钥和校验用的密钥不是同一份。排查时先确认编排层的签名配置是否统一,再回头看模型请求记录里那次调用是否真的产出了这条 content。
这三类报错里,前两类和模型通道直接相关,第三类和 A2A 实现相关。统一模型通道之后,前两类的排查范围会明显缩小,因为三个 Agent 走的是同一个 provider,配置只需要对一处。
7. 收尾:通道先接上,四组件映射图慢慢画
论文里那张四组件职责映射图,planning、policy、memory、communication 各自的边界,其实可以边跑边画。但模型通道这件事,建议在画图之前就先接上,因为三个 Agent 的每次初始化、每次任务拆分、每次条件判断都要发模型请求,通道不通的话整个编排层跑不起来。
接通道的顺序还是那两步:先去 控制台 API Keys 创建一把 Key,再把编排层的 base_url 指向 https://taotoken.net/api。Key 建好之后,如果想先确认套餐和调用规模是否匹配,可以顺带看一下 Coding Plan;编排层里如果有 Agent 需要跑命令行任务,CLI 也可以按文档方式接入:npm install -g @taotoken/taotoken,然后taotoken cc -k YOUR_API_KEY -u https://taotoken.net/api -m YOUR_MODEL_ID。跑通 Agent A 单跳之后,再回到 https://taotoken.net/?utm_source=taotoken_aicg_blog_end 的控制台对一下这次模型请求有没有记上账,确认通道和落盘记录都对得上,再放 B、C 两跳。