Skip to content

多 Agent 协调

单 Agent 的问题是串行。Plan → Act → Observe 一次只走一步,如果任务可以拆开来同时推进,单 Agent 就是瓶颈。

多 Agent 系统的思路很直接:让多个 Agent 分工,把可以并行的部分真的并行起来。

本章目标

  • 理解多 Agent 系统比单 Agent 多了什么,代价是什么
  • 掌握 Coordinator + Worker 这一核心架构模式
  • 知道任务什么时候适合并行、什么时候必须串行
  • 能说出多 Agent 系统最容易失控的地方

从单 Agent 到多 Agent

假设你要重构一个大型代码库:

  • 先要读懂现有代码结构(探索)
  • 再制定重构方案(规划)
  • 然后在多个文件上做修改(实现)
  • 最后验证改动是否正确(验证)

这四个阶段在单 Agent 下只能依次走,总耗时是所有步骤之和。但「探索不同模块」这件事完全可以并行——三个 Agent 同时读三个模块,探索速度是原来的三倍。

这就是多 Agent 的核心价值:把可以并行的工作真的并行起来

Coordinator + Worker 架构

最主流的多 Agent 模式是两层结构:

用户 → Coordinator Agent
              ↓         ↓         ↓
         Worker A   Worker B   Worker C
              ↓         ↓         ↓
         结果 A     结果 B     结果 C

         Coordinator 汇总 → 用户

Coordinator(协调者)

  • 接收用户的完整目标
  • 拆分任务,判断哪些子任务可以并行
  • 派发给 Worker,监听结果
  • 汇总结果,决策下一步
  • 和用户沟通进展

Worker(执行者)

  • 接收一个具体的、自包含的子任务
  • 独立执行,不依赖其他 Worker 的实时状态
  • 完成后向 Coordinator 汇报

Coordinator 的核心职责不是派活,而是读懂 Worker 的结果,再决策下一步

并行与串行的边界

多 Agent 的关键设计决策:哪些任务可以并行,哪些必须串行?

可以并行的情况(读操作、独立子任务)

  • 同时探索代码库的不同模块
  • 同时搜索多个主题的资料
  • 同时对不同文件做只读分析

必须串行的情况(有依赖关系、写操作)

  • 实现依赖探索的结果——必须先探索完才能实现
  • 多个 Worker 写同一批文件——会产生冲突
  • 验证依赖实现完成——不能提前跑

乱用并行的后果:Worker 拿到脏数据,结果互相覆盖,Coordinator 无法汇总。并行是效率工具,不是默认选项

上下文隔离问题

多 Agent 系统的一个关键工程挑战是:每个 Worker 的上下文是隔离的

Worker 只知道 Coordinator 给它的那段 prompt,看不到用户的完整对话历史,也看不到其他 Worker 正在做什么或已经做了什么。

这要求 Coordinator 在派发任务时必须做到:

  • 自包含:每个 Worker 的 prompt 里包含它完成任务所需的全部信息
  • 不依赖共享上下文:不能写"根据刚才讨论的方案去实现"——Worker 没看过那段讨论
  • 明确的完成标准:让 Worker 知道什么算「做完了」

一个反例:「根据你的发现去修复这个 bug」——这种 prompt 没有给 Worker 具体的文件路径、错误信息和修改方向,Worker 只能盲猜,结果大概率跑偏。

Worker 重试时的幂等性

多 Agent 系统里,Worker 失败后重试很常见。问题是:如果 Worker 已经执行了一半,Coordinator 只看到"失败",下一次重试可能会把副作用再执行一遍。

举个具体场景:一个 Worker 负责"给 100 个用户发送通知邮件"。它执行到第 60 个时网络断了,Coordinator 收到失败状态后重新派发任务。如果 Worker 没有幂等设计,前 60 个用户可能会收到第二封邮件。

工程上不要把"重试"简单理解成重新调用一次模型。只要 Worker 会写文件、发请求、改数据库、发消息,就要先设计幂等边界。常见做法有几种:

  • 给每个子任务生成稳定的 task_id,所有外部写入都带上这个 id
  • 对有副作用的操作记录执行状态,例如 pending / running / completed / failed
  • 写入前检查同一个 task_id 是否已经完成,完成过就直接返回已有结果
  • 把 Worker 输出拆成"计划"和"执行"两步,先由 Coordinator 审查计划,再允许执行副作用

一个简化版的状态记录可以长这样:

