# 3. Multi-Agent:通信、协作、任务分发与 SuperAgent 路由
# 3.1 原理
Multi-Agent 的难点不是“并行调用多个模型”,而是任务图、状态所有权和结果一致性。核心组件包括:
- Agent Registry:记录 agent id、父子关系、角色、能力、状态、所在 Runtime。
- Task Graph:任务依赖、所有者、优先级、输入、验收条件、重试策略。
- Message Bus/Mailbox:点对点消息、广播、结果通知、ack、去重、超时。
- Scheduler/Router:根据能力、负载、上下文成本和依赖选择执行者。
- Join/Aggregator:等待部分或全部结果,做冲突检测、排序、合并和最终验收。
所谓 SuperAgent 更适合理解为根协调角色,而不是拥有无限能力的 Agent。它负责拆解、路由、等待、合并和终止;业务执行下沉给工作 Agent。为了避免单点上下文膨胀,SuperAgent 只保留任务摘要、状态和证据索引,不复制所有子 Agent 全量历史。
# 3.2 Claude Code 源码
runAgent创建独立agentId、记录父 id、准备上下文与工具,并支持工作树隔离和持续消息回调:runAgent.ts:248、runAgent.ts:347。- Fork 子 Agent 会继承父对话,但过滤不完整工具调用;为 Prompt Cache 共享构造字节一致的前缀,并使用占位 ToolResult 保持 API 配对不变量:
forkSubagent.ts:91、forkSubagent.ts:96。 - 恢复 Agent 时读取 transcript/metadata、过滤未解决 ToolUse、重建替换状态并恢复 worktree:
resumeAgent.ts:42、resumeAgent.ts:64。
# 3.3 Codex 源码
AgentControl在 spawn 前检查全局执行容量和最大线程数,并继承环境/执行策略:spawn.rs:382。- 创建子 Thread 后持久化父子边、发送初始输入或
InterAgentCommunication,再启动完成监听:spawn.rs:452、spawn.rs:538。 - 通信事件明确区分
Spawn/Message/Followup/Result,并记录 sender、receiver、communication id:agent_communication.rs:6、agent_communication.rs:44。
源码没有名为 SuperAgentRouter 的单体类。对应能力由根 Agent 的模型决策、AgentControl、父子 Thread 图、Mailbox 和完成监听共同实现。这是“架构推导”,面试时要如实表述。
# 3.4 调度伪代码
function route(task, agentRegistry): // 为一个可运行任务选择最合适且有权限的 Agent
candidates = agents.filter(a => // 从注册表中过滤不满足硬约束的执行者
a.status == IDLE && // 只选择当前有容量、未执行其他任务的 Agent
a.capabilities covers task.requiredCapabilities && // Agent 能力集合必须覆盖任务所需能力
a.permissionProfile permits task.scope) // Agent 的权限上限必须允许访问任务资源
score(a) = skillMatch(a, task) // 能力和历史专长匹配越高,基础得分越高
- contextTransferCost(a, task) // 传输大量上下文会增加 Token、延迟和泄漏风险
- currentLoad(a) // 当前负载越高,排队与超时风险越大
- historicalFailureRate(a, task.type) // 同类任务历史失败率用于降低不可靠 Agent 得分
return argmax(candidates, score) // 返回综合得分最高的候选 Agent
async function superAgentExecute(goal): // 定义根协调 Agent 执行复杂目标的流程
graph = planner.decompose(goal) // 将目标分解为带依赖和验收条件的任务 DAG
while graph.hasRunnableNodes: // 只要仍有依赖已满足的节点就继续调度
for node in graph.runnableNodes: // 遍历当前所有可并行执行的任务节点
agent = route(node, registry) // 根据能力、权限、成本和负载选择执行者
mailbox.send(agent, assignment(node)) // 通过可追踪 Mailbox 发送结构化任务分配
events = await mailbox.waitAnyResult() // 等待任一 Agent 的进度、结果或失败事件
graph.apply(events) // 幂等地更新节点状态、证据和后继节点可运行性
if conflict(events): // 检测多个结果之间的文件、事实或结论冲突
createVerificationTask(events) // 创建独立验证任务,而不是任意选择一个结果
return aggregator.mergeAndVerify(graph.results) // 汇总所有结果并通过最终验收器后返回
# 3.5 面试题
问:子 Agent 之间共享内存还是消息通信?
优先使用消息通信,并用执行产物(Artifact)传递大结果;共享文件系统只作为受控的数据通道。直接共享可变内存会造成竞态、难回放和权限越界。消息需要 id、sender/receiver、父任务、版本、确认状态和去重键。
问:如何解决多个 Agent 修改同一文件?
按文件或模块分区,使用独立 Worktree 或补丁产物(Patch Artifact);合并前检查基线哈希,冲突交给专门的集成 Agent 或根 Agent;禁止“最后写入者获胜”。
# 3.6 原理深化:Multi-Agent 是四个一致性域的组合
Claude Code 的 AgentTool 先解析 Agent Definition,再由 runAgent() 计算模型、工具池、权限模式和同步/异步执行方式;它不会简单复制父 Agent 全部上下文与权限。allowedTools、Agent 自带 mode、父 Session mode 和后台执行规则共同决定子 Agent 的有效能力:runAgent.ts:412、runAgent.ts:436、runAgent.ts:465。
消息和任务是两种协议:Mailbox 传递指令、结果和审批通知;Task Store 保存 owner/status/blocks/blockedBy 并通过锁或原子更新认领。消息已发送不代表任务已转移,任务 owner 改变也不代表上下文已完整交接。Claude Code 在 owner 更新时额外发送分配消息,正是为了同步这两个平面:TaskUpdateTool.ts:276、TaskUpdateTool.ts:300。
Codex 的 agent/control 管生命周期与层级,agent_communication 把消息工具路由到目标线程。父 Agent 应持有调度责任,但不能直接篡改子线程内部 Step;跨线程只交换结构化消息、任务状态和 Artifact 引用,以保持可恢复边界。
并行写代码还要单独走 Worktree 链:创建独立目录、持久化 worktree state、执行、验证、汇总 Diff、由集成者合并。Worktree 不改变 Task owner,也不授予额外权限。面试时把 Spawn、Message、Task、Workspace 四条链分别画出,通常能避免把 Multi-Agent 误讲成“开多个线程”。
四条链之所以必须分开,是因为它们的成功条件不同:Spawn 成功只表示执行实体存在,Message 成功只表示消息可达,Task 转移成功只表示责任归属变化,Worktree 创建成功只表示文件视图隔离。真正的端到端完成需要 Join/Aggregator 同时验证任务终态、结果证据、工作区 Diff 和子 Agent 生命周期;否则可能出现 Agent 已退出但任务仍 running,或任务已完成但补丁从未进入集成分支。