Chapter 07 · 协作
协作:合鸣之美,多 Agent 之间如何传 token
前面几章都在单个 agent 内部——感知、记忆、推理、行动、反思,都是一个 context window 里的循环。协作是执行拓扑轴的另一端:多个 context 之间如何传递 token。这一章定义"何时该上多 Agent"的成本判据,再逐一拆开层级委派、扇出聚合、对抗评审、交接链四种把多个 agent 接起来的工艺。
本章你将建立的 schema
- workflow vs agent 的切分,以及"多 Agent 约 15× chat token、性能增益 80% 由 token 用量解释"的成本判据——多 Agent 不是架构魔法。
- orchestrator-worker 层级委派:动态拆解 + 上下文隔离 + 回传 1–2k 压缩摘要,以及子 Agent 任务说明书必含的四件事。
- 扇出聚合(fan-out/fan-in / map-reduce)与 sectioning / voting 两子型,及它与 orchestrator 的"拓扑同构、语义不同"。
- 对抗评审的谱系(generator-critic / debate / red-team)与它的失效模式,以及 handoff(Command goto+update)与 swarm vs supervisor 的实测取舍。
07.1何时上多 Agent:先用最简方案
单 Agent 是默认,多 Agent 是一笔"花 token 换并行与隔离"的交易——只在任务能拆成独立并行支线、且超出单窗口容量时才划算。
看到"多个专家分工一定比一个人强"的直觉,最自然的反应是一上来就搭 orchestrator 或 swarm。这个直觉抓错了成本。Anthropic 把 LLM 系统切成两类:workflow 是 LLM 和工具沿预定义代码路径编排;agent 是 LLM 动态自主决定流程与工具调用。多 Agent 是在 agent 之上再叠一层协调,复杂度、延迟、成本都跳一个台阶。所以 L31 的纪律是:先用最简方案,把多 Agent 当成需要论证的升级,而不是起手式。
底层机制(比"多个脑子更聪明"深一层):多 Agent 的增益主要不是来自架构,而是来自烧更多 token 做更多并行探索。Anthropic 的内部 research eval 里,Opus lead + Sonnet 子 Agent 的多 Agent 系统比单 Opus 高 90.2%;但回归分析显示 token 用量单独解释 80% 的性能方差,加上工具调用数与模型选择三因子合计解释 95%。换句话说,多 Agent 赢,是因为它花了 4× 单 agent、约 15× chat 的 token 去并行铺开搜索面,不是"分工 = 更聪明"。判据因此落在任务结构:仅当任务能拆成独立并行支线、且单个 context window 装不下时,并行才值回这 15× 成本。Anthropic 内部有团队花数月搭精巧多 Agent 架构,最后发现把单 Agent 的 prompt 改好就追平——这是反复出现的教训。
| 方案 | 解决什么 | 为什么没选 / 选中 |
|---|---|---|
| 一上来就搭 orchestrator / swarm 框架 | "分工"的直觉满足感 | 约 15× chat token、增延迟与协调失败面;精巧多 Agent 常被改好 prompt 的单 Agent 追平 |
| 紧耦合任务(如 coding)上多 Agent | 想并行加速写操作 | 子任务间依赖太多,并行写会因隐含决策冲突产出互相打架的结果 |
| 默认单 Agent,多 Agent 仅当满足三判据 | 上下文污染会降质 / 任务可并行 / 专业化改善工具选择 | 选中——把 15× token 当成需要论证的预算,只为"独立并行支线且超单窗口"买单 |
# L31:把"要不要上多 Agent"做成一个显式判据,而非默认
def should_go_multi_agent(task):
# 三判据全为否 → 单 Agent,省 15× token
context_pollution = task.needs_many_subqueries # 污染会降质
parallelizable = task.has_independent_branches # 支线可并行
specialization = task.benefits_from_distinct_tools # 专业化改善工具选择
if not (context_pollution or parallelizable or specialization):
return single_agent # 默认路径
# 紧耦合(写操作有依赖,如 coding)→ 仍走单 Agent
if task.is_tightly_coupled: # 子任务依赖太多
return single_agent # Cognition 的立场
return orchestrator_workers # 仅在确实划算时才付 ~15× chat token 的并行预算
# 不变式:增益的 80% 由 token 用量解释 —— 多 Agent 是用算力换探索,不是免费红利
两个头部团队公开对立:Anthropic 主推并行多 Agent(其 Research 系统),Cognition 公开喊"别搭多 Agent"。两边都拿出了实测数据。谁错了?
展开答案(先停 10 秒再点)
都没错——分歧出在任务结构,不是架构对错。Anthropic 的 Research 是读多、支线独立的研究型任务:子 Agent 各自探索一个子问题、彼此不依赖,并行铺开正好划算。Cognition 谈的是写多、紧耦合的编码任务:子 Agent 看不到彼此的中间决策,并行写会产出互相打架的结果(它的 Flappy Bird 变 Super Mario 例)。同一个 09 章的组合视角下,这是"任务可分解性"这一个变量在两端取值,不是两条互斥的真理。判据始终是任务结构,不是谁的 PPT 更响。
07.2层级委派:orchestrator-worker 的上岗培训
一个 lead agent 动态拆解任务、把子任务派给各有独立 context window 的 worker,worker 只回传 1–2k 压缩摘要——隔离防污染,但隔离也切断了子 Agent 间的中间决策共享。
当任务通过了 07.1 的判据,下一个问题是"怎么把它拆出去"。orchestrator-worker(也叫 supervisor / 监督者模式)是层级委派的主干:lead 分析任务、临场拆成子任务、派给 worker、再综合结果。它与 07.3 扇出的区别在于子任务不预定义,由 orchestrator 按输入动态决定。它的可靠性几乎全靠 prompt——没有详尽指令时,子 Agent 会重复劳动、留空白、漏关键信息。
底层机制(两件工艺:上岗培训 + 上下文隔离):其一,每个子 Agent 必须收到一份完整的任务说明书——目标、输出格式、工具/来源指引、清晰任务边界,缺一项就退化成重复劳动或漏报。还要把投入度规则写进 prompt 当启发式:简单查证用 1 个 Agent 跑 3–10 次工具调用;直接对比用 2–4 个子 Agent 各 10–15 次;复杂研究可起 >10 个子 Agent。其二,上下文隔离:子 Agent 各有独立 context window 并行探索,只把最重要的 token 压缩成 1–2k 摘要回传,重物件用 artifact 系统传"轻量引用"而非全文,避免多级处理中的信息丢失。这正是 03 章 context rot 的对策——把每条支线关进自己的窗口,lead 的窗口就不被子任务的噪声撑爆。但隔离是双刃:子 Agent 看不到彼此的中间决策,这正是 Cognition 抨击的断点。最后用一个单独的 CitationAgent 跑一遍,把每条声明绑回来源。
| 痛点 | 设计回应 | 代价 / 边界 |
|---|---|---|
| 子 Agent 重复劳动、留空白、漏关键信息 | 每个子 Agent 收齐目标/输出格式/工具指引/任务边界四件套 | lead 的 prompt 工程量大;说明书写糙则可靠性失去基础 |
| 所有 Agent 共享同一上下文 → 互相污染、撑爆窗口 | 各子 Agent 独立 context window 并行探索 | 切断子 Agent 间中间决策共享(Cognition 警告的硬币另一面) |
| 把完整子轨迹全回传 → 抵消隔离收益 | 只回传 1–2k 压缩摘要,重物件用 artifact 轻量引用 | 选中(生产标准)——压缩有损,关键细节要在摘要里点名保留 |
| 综合环节凭空生成、声明无出处 | 单独跑一遍 CitationAgent 把每条声明绑回来源 | 多一次专门的 LLM 调用与一轮延迟 |
一个团队让 lead agent 把每个子 Agent 的完整探索轨迹(含全部 thought / tool 调用)回传,理由是"信息越全综合越准"。结果 lead 的窗口频繁爆掉、综合质量反而下降。错在哪?
展开答案(先停 10 秒再点)
这个做法抵消了上下文隔离的全部收益。隔离的意义就是让每条支线的噪声留在子窗口里、只把精华喂给 lead;把全轨迹回传等于把所有子窗口的污染又汇总进 lead 的一个窗口,立刻撞上 03 章的 context rot——token 越多召回越差,综合质量随之下降。正确做法是回传 1–2k 压缩摘要,重物件(大文件、长文档)用 artifact 系统传一个轻量引用,需要时再按引用取。隔离的价值在"只回传最重要的 token"这一句话上,破坏它,多 Agent 就只剩成本没有收益。
07.3扇出聚合:fan-out / fan-in 与它的两个子型
把可并行的子问题同时派出去(fan-out)再综合(fan-in);它和 orchestrator 拓扑同构,唯一区别是这里的子任务可以预定义,不必由 LLM 临场决定。
当子任务在写代码时就已经确定(不需要 lead 临场拆解),用 orchestrator 的动态决策就是浪费。扇出聚合(fan-out-fan-in / map-reduce)针对这类静态可并行的问题:拆给多个子 Agent 同时跑,再把结果归并。Anthropic 实测,子 Agent 并行用 3+ 工具时,复杂查询的研究时间最多砍掉 90%——这就是并行换来的墙钟时间收益。
底层机制(拓扑同构,但语义不同):扇出与 07.2 的 orchestrator-worker 画出来是同一张图,差别只在一处——parallelization 的子任务可事先静态定义,orchestrator 的子任务由 LLM 临场决定。Anthropic 的《Building Effective Agents》把它细分成两个子型。sectioning(分段):把任务拆成独立子任务并行,目的是纯提速或做护栏——比如一个 Agent 答用户、另一个并行筛查违规内容。voting(投票):同一个任务跑多次取多样输出或共识,用于需要冗余校验的场景——安全代码审查、内容审核。两个子型共享"扇出—扇入"的骨架,分歧只在扇出的是不同子任务还是同一任务的多次复跑。
| 痛点 | 设计回应 | 典型场景 / 边界 |
|---|---|---|
| 独立子任务串行太慢 / 需要旁路护栏 | sectioning:拆成独立子任务并行跑 | 一个 Agent 答用户、另一个并行筛违规内容——纯提速或加护栏 |
| 单次输出不够可信,需要冗余校验 | voting:同一任务多跑取多样 / 共识 | 安全代码审查、内容审核——用复跑换可靠性,代价是 N× token |
| 子任务要 lead 看到输入才能定 | 改用 07.2 的 orchestrator 动态拆解 | 拓扑同构但子任务非预定义,多一层 LLM 决策开销 |
层级委派(图 07.2)和扇出聚合画出来几乎一模一样:一个分发、几个并行、一个综合。既然拓扑同构,为什么还要把它们当成两个不同的模式?
展开答案(先停 10 秒再点)
区别不在拓扑,在子任务从哪来。扇出聚合(parallelization)的子任务可预定义——写代码时就知道要拆成哪几块,运行时直接 fan-out,无需 LLM 决策;orchestrator-worker 的子任务由 lead 临场决定——要先让 lead 看到具体输入、动态拆解,多一层 LLM 推理。这条区别决定了成本与可控性:能预定义就别让 LLM 临场拆(省一次决策、更可控);只有当拆法依赖具体输入时,才付 orchestrator 那层动态决策的开销。同一张图,语义判然不同——这正是 01 章"模式是对同一原子循环施加不同约束"的体现。
07.4对抗评审:用结构对抗共识偏误
专门设计会唱反调的 Agent 来制衡共识偏误;但对抗本身有失效模式——朴素 debate 会因附和把对的答案带偏成错的,且成本随 Agent×轮数二次方膨胀。
多个同质 Agent 自由讨论会趋同,趋同会放大共识偏误而非纠正它。对抗评审给系统装一个结构化的反方。最轻量的是 06 章 反思里见过的 evaluator-optimizer / generator-critic-refiner 回路——一个生成、一个 critic 指出具体问题、refiner 按反馈改,适合"有清晰评判标准 + 迭代精化有可测收益"的任务。重一点是 multi-agent debate:多个 LLM 实例多轮各陈推理再收敛。
底层机制(对抗有效,但对抗自己会反噬):multi-agent debate(Du 等,ICML 2024)实测把传记事实准确率从单 LLM 的 60% 提到 74%(异质自适应辩论可到 80.6%),显著降幻觉。但机制有两道反噬。其一成本:每个 Agent 要持完整辩论史作上下文,token 随 Agent×轮数二次方膨胀——8 Agent×4 轮涨 36–49×;而准确率在 2–3 轮、2–4 Agent 就 plateau,再加边际收益与算力效率双降。其二更危险(2025《Talk Isn't Always Cheap》):模型常因同伴推理从对的改成错的,宁可附和也不挑战错误论证,即便强模型在数量上压过弱模型仍会掉分。根因是 Agent 缺乏对抗"有说服力但错误论证"的激励与防御。所以 red-team / devil's-advocate 要显式给对抗 Agent"挑刺"的角色与激励,否则辩论退化成趋同——这与 06 章"自评无外部信号会更差"是同一个故障的群体版本。
| 方案 | 制衡机制 | 失效模式 / 选中 |
|---|---|---|
| 朴素 debate:多个同质 Agent 自由讨论自行收敛 | 多轮各陈己见 | sycophancy 趋同把对的答案带偏成错的;成本随 Agent×轮数二次方膨胀、2–3 轮即 plateau |
| generator-critic-refiner(evaluator-optimizer) | 一写一评迭代精化 | 需清晰评判标准;无外部信号时退化(同 06 章自评故障) |
| 显式角色化 critic / devil's-advocate / red-team | 给对抗 Agent 明确"挑刺"角色与激励 + 停机条件 | 选中——保住制衡价值;代价是要设计角色 prompt 与停机条件 |
一个团队相信"辩论越多越准",把 multi-agent debate 从 2 Agent×2 轮加到 8 Agent×4 轮。token 账单涨了几十倍,准确率却几乎没动,某些题目甚至更差。两件事各自的原因是什么?
展开答案(先停 10 秒再点)
两件事,两个机制。token 暴涨:debate 的成本是 Agent×轮数的二次方——每个 Agent 每轮都要把完整辩论史读进上下文,8 Agent×4 轮约涨 36–49×。准确率不动:debate 的收益在 2–3 轮、2–4 Agent 就 plateau,再加边际收益与算力效率双降,多花的算力大半是浪费。个别更差:朴素 debate 有 sycophancy 反噬——模型常因同伴推理从对的改成错的,宁可附和也不挑战错误论证,强模型在数量上占多数也救不回。结论:加 Agent 不必然更准,要给对抗显式"挑刺"角色并设停机条件,而不是堆轮数。
07.5交接链:handoff 与 swarm vs supervisor
handoff 让 Agent 间直接转移控制权而非经中心中转;LangGraph 的 Command 把"改 state"和"换节点"合并成一次原子返回——goto + update + graph=PARENT。
跨角色、跨阶段、跨上下文的交接有一个难点:既要更新共享 state(带什么消息过去),又要路由到下一个 Agent(跳到谁)。两件事若分两步做,中间任何一步失败就状态错位。这是 OpenAI 实践指南两大编排法里 manager(agents-as-tools)之外的另一条——decentralized handoff:对等 Agent 互相直接转交,谁都能转给谁。
底层机制(Command 把两件事合并成原子返回):LangGraph 的 create_handoff_tool 返回一个 Command 对象,单次返回里同时做三件事——goto=目标 Agent 节点 决定跳到哪、update={messages, active_agent, ...} 决定带什么 state 过去、graph=Command.PARENT 让子图节点能跳到父图的兄弟 Agent。swarm 在持久化 state 里记一个 active_agent,下一轮直接从该 Agent 续上,无需每次回中心。这与 03 章把状态外化到外部是同一招——控制权的"游标"写进 state,崩溃或换轮后照样续得上。network/swarm vs supervisor 的实测差异(LangChain 改造版 τ-bench,航空域 + 干扰项):单 Agent 在 2+ 干扰域时急剧掉分;swarm 全场最佳,因为子 Agent 直接答用户、避开了 supervisor 在子 Agent 与用户之间"传话(telephone game)"的翻译损耗。但 supervisor 不是没救:去掉 handoff 噪声消息、给 supervisor 一个 forward_message 工具原样透传子 Agent 回复、把工具命名从 transfer_to 调成 delegate_to,三招让它在该 benchmark 上性能涨近 50%。结论不是"swarm 永远赢",而是从成功定义与约束反推架构。
# L35:Command 把"改 state"和"换节点"合并成一次原子返回(LangGraph 风格)
def make_handoff(target):
@tool
def transfer_to(state):
return Command(
goto=target, # 跳到目标 Agent 节点
update={"active_agent": target, # swarm 记住谁在掌权
"messages": state["messages"]}, # 带什么 state 过去
graph=Command.PARENT) # 子图跳到父图的兄弟 Agent
return transfer_to
# swarm:对等 Agent 互相直接 handoff,下一轮从 active_agent 续上,不回中心
# supervisor 想补回差距:forward_message 原样透传,避开"传话"翻译损耗
def forward_message(state):
return state["last_subagent_reply"] # 不让中心 Agent 转述 → 该 benchmark 涨近 50%
| 方案 | 优势 | 为什么没选 / 选中 |
|---|---|---|
| 纯 supervisor:所有回复经中心 Agent 转述给用户 | 可控性强、易调试、路由集中 | "传话(telephone game)"翻译损耗掉分;裸用在 τ-bench 弱于 swarm |
| 单 Agent 扛多域 | 零协调成本 | 2+ 干扰域时急剧掉分——单窗口装不下多域 + 干扰项 |
| swarm / handoff:对等 Agent 直接答用户 | τ-bench 占优、少一次 LLM 调用更快、避开翻译损耗 | 选中(该 benchmark)——但更难调试、路由更不可控 |
| supervisor + forward_message 透传 + 去噪 + 改命名 | 补回近 50% 差距、保留可控性 | 早期部署常先上它——架构对错往往输给实现细节 |
# 把五课串起来的最小骨架:lead 编排 + 扇出 + 隔离回传 + 对抗评审 + handoff
def lead_agent(query):
# 07.1:先判断要不要上多 Agent —— 简单任务直接单 Agent 返回
if is_simple(query): # 简单查证:单 Agent 更省更快
return single_agent(query)
# 07.2 + 07.3:动态拆解 → 扇出给隔离的子 Agent(map)
subtasks = lead.decompose(query) # 子任务临场决定,非预定义
summaries = parallel_map( # fan-out:各子 Agent 独立 context window
lambda t: run_subagent(spec=t), # spec={目标, 输出格式, 工具, 边界}
subtasks) # 子 Agent 只回传 1–2k 压缩摘要,不回全轨迹
draft = lead.synthesize(summaries) # fan-in / reduce
# 07.4:对抗评审 —— 显式 devil's advocate,给它"挑刺"的角色
critique = critic_agent.attack(draft, role="找出最致命的反例与漏洞")
if critique.has_blocking_issues:
draft = lead.revise(draft, critique) # 限 1–2 轮,避免 plateau 与成本爆炸
citations = citation_agent(draft, summaries) # 单独跑:把每条声明绑回来源
return draft, citations
Cognition 的 single writer 原则:让多个 Agent 并行执行有副作用的写动作,会因隐含决策冲突产出不一致结果——它的实测例是一个 Agent 写 Flappy Bird、另一个写成 Super Mario,综合 Agent 被迫缝合两份误解。当下最稳的多 Agent 用法是:让额外 Agent 只做评审 / 分析 / 建议(对抗评审、debate),把 action 收敛到单线程。代价是放弃写操作的并行加速——但读多写少的研究型任务正好吃这套,写多紧耦合的编码任务不吃。
§本章 self-check
先合上教程,把你能想到的答案写在纸上或编辑器里。写完再点开答案对照——直接点开等于把这一节当再读一遍。
- 多 Agent 的 90.2% 增益里,token 用量单独解释多少性能方差?这个数字说明多 Agent 赢在哪里?
- orchestrator-worker 里子 Agent 必须收到的"任务说明书"包含哪四件事?回传给 lead 的该是什么、不该是什么?
- 扇出聚合与 orchestrator-worker 拓扑同构,唯一的区别是什么?sectioning 与 voting 各扇出什么?
- 朴素 multi-agent debate 的两道失效模式分别是什么(成本与准确率各一条)?怎么缓解?
- LangGraph 的
Command在一次返回里合并了哪两件事?swarm 为什么在 τ-bench 上打败 supervisor?
答案(先做完再展开)
- 80%(三因子合计 95%)。说明多 Agent 赢主要是"用算力换并行探索"——它烧了约 15× chat token 去铺开搜索面,不是分工本身让它更聪明。
- 四件事:目标、输出格式、工具/来源指引、清晰任务边界,缺一项子 Agent 就会重复劳动 / 留空白 / 漏信息。回传该是 1–2k 压缩摘要 + 重物件的 artifact 轻量引用;不该是完整探索轨迹(会抵消隔离、撑爆窗口)。
- 唯一区别:扇出的子任务可预定义,orchestrator 的子任务由 LLM 临场决定。sectioning 扇出独立子任务(提速 / 护栏);voting 扇出同一任务的多次复跑(取多样 / 共识)。
- 成本:token 随 Agent×轮数二次方膨胀(8×4 涨 36–49×),而准确率 2–3 轮即 plateau。准确率:sycophancy 趋同,模型宁可附和也不挑战错误论证,强模型占多数也救不回。缓解:给对抗 Agent 显式"挑刺"角色 + 激励 + 停机条件。
Command合并 goto(换到哪个 Agent 节点)+ update(带什么 state/messages 过去)(加 graph=PARENT 跳父图)。swarm 赢因为子 Agent 直接答用户、避开了 supervisor 在子 Agent 与用户间"传话"的翻译损耗,还少一次 LLM 调用。
给一个"读多写多"的混合任务选拓扑
07.1 说研究型(读多、支线独立)适合并行多 Agent,编码型(写多、紧耦合)适合单 Agent。现在给你一个夹在中间的任务:一个需要先并行调研多个第三方 API、再据此写一份会改动同一份配置文件的迁移脚本的工程。它前半段读多、后半段写多。设计一个拓扑,既吃到调研阶段的并行收益,又不让写阶段的并行打架。说清你在哪一阶段切换拓扑、控制权怎么交接、代价是什么。
提示(卡住再展开)
关键是按阶段切拓扑,不是全程一种。调研阶段用 07.2/07.3 的 fan-out:多个隔离子 Agent 并行查不同 API,各回传 1–2k 摘要给 lead;写阶段切到 Cognition 的 single writer——只留一个 Agent 持有写权,其余 Agent 降级成 07.4 的评审角色(review 脚本 diff、给建议),写动作收敛到单线程。两阶段之间用 07.5 的 handoff:lead 把综合后的调研结论 + 写权一起 Command(goto=writer, update={...}) 交给唯一的 writer。代价:放弃写阶段的并行加速,且要设计"调研完成"的交接判据。这正好把本章四种工艺串成一条:判据(07.1)→ 扇出(07.3)→ 评审(07.4)→ 交接(07.5)。