Code Agent 解剖(18):AgentTeams——TeamFanout 与 TeamCollect 的并行机制

上一篇的基础

上一篇讲了消息 ACK 三态:消息从 pendingdeliveredprocessed,每个状态都有明确的触发时机,协调者随时可以查询。

现在我们往上走一层,看任务是怎么被批量分发出去(TeamFanout),结果又是怎么被汇总回来的(TeamCollect)。

这两个操作合在一起,就是 AgentTeams 的核心能力:把一个大任务拆成多个小任务,并行执行,再把结果拼回来


结论先说

工具 职责 关键设计
TeamFanout 把任务分发给多个成员 agent 每个成员拿到独立的上下文片段,互不干扰
TeamCollect 等待所有成员完成,汇总结果 支持超时、部分结果、冲突检测

两者配合的核心思想:分而治之(divide and conquer)------拆分时上下文隔离,汇总时冲突显式处理


一、TeamFanout:分发不是复制

最直觉的多 agent 分发方式:把整个任务描述复制一份,发给每个成员,让它们各自做。

这个方式有一个根本问题:每个成员的上下文里都有完整信息,但它们实际上只需要处理其中的一部分。

比如有 50 个文件需要重构,你发给 5 个 agent 的消息里都包含了全部 50 个文件的路径和内容------每个 agent 的上下文窗口都被撑得很满,而且每个 agent 做决策时都要在 50 个文件里搜索,浪费大量 token。

TeamFanout 的设计不是这样的。

ini 复制代码
协调者调用 TeamFanout:
  tasks = [
    {"member": "agent_1", "scope": ["file_1.py", ..., "file_10.py"], "instruction": "重构为 async"},
    {"member": "agent_2", "scope": ["file_11.py", ..., "file_20.py"], "instruction": "重构为 async"},
    ...
  ]

每个成员 agent 只收到属于自己的那一份任务,包含:

  • 自己负责的文件列表(scope)
  • 这批文件的处理指令(instruction)
  • 必要的上下文(比如共享的接口定义)

成员 agent 启动后,只看到这些信息,不知道也不需要知道其他成员在做什么。

这就是上下文隔离:每个 agent 的认知边界被人为划定,专注在自己的子任务上。


二、成员 agent 怎么"真正并行"运行

上一篇提到了三种执行模式:in-processtmuxauto

要真正理解并行,需要了解这三种模式的本质区别。

in-process 模式

arduino 复制代码
主进程
  ├── 主 agent loop (thread A)
  ├── 成员 agent 1 loop (thread B)
  ├── 成员 agent 2 loop (thread C)
  └── 成员 agent 3 loop (thread D)

所有 agent 都在同一个 Python 进程里,用不同线程运行。

优点 :启动快,内存共享,通信开销小。

缺点:受 Python GIL(全局解释器锁)限制,CPU 密集型操作不能真正并行。但因为 LLM 调用是 IO 密集型操作(大部分时间在等网络返回),GIL 的影响没有想象中大------等待期间 GIL 会释放,其他线程可以运行。

tmux 模式

复制代码
主进程          tmux session
  │                │
  │          ┌─────┴─────┐
  │      成员1终端  成员2终端  成员3终端
  │          │           │
  │      独立进程      独立进程
  │                │
  └────── 通过消息队列通信 ──────┘

每个成员 agent 是一个独立的操作系统进程,运行在独立的 tmux 窗格里。

优点 :真正的操作系统级并行,互不干扰,一个成员崩溃不影响其他成员。

缺点:启动一个 tmux 进程需要几百毫秒,如果任务很多,启动开销会很显著。

auto 模式

框架根据当前环境自动选择:有 tmux 就用 tmux,否则用 in-process。


三、TeamFanout 的分发过程

现在把 TeamFanout 的完整执行过程走一遍:

css 复制代码
协调者调用 TeamFanout(tasks=[task1, task2, task3])
    │
    ▼
1. 为每个 task 生成一条消息,写入消息队列
   (task1 → message_id_1, task2 → message_id_2, task3 → message_id_3)
   所有消息初始状态:pending
    │
    ▼