python
from dataclasses import dataclass


@dataclass
class TaskRecord:
    task_id: str
    status: str
    result: str | None = None


class TaskStore:
    def __init__(self):
        self.records: dict[str, TaskRecord] = {}

    def start_once(self, task_id: str) -> bool:
        record = self.records.get(task_id)
        if record and record.status == "completed":
            return False
        self.records[task_id] = TaskRecord(task_id=task_id, status="running")
        return True

    def complete(self, task_id: str, result: str) -> None:
        self.records[task_id] = TaskRecord(
            task_id=task_id,
            status="completed",
            result=result,
        )

这段代码不适合直接上生产,生产里要换成数据库事务或队列系统的去重能力。它想说明的是一个原则:Coordinator 不能只记"派出去过",还要记"这个副作用是否已经成功发生过"。

子 Agent 的权限边界

多个 Worker 共用一批工具时,真正危险的不是 Worker "不听话",而是系统把它不该拥有的能力给了它。

比如一个 Worker 只负责读取公开文档,却拿到了数据库写入工具;另一个 Worker 只负责总结搜索结果,却能读取其他用户的会话状态。你可以在 prompt 里写"不要访问无关数据",但更可靠的做法是:它根本拿不到那个工具。

权限边界通常可以从三层做:

  • 工具列表隔离:只把当前任务需要的工具交给 Worker
  • 参数范围限制:即使能调用工具,也只能访问允许的路径、集合或用户空间
  • 结果返回过滤:Worker 结果回到 Coordinator 前,先过滤掉密钥、内部日志和不该暴露的中间状态

如果把 Worker 当成"带工具的函数调用",权限设计会清楚很多。函数只接收必要参数,只返回约定结果,不应该随手拿到全局状态。

会话隔离

还有一个容易晚发现的问题:不同用户的 Coordinator 实例之间不能共享临时状态。

假设你把 Worker 中间结果存在一个全局字典里,key 只用 task_id。两个用户同时发起任务时,只要 task_id 生成规则不够稳,A 用户的 Worker 结果就可能被 B 用户的 Coordinator 读到。这个 bug 不一定马上暴露,但一旦发生就是数据隔离事故。

最小可用的做法是把所有运行态 key 都带上 session_iduser_id

python
def state_key(session_id: str, task_id: str) -> str:
    return f"{session_id}:{task_id}"

更稳的做法是让 Coordinator、Worker、工具调用日志都显式携带同一个 session_id,日志查询、状态读取、结果汇总都只能在这个会话范围内发生。多 Agent 系统一旦接入真实用户,隔离问题就不再是架构洁癖,而是安全底线。

从 Claude Code 源码看真实的多 Agent 实现

Claude Code v2.1.88 内置了一套完整的多 Agent 架构,是观察这套模式工程落地的好案例。

Coordinator 的职责边界

Claude Code 在 Coordinator 模式(coordinator/coordinatorMode.ts)下运行时,系统提示词明确规定了它的角色:

"你是协调者(coordinator)。你的工作是:帮用户实现目标、指导 Worker 研究和实现代码、汇总结果并与用户沟通。能直接回答的问题直接回答——不要把自己能处理的工作委派出去。"

Coordinator 不是只负责调度的机器,它本身有判断能力,简单的事情自己处理,不要无脑地把所有事情都转包出去。

专用 Worker 的设计

Claude Code 内置了几类专门化的 Worker,每类有固定的权限边界:

Explore Agent(探索专员)

  • 专门负责搜索和读取代码库
  • 严格只读:系统提示词里有 === CRITICAL: READ-ONLY MODE ===,列出了所有禁止操作——不能创建文件、不能修改文件、不能删除文件,不能用重定向符写文件
  • 工具层面也做了限制:FileEditToolFileWriteTool 从可用工具列表中移除
  • 目的:让 Coordinator 可以放心地并行派发多个探索任务,不用担心探索 Agent 误改代码

Verification Agent(验证专员)

  • 专门验证实现结果是否正确
  • 设计原则:用全新视角审查,不带实现过程的先入为主
  • 和实现 Worker 隔离上下文,就是为了让验证独立有效

工具权限是任务边界的工程化表达。探索不该改文件,就从工具层面禁掉写操作,而不是只靠 prompt 里写"请不要修改文件"。

Worker 结果的传递方式

Coordinator 和 Worker 之间的通信通过结构化消息进行。Worker 完成后,结果以 <task-notification> XML 格式传回给 Coordinator,包含任务 ID、状态(completed / failed / killed)、摘要和具体结果。

