并行协作:任务分发与结果汇合
并行协作把可以独立执行的子任务同时交给多个 Agent,再按约定条件收集结果,形成一次交付。分发阶段称为 fan-out,汇合阶段称为 fan-in。它既可以由主管 Agent 发起,也可以由固定工作流调度。
例如,比较 A、B、C 三款手机时,各款资料查询可以分别进行;比较结论则需要等相关资料返回。并行减少的是这些独立查询之间的等待,查询完成后的验收、口径统一和汇总仍然需要执行。
先确定哪些工作真的独立
判断两项任务能否并行,要看启动时是否已经具备各自需要的输入,以及执行过程中是否会争用同一份可变产物。
共同输入:型号、地区、配置、资料要求
┌→ Agent A:查询 A ─┐
分发任务 ├→ Agent B:查询 B ─┼→ 验收并汇合 → 比较与回答
└→ Agent C:查询 C ─┘这三个查询不依赖其他款的结果,可以同时开始。若另一个任务要“根据三款资料找出续航最好的产品”,它必须等待前面的结果,并检查测试条件是否可比。提前启动比较 Agent,只会让它反复等待或依据不完整信息生成结论。
任务目标独立,也不一定允许共享写入。让三个查询 Agent 同时修改 comparison.md,可能产生覆盖。这里让每个 Agent 返回自己的资料,汇合后由一个步骤生成对比表;其他文件协作方式见多 Agent 的文件与产物协作。
如果只是向三个查询接口各发一次请求,再交给同一个 Agent 读取,属于工具并发。多 Agent 并行中的各执行者有自己的任务上下文,并能在任务范围内继续决定行动:B 的商品页没有售后信息,可以转查保修页面,而 A 已经完成。固定接口调用并不需要这一层自主循环。
任务数与并发数分别控制
准备了十个子任务,不意味着十个必须同时启动。执行程序通常维护待执行队列和运行集合,空出名额后再启动下一项。
假设有 A、B、C 三项任务,并发上限为 2:
| 事件 | 正在执行 | 等待执行 | 已接收结果 |
|---|---|---|---|
| 开始分发 | A、B | C | 无 |
| B 先完成 | A、C | 无 | B |
| C 完成 | A | 无 | B、C |
| A 完成 | 无 | 无 | A、B、C |
B 完成后立即释放名额,C 可以开始,无须等 A。三个任务的启动顺序、完成顺序和最后展示顺序是三件不同的事。
并发上限要考虑模型请求限额、工具服务容量和内存占用。一个子 Agent 内部也可能同时发出多项工具请求,因此限制“活跃 Agent 数”并不能限制全部外部请求;模型服务和搜索服务还需要各自的限流规则。
在所有任务同时启动、没有资源争用的理想情况下,查询阶段耗时接近最慢子任务的耗时;如果只能分批执行,还要加上队列等待。整体耗时仍包含分派、验收与汇总。并行通常也不会减少总 token,多个 Agent 会分别读取任务背景并生成结果。
按任务接收结果,不按完成顺序拼答案
每个子任务需要稳定的 task_id,在同一次父任务中唯一。结果返回时,汇合器先找到对应的父任务和子任务,再检查是否属于当前执行、格式是否符合要求、产物是否可接受。
{
"task_id": "research-B",
"plan_version": 1,
"attempt": 1,
"status": "completed",
"artifact_ref": "results/research-B/attempt-1.json",
"unresolved": ["未找到指定地区的保修条款"]
}这里的 completed 表示子 Agent 本轮执行完成。汇合器仍要读取产物并检查交付要求,不能仅凭这个字段把 B 的所有信息视为已确认。
结果通常存进以任务 ID 为键的记录:
计划顺序:research-A、research-B、research-C
到达顺序:research-B、research-C、research-A
已验收结果:
research-A → A 的资料
research-B → B 的资料与缺失项
research-C → C 的资料
交给汇总步骤:按计划顺序读取 A、B、C重复事件不应变成两份独立成果。同一个 task_id 的结果只占一个汇合位置;plan_version 与 attempt 用来判断它是否属于当前有效的任务版本和执行尝试。例如,第 1 次查询超时后已被标记为过期,第 2 次查询正在执行,第 1 次迟到的结果不能仅因先到达就覆盖当前任务。
接受哪个尝试,需要由任务记录中的状态决定。汇合器完成校验后原子地记录本次接收,同一尝试重复送达时返回已有处理结果。这样既能去重,也不会把两次执行的部分字段拼成一份来源不清的资料。
不同任务之间还可能返回相同来源。那是内容层的去重:可以合并重复引用,但要保留它分别支持哪些结论。同一网页被三个 Agent 找到,不等于三份独立证据。
汇合条件决定什么时候继续
最常见的汇合条件是等待所有必需任务通过验收。但并非所有工作都需要等待全部结果,选择条件时要从交付要求出发。
| 汇合条件 | 可以用于什么任务 | 必须保留的限制 |
|---|---|---|
| 等待全部必需结果 | 完整比较 A、B、C;组合多个必要字段 | 任一必要结果缺失时,不能声称比较完整 |
| 截止时间内收集结果 | 允许先返回阶段性调研结果 | 明确哪些任务已完成、哪些仍缺失 |
| 达到指定覆盖条件 | 从多个候选中收集足够的不同类别资料 | 判断内容覆盖,不能只数返回条数 |
| 取得首个通过校验的结果 | 多条路径查找同一份可核验资料 | 成功条件必须明确,先返回不等于正确 |
手机比较属于第一种。A、C 已完成而 B 超时,主管可以继续重试 B,也可以在总截止时间到达后返回部分结果,但要说明 B 缺少哪些信息。不能把“两份返回值”当成已经覆盖三款产品。
“取得首个结果”适合多条等价查询路径都可能找到同一份官方说明。若几个 Agent 正在寻找不同风险、检查不同模块,首个完成并不满足任务覆盖要求。同样,“三个 Agent 中两个同意”也不能替代事实核验;方案评议和投票的适用边界见审查、辩论与结果裁决。
汇合后的生成步骤可以整理措辞、比较资料,但关键完成条件最好在输入生成模型前检查。否则,模型可能把缺失项写成流畅的结论,掩盖上游任务没有完成的事实。
提前汇合后,还要处理剩下的任务
达到覆盖条件或总截止时间后,执行程序要停止派发尚未启动的任务,并按策略请求取消仍在运行的任务。只从最终答案中忽略它们,后台模型与工具调用可能仍在继续产生费用。
取消通常需要合作式处理:子 Agent 在下一次模型或工具调用前检查取消状态;已经发送出去的远程请求未必能够立即中断。执行程序应区分“已请求取消”和“执行已停止”,并为暂时无法停止的任务保留追踪记录。
汇合结果也要确定接收边界。一次回答已经基于 A、C 的资料生成,B 后来返回时,可以保存它供后续更新,但不能悄悄修改已交付结果的状态。若产品支持更新回答,应显式开启新一轮合并,并记录采用了哪些新增资料。
父任务与子任务之间的取消传播、迟到结果和恢复过程,详见子任务生命周期与失败恢复。
参考:Anthropic:Building effective agents,Parallelization;LangGraph:Workflows and agents,Parallelization。