2. 根据执行模式启动成员 agent
   (in-process: 创建新线程; tmux: fork新进程)
    │
    ▼
3. 每个成员 agent 启动后:
   a. 检查自己的"收件箱",取到 pending 消息
   b. 消息状态变为 delivered
   c. 开始执行任务
    │
    ▼
4. TeamFanout 立刻返回(不等成员完成!)
   返回: {message_ids: [message_id_1, message_id_2, message_id_3]}
    │
    ▼
协调者拿到 message_ids,可以继续做其他事情
(比如自己处理第一批,或者准备合并逻辑)

这里有个关键点:TeamFanout 是非阻塞的。它发完任务就返回,协调者不需要在这里等待。

这和我们通常理解的"函数调用"不同------调用函数,等结果,函数返回。TeamFanout 是"调用函数,函数立刻返回,结果以后再取"。


四、TeamCollect:把结果拼回来

成员 agent 各自完成任务后,协调者需要收集结果。这就是 TeamCollect 的职责。

python 复制代码
results = TeamCollect(
    message_ids=[message_id_1, message_id_2, message_id_3],
    timeout=300,          # 最多等待5分钟
    require_all=False,    # 是否要求所有成员都完成
)

TeamCollect 会:

  1. 等待 :持续查询消息状态,直到所有指定消息变为 processed,或者超时
  2. 收集:把每条消息对应的处理结果取出来
  3. 返回:把所有结果打包返回给协调者

返回的结果大概是这样的结构:

json 复制代码
{
  "completed": [
    {"message_id": "id_1", "member": "agent_1", "result": "file_1.py 已重构", "files_modified": ["file_1.py"]},
    {"message_id": "id_2", "member": "agent_2", "result": "file_11.py 已重构", "files_modified": ["file_11.py"]},
  ],
  "failed": [
    {"message_id": "id_3", "member": "agent_3", "error": "超时", "status": "delivered"}
  ],
  "pending": []
}

注意 require_all=False 这个参数:允许部分完成就返回。这很重要------如果一个成员崩溃了,你不希望整个任务一直卡在那里等,而是先拿到已完成的部分,把失败的部分单独处理。


五、结果有冲突怎么办

多个成员 agent 并行工作,最棘手的问题就是冲突:两个成员都修改了同一个文件,谁的算数?

AgentTeams 对这个问题的处理是:冲突检测,但不自动解决

TeamCollect 在汇总结果时,会检查各成员修改的文件列表,如果发现重叠,会在返回结果里标记出来:

json 复制代码
{
  "conflicts": [
    {
      "file": "config.py",
      "modified_by": ["agent_1", "agent_3"],
      "message": "该文件被多个成员修改,需要人工或协调者介入合并"
    }
  ]
}

然后由协调者(或者人类)来决定怎么解决。

这个设计选择很务实:自动合并两个 LLM 的代码修改,几乎不可能做得对。与其搞一个很复杂的自动合并算法,不如把冲突明确标出来,让有判断力的一方来处理。


六、一个完整的流程示例

把 16-18 篇的内容串起来,一个完整的 AgentTeams 协作流程是这样的:

ini 复制代码
1. 主 agent 分析任务,决定怎么切分
   ↓
2. 调用 TeamCreate,创建一个团队
   返回: team_id = "team_abc"
   ↓
3. 准备任务列表,每个成员一份独立的 scope
   tasks = [
     {member: "agent_1", scope: ["file_1..10.py"]},
     {member: "agent_2", scope: ["file_11..20.py"]},
     ...
   ]
   ↓
4. 调用 TeamFanout,把任务分发出去(非阻塞,立刻返回)
   返回: message_ids = ["msg_1", "msg_2", ...]
   ↓
5. 主 agent 继续做自己的事(比如写框架代码、准备测试)
   同时,成员 agent 并行工作...
   ↓
6. 主 agent 自己的事做完了,调用 TeamCollect 等待成员结果
   results = TeamCollect(message_ids, timeout=300)
   ↓
7. 检查结果:哪些成功了,哪些失败了,有没有冲突
   ↓