这个设计让 Coordinator 可以:

  • 同时跟踪多个 Worker 的状态
  • 区分「任务完成」和「任务失败」
  • 根据 task_id 决定是继续已有 Worker 还是启动新 Worker

Coordinator 可以「续接」已完成 Worker(保留之前的上下文),也可以新建 Worker(从空白上下文开始)。选哪种取决于新任务和上一个任务的上下文重叠度:重叠高就续接,重叠低就新建。

并行是刻意设计的

Claude Code 的 Coordinator 系统提示词里有一句话很直白:

"并行是你的超能力。Worker 是异步的。只要有机会,就并行启动独立的 Worker,不要把可以同时做的事情串行化。"

这是架构决策。Agent 系统的速度瓶颈通常在等待(等模型响应、等工具执行),能并行就并行,等待时间重叠,总时长才能压缩。

多 Agent 系统的失控点

多 Agent 比单 Agent 更难控制,主要在三个地方:

1. Coordinator 的任务分解质量

Coordinator 拆出来的子任务如果粒度不对——太粗了 Worker 不知道怎么做,太细了 Worker 花大量时间做无用功——整个系统效率就会崩塌。拆任务是多 Agent 系统中技术要求最高的环节。

2. Worker 之间的隐性依赖

并行运行的 Worker 如果存在依赖(Worker A 的结果是 Worker B 的输入),但 Coordinator 没有感知到,就会出现数据竞争或结果不一致。单次测试通常不会暴露,任务复杂了才会炸。

3. 成本和轮次的指数级增长

每个 Worker 都在独立消耗 Token。Coordinator 无节制地并行派发,成本比单 Agent 快速翻倍。多 Agent 系统必须有更严格的预算和轮次控制,不能沿用单 Agent 的阈值。

什么任务适合多 Agent

适合

  • 任务可以被清晰拆解成独立子任务
  • 子任务之间真正可以并行(不存在实时依赖)
  • 单 Agent 串行完成会太慢(耗时是主要问题)
  • 有明确的汇总点(所有结果最终需要整合)

不适合

  • 任务本身就是线性的、无法拆分
  • 子任务之间依赖紧密、必须串行
  • 任务规模小(Coordinator 的调度开销比任务本身还大)
  • 上下文需要完全共享(各 Worker 需要看到彼此的实时决策)

先用单 Agent 做。确认单 Agent 真的是速度瓶颈之后,再引入多 Agent。很多开发者把本该写死步骤的流程硬上多 Agent,反而更复杂、更难调试。

和其他章节的关系

  • Agent 基础原理:多 Agent 建立在单 Agent 循环的基础上,Coordinator 和 Worker 本质上都是在跑各自的 Agent Loop。先把单 Agent 的状态管理和终止机制理解清楚,再看多 Agent 的调度才不会迷失。
  • Tool Calling:Worker 的权限边界通过工具列表来控制,理解工具权限系统有助于设计专用化 Worker。
  • AI 应用系统设计:多 Agent 在完整系统里怎么落地,涉及任务调度、状态持久化、日志追踪,这些在系统设计章节有进一步展开。

常见面试考点

多 Agent 的问题经常考得很工程化:不是“多个 Agent 更强”,而是多个执行单元并行以后,系统怎么不乱。

  1. 子 Agent 边界:Worker 的输入、权限、可写范围和输出格式都要明确,不能让它靠共享上下文猜任务。
  2. Coordinator 角色:Coordinator 不只是派活,还要判断是否值得拆分、跟踪 Worker 状态、汇总结果并决定下一步。
  3. 并行与串行判断:读操作和互不依赖的子任务适合并行;共享写文件、有前后依赖或需要统一决策的任务必须串行。
  4. 幂等性设计:Worker 重试时要避免重复副作用,常见手段包括稳定 task_id、执行状态记录和写入前去重。
  5. 会话隔离:多用户或多任务并行时,状态 key、日志和 Worker 结果必须带 session_id 或用户边界,避免串数据。
  6. 成本控制:多 Agent 会放大 token、工具调用和等待成本,不能无节制地把小任务拆给多个 Worker。

下一章:持久化记忆系统——多 Agent 解决任务怎么分工,记忆系统解决跨轮次、跨会话的信息怎么留下来。

面向开发者的 AI 实战路线——Vibe Coding 与 AI 应用开发