---
title: 多 Agent 编排与结果合并
url: https://doc.liz6.com/ai/03-agent-systems/06-multi-agent-orchestration
locale: zh
area: ai
tags:
- 大模型与 Agent
- Agent 执行系统
date: 2026-06-30
modified: 2026-09-10
description: 先用单 Agent 建立可验证基线，再决定是否拆成多个独立推理循环。本文沿任务依赖计算并行上限，明确每个分支的输入、产物与提交权，并处理迟到结果和失败恢复。成功标准是完整任务的质量、时间和成本改善。
---

# 多 Agent 编排与结果合并

先用单 Agent 建立可验证基线，再决定是否拆成多个独立推理循环。本文沿任务依赖计算并行上限，明确每个分支的输入、产物与提交权，并处理迟到结果和失败恢复。成功标准是完整任务的质量、时间和成本改善。

## 从工作流到多 Agent

单 Agent 也能并行调用独立工具；因此“需要同时读多个文件”不一定需要多个推理循环。多 Agent 更适合需要各自较长分析、不同信息范围或独立工作过程的子任务。每个 Worker 形成自己的上下文后，向协调者返回压缩结果与证据定位，可以减少主上下文承载的原始材料。

多次模型调用也不自动等于多 Agent。固定抽取、校验和格式化流水线可以由普通工作流实现；动态分解任务并让各分支根据工具反馈独立推进，才更接近这里讨论的协作 Agent。[Building effective agents](https://www.anthropic.com/engineering/building-effective-agents)

| 组织方式 | 谁决定步骤 | 主要收益与代价 |
|---|---|---|
| 串接与路由 | 程序预设路径或分类规则 | 易复现，但面对未知分支需扩展流程 |
| 并行分片 | 预先划定独立范围 | 缩短可重叠工作，仍需归并 |
| 动态协调者与 Worker | 模型提出划分，调度器执行 | 适应未知任务，协调与验证更复杂 |
| 生成与评审循环 | 既定流程加模型反馈 | 改进候选，受评审质量与迭代上限约束 |

多 Agent 对话框架展示了角色、工具和交流模式的组合能力，但框架提供对话机制不等于自动提供任务正确性。[AutoGen 论文](https://arxiv.org/abs/2308.08155) 决定采用哪种结构时，应先找出单 Agent 当前的具体限制，再验证增加协作是否改善了它。

## 先画依赖，再计算收益

假设任务由准备 A、实现 B、独立兼容性检查 C 和汇总 D 组成。B、C 都需要 A 的接口约定；D 必须拿到两者结果。若 B 与 C 确实能独立推进，下面的并行成立：

<svg viewBox="0 0 760 360" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="并行由依赖决定：准备、独立分支、汇总验证" style="max-width:100%;height:auto" font-family="Source Han Sans CN,Microsoft YaHei,sans-serif">
<defs><marker id="agent-dependencies-arrow" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#64748b"></path></marker></defs>
<rect width="760" height="360" rx="12" fill="#f8fafc"></rect>


<g transform="translate(0 0)"><rect x="25" y="130" width="145" height="75" rx="8" fill="#e0e7ff" stroke="#c7d2fe"></rect><text x="97.5" y="164.5" font-size="15" fill="#1e293b" text-anchor="middle" font-weight="600">准备 A：2 分钟</text><text x="97.5" y="186.5" font-size="12" fill="#475569" text-anchor="middle" font-weight="400">冻结目标与接口</text><rect x="270" y="65" width="205" height="75" rx="8" fill="#e0e7ff" stroke="#c7d2fe"></rect><text x="372.5" y="99.5" font-size="15" fill="#1e293b" text-anchor="middle" font-weight="600">分支 B：4 分钟</text><text x="372.5" y="121.5" font-size="12" fill="#475569" text-anchor="middle" font-weight="400">迁移实现</text><line x1="170" y1="167" x2="265" y2="102" stroke="#64748b" stroke-width="1.8" marker-end="url(#agent-dependencies-arrow)"></line><line x1="475" y1="102" x2="560" y2="167" stroke="#64748b" stroke-width="1.8" marker-end="url(#agent-dependencies-arrow)"></line><rect x="270" y="205" width="205" height="75" rx="8" fill="#e0e7ff" stroke="#c7d2fe"></rect><text x="372.5" y="239.5" font-size="15" fill="#1e293b" text-anchor="middle" font-weight="600">分支 C：6 分钟</text><text x="372.5" y="261.5" font-size="12" fill="#475569" text-anchor="middle" font-weight="400">独立兼容性检查</text><line x1="170" y1="167" x2="265" y2="242" stroke="#64748b" stroke-width="1.8" marker-end="url(#agent-dependencies-arrow)"></line><line x1="475" y1="242" x2="560" y2="167" stroke="#64748b" stroke-width="1.8" marker-end="url(#agent-dependencies-arrow)"></line><rect x="565" y="130" width="170" height="75" rx="8" fill="#e0e7ff" stroke="#c7d2fe"></rect><text x="650.0" y="164.5" font-size="15" fill="#1e293b" text-anchor="middle" font-weight="600">汇总 D：3 分钟</text><text x="650.0" y="186.5" font-size="12" fill="#475569" text-anchor="middle" font-weight="400">核对并集成</text></g><text x="24" y="29" font-size="19" fill="#0f172a" text-anchor="start" font-weight="700"><tspan x="24" dy="0">并行由依赖决定：准备、独立分支、汇总验证</tspan></text><text x="24" y="313" font-size="13" fill="#475569" text-anchor="start" font-weight="400"><tspan x="24" dy="0">理想总时长 2 + max(4, 6) + 3 = 11 分钟；还未包含委派、排队与返工。</tspan></text>
</svg>

串行时间是 2+4+6+3=15 分钟；理想并行时间是 2+max(4,6)+3=11 分钟，节约 4 分钟。若委派、排队和合并冲突额外耗费 5 分钟，总时间反而是 16 分钟。启动了两个 Worker，并不等于任务快了一倍。

如果 C 检查的是 B 尚未产出的补丁，C 就依赖 B，这个图需要改成串行；也可以先让 C 独立整理检查标准，等补丁完成后再验证。**改变任务定义可以创造一部分并行空间，但不能用模型猜测消除真实数据依赖。**

```python
duration = {"A": 2, "B": 4, "C": 6, "D": 3}
deps = {"A": [], "B": ["A"], "C": ["A"], "D": ["B", "C"]}
finish = {}
# 本例字典按依赖的拓扑顺序列出，不是通用调度器。
for node, minutes in duration.items():
    finish[node] = max((finish[x] for x in deps[node]), default=0) + minutes
assert finish["D"] == 11
assert sum(duration.values()) == 15
print("理想并行分钟:", finish["D"])
print("另加 5 分钟协调开销:", finish["D"] + 5)
```

成本也要加总主 Agent、所有 Worker、重复读取、工具调用和失败尝试。便宜模型承担合适子任务可能节省费用，但多个独立窗口也会重复加载约束和材料；前缀缓存能否命中取决于服务、模型和输入。不能保证“另开子 Agent 必然比主循环切模型便宜”。

实际多 Agent 研究系统的工程报告同时讨论了上下文隔离、独立研究与较高 token 消耗，也指出紧密依赖任务的协调限制。该系统的收益应作为具体案例理解，而非所有任务的加速倍数。[Anthropic 多 Agent 研究系统](https://www.anthropic.com/engineering/multi-agent-research-system)

### 增加并行，为什么没有按人数提速？

先画出依赖，再谈并行收益。图中每条任务条的起点由前置任务决定，合并也占时间。注意默认总工时是 15，最长路径却是 9；这两个量分别回答资源消耗与完成延迟。

$$
T_{\mathrm{parallel}}=\max_{p\in\mathrm{paths}}\sum_{i\in p}t_i+T_{\mathrm{coordination}}
$$

**增加并行，为什么没有按人数提速？**

并行时间由最长依赖路径和协调开销决定；任务总工时除以人数通常不是实际完成时间。


## 委派是交付一个任务契约

“你负责检查兼容性”过于模糊：检查哪个版本、哪些接口、是否允许修改、需要什么证据都没有定义。协调者应把 Worker 完成任务所需的信息交付完整，同时避免倾倒全部主会话历史。

| 契约项目 | 示例 |
|---|---|
| 目标 | 检查迁移方案是否破坏已有导入格式 |
| 输入与版本 | schema-v3、样例集 R12、方案 draft-4 |
| 范围 | 只分析格式兼容，不修改实现 |
| 可用能力与权限 | 读取样例、运行本地验证；不发布产物 |
| 输出 | 兼容矩阵、失败样例、证据位置、未覆盖项 |
| 停止条件 | 完成矩阵或达到已分配预算，明确剩余缺口 |
| 合并接口 | 结果写到任务专属目录并回传标识 |

<svg viewBox="0 0 760 340" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="子任务结果需要证据与版本，协调者负责接受或退回" style="max-width:100%;height:auto" font-family="Source Han Sans CN,Microsoft YaHei,sans-serif">
<defs><marker id="agent-result-contract-arrow" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#64748b"></path></marker></defs>
<rect width="760" height="340" rx="12" fill="#f8fafc"></rect>


<g transform="translate(0 0)"><rect x="25" y="95" width="185" height="100" rx="8" fill="#e0e7ff" stroke="#c7d2fe"></rect><text x="117.5" y="142.0" font-size="15" fill="#1e293b" text-anchor="middle" font-weight="600">任务契约</text><text x="117.5" y="164.0" font-size="12" fill="#475569" text-anchor="middle" font-weight="400">目标、输入、权限、输出</text><rect x="275" y="95" width="210" height="100" rx="8" fill="#e0e7ff" stroke="#c7d2fe"></rect><text x="380.0" y="142.0" font-size="15" fill="#1e293b" text-anchor="middle" font-weight="600">Worker 产物</text><text x="380.0" y="164.0" font-size="12" fill="#475569" text-anchor="middle" font-weight="400">结论、差异、证据、未完成项</text><rect x="550" y="95" width="185" height="100" rx="8" fill="#e0e7ff" stroke="#c7d2fe"></rect><text x="642.5" y="142.0" font-size="15" fill="#1e293b" text-anchor="middle" font-weight="600">协调者验收</text><text x="642.5" y="164.0" font-size="12" fill="#475569" text-anchor="middle" font-weight="400">版本、覆盖、冲突、验证</text><line x1="210" y1="145" x2="270" y2="145" stroke="#64748b" stroke-width="1.8" marker-end="url(#agent-result-contract-arrow)"></line><line x1="485" y1="145" x2="545" y2="145" stroke="#64748b" stroke-width="1.8" marker-end="url(#agent-result-contract-arrow)"></line><line x1="640" y1="201" x2="640" y2="263" stroke="#64748b" stroke-width="1.8" marker-end="url(#agent-result-contract-arrow)"></line><line x1="640" y1="263" x2="380" y2="263" stroke="#64748b" stroke-width="1.8" marker-end="url(#agent-result-contract-arrow)"></line><line x1="380" y1="263" x2="380" y2="201" stroke="#64748b" stroke-width="1.8" marker-end="url(#agent-result-contract-arrow)"></line><text x="380" y="306" font-size="14" fill="#334155" text-anchor="middle" font-weight="400">退回时提供具体缺口；收到结果不等于已经接受结果</text></g><text x="24" y="29" font-size="19" fill="#0f172a" text-anchor="start" font-weight="700"><tspan x="24" dy="0">子任务结果需要证据与版本，协调者负责接受或退回</tspan></text>
</svg>

工具、历史、文件系统是否共享依运行环境而定。即使共享目录，Worker 也未必已经读过文件；即使不共享历史，也可以通过明确输入恢复必要背景。委派消息应说明实际可访问的资源，而不是假定对方“知道前面聊过什么”。

如果主任务要求“先只改中文”，这个约束必须传给所有可能修改文档的 Worker。主 Agent 的授权也不是任意扩张工具权限的理由：只读检查任务应获得它需要的能力，越出范围的发现交回协调者决定。

## 产物所有权与结果验收

### 给写入划定边界

共享工作区中，两个 Agent 同时修改同一文件可能覆盖内容；分配不同文件也不一定独立，因为它们可能共同改变某个接口约定。可选择按目录或产物分工、使用独立分支或工作副本，再由一个明确的集成者合并。

隔离的副本减少直接覆盖，却不能避免语义冲突。例如 B 把字段改名为 `item_id`，C 的测试仍认为字段叫 `sku`；即使补丁文本能自动合并，集成后也会失败。契约中固定接口版本，变更时先传播给依赖方，可以减少这种无效工作。

### 摘要用于定位，证据用于确认

Worker 返回“检查通过”不够。结果应包含针对的输入版本、采用的方法、可查看产物和未覆盖项。协调者先检查目标覆盖，再核验版本与证据，最后决定接受、补充还是重新划分。

| 返回情况 | 协调者动作 |
|---|---|
| 所有结论有对应样例与检查结果 | 接受并纳入整体证据 |
| 结论正确但只覆盖部分格式 | 标记部分完成，分配明确缺口 |
| 两个 Worker 结论冲突 | 回到原始条件与版本，不直接多数表决 |
| 引用文件存在但已被后续修改 | 核对哈希或提交，重新验证相关结论 |
| 只有流畅摘要，没有可核验产物 | 视任务风险要求补证据 |

独立评审有助于发现遗漏，但另一个同模型 Agent 也可能共享同样偏差。“作者与评审分离”提供角色和上下文差异，不等于统计独立或证明正确。把明确标准、独立测试、实际运行与必要的人类评审结合，才有可解释的验证边界。

### worker 成功，为什么仍不能合并？

结果归档可以保存所有尝试，正式产物合并却只能接受满足当前合同的结果。把“worker 已结束”“结果已收到”“结果已验收并合并”拆成不同状态，避免一个 success 字段承担三种含义。

**worker 成功，为什么仍不能合并？**

成功状态不等于当前有效结果；合并门必须检查任务身份、当前尝试、输入版本与验收证据。


## 编排也需要恢复语义

协调者应为每个子任务保存任务 ID、尝试编号、输入版本、状态和产物位置。状态至少区分 queued、running、completed、accepted、failed、cancelled：Worker 已完成，只代表结果产生；accepted 才表示协调者已确认可用于整体交付。

假设尝试 1 超时，协调者启动尝试 2；稍后尝试 1 的旧结果到达。若只按子任务名接受，会让旧内容覆盖新内容。需要按尝试编号与输入版本核验迟到结果，必要时把它留作参考而不自动发布。

取消也不保证旧 Worker 立刻停止写入。共享资源场景要控制提交权限，例如由集成者核验当前有效尝试或版本后才写入权威产物；否则界面显示 cancelled 的 Worker 仍可能在后台覆盖文件。跨执行者的状态规则与 [记忆与状态](/ai/03-agent-systems/04-memory-and-recovery.md) 中的条件更新相呼应。

| 故障 | 恢复时先确认 |
|---|---|
| Worker 失联 | 有没有已完成产物，是否仍可能执行 |
| 协调者重启 | 哪些任务已接受，哪些结果未知 |
| 子任务重复启动 | 两个尝试是否会写同一资源 |
| 合并过程中失败 | 哪部分已落盘，能否恢复或回退 |
| 外部副作用响应丢失 | 业务操作实际是否完成，不能只看线程状态 |

## 怎样判断多 Agent 确实有收益

用同一任务集比较单 Agent、单 Agent 并行工具和多 Agent，尽量保持工具权限、输入证据与验收标准一致。除了任务成功率和总延迟，还记录主 Agent 协调时间、重复工作比例、冲突数、失败重试与全部成本。

如果 Worker 很快而主 Agent 长时间反复澄清和合并，瓶颈是任务划分或结果契约；如果两个 Worker 总查相同材料，范围可能重叠；如果总是合并后失败，应检查共享接口与集成测试。如果单 Agent 的批量工具已达到相同效果，就没有必要为了角色数量增加维护成本。

更详细的指标和逐任务追踪在 [评估与可观测](/ai/04-evaluation-and-production/01-evaluation-and-observability.md) 展开。评估的单位应是用户的完整任务，不能只统计启动了多少 Agent 或产生了多少条消息。

继续阅读：[评估、试次与可观测](/ai/04-evaluation-and-production/01-evaluation-and-observability)。