8. 处理失败和冲突,合并所有结果
   ↓
9. 调用 TeamDelete,清理团队,释放资源

这个流程里,步骤 5 是关键------主 agent 在等待成员的同时没有闲着,而是在并行处理其他任务。这才是多 agent 系统的真正价值。


设计亮点

1. 上下文裁剪到成员粒度

每个成员只收到自己需要的信息。这不只是节省 token,更重要的是让成员 agent 的决策更聚焦------它看到的上下文越干净,做出来的结果越准确。

2. 非阻塞的 Fanout

TeamFanout 立刻返回,允许协调者在等待期间继续工作。这是多 agent 系统效率提升的核心:协调者和成员是真正并行的,而不是协调者等着看成员干活。

3. 显式冲突而不是自动合并

把冲突标记出来,交给有判断力的一方处理。这在工程上比自动合并更稳健------你永远不知道两个 LLM 对同一个文件的修改在语义上是否兼容。

4. 部分结果也可用(require_all=False)

允许在部分成员失败的情况下仍然返回已完成的结果。这让系统在面对单个成员故障时,不是全部重来,而是保留已完成的工作,只重做失败的部分。


小结

设计选择 方案 工程价值
任务分发 TeamFanout 非阻塞,每成员独立 scope 协调者和成员真正并行,上下文隔离
并行执行 in-process / tmux 二选一 平衡启动开销与真实并行度
结果收集 TeamCollect 等待 + 超时保护 可容忍部分失败,不死等
冲突处理 检测但不自动解决 比自动合并更稳健,把判断交给更有能力的一方

下一篇是这个系列的最后一篇,也是最有意思的一篇:AgentTeams 最终为什么被移出了稳定版本?它的失败教训告诉了我们什么?


关于本系列的源码

本系列所有分析均基于开源项目 MyCodeAgent

AgentTeams 的实现已从稳定版本移除,具体设计记录见 docs/archives/legacy-harness/HARNESS_ROADMAP.md Phase 7 章节,移除计划见 docs/plans/2026-07-12-lean-runtime/tasks/M2-03-remove-agent-teams.md

bash 复制代码
git clone https://github.com/chendongqi/MyCodeAgent
cd MyCodeAgent
cp .env.example .env
uv sync
uv run python main.py

欢迎访问 PrimeSkills ------ 一个精心策划的 AI Agent 与技能市场,所有内容均经过真实企业级工作流验证。没有噱头,只有真正有效的东西。

更多实用知识和有趣产品,欢迎访问我的个人主页

相关推荐
冬奇Lab14 分钟前
一天一个开源项目(第206篇):T3 Code - AI 编程 Agent 的统一控制台
人工智能·开源·资讯
IT古董15 分钟前
AI 资讯日报 | 2026年9月1日 :混元 Hy4 开源、DeepSeek 多模态登顶、可灵获国家队 14 亿注资
人工智能·开源
ai小陈21 分钟前
FramePack图生视频云端部署实战:从单图输入到视频输出的完整流程
服务器·人工智能·安全·ai·音视频·gpu算力
程序员-Benothing35 分钟前
OpenAI断供Cursor:当AI巨头开始“清理门户“,开源生态的中立性还能撑多久?
人工智能·开源·大模型
光锥智能39 分钟前
机器人走进大众时代加速到来:郎朗跨界合作启元机器人,消费级人形机器人开启直播发售
人工智能
Jialu.43 分钟前
中文 BERT 多任务分类项目:从模型结构到训练细节
人工智能·pytorch·分类·微软·nlp·bert
ZhouDevin43 分钟前
算法论文/数据集3——CLD(TMLR2025)压缩训练集,仅保留对验证集有益的样本
人工智能·深度学习·算法·计算机视觉
长沙京卓1 小时前
Copilot Coding Agent 变了:AI 编程正在从插件变成项目成员
人工智能·ai
AIGC大时代1 小时前
知网 AIGC 检测在罚什么:均匀句长、低指代、零口癖,并不等于「用过 ChatGPT」
人工智能·chatgpt·nlp·aigc·论文·知网·学术规范