s15: Agent Teams — 一个搞不定,组队来
s01 → ... → s13 → s14 → s15 → s16 → s17 → s18 → s19 → s20
"一个搞不定, 组队来" — 文件收件箱 + 队友线程。
Harness 层: 团队 — 多 Agent 协作, 消息总线。
问题
"重构整个后端"涉及认证模块、数据库层、API 路由、测试。一个 Agent 在修 API 路由时,认证模块的细节已经不在上下文里了。上下文窗口就那么大,单个 Agent 的注意力覆盖不了所有模块。
s06 的子 Agent 是临时工,叫来干一件事就走了。但有些任务需要能通信、能协作的队友。
解决方案
)
教学代码沿用 S14 的能力(prompt 组装、任务系统、后台执行、cron 调度)。为了聚焦团队机制,省略了完整错误恢复、记忆和技能系统。新增三样:MessageBus(文件收件箱)、spawn_teammate_thread(启动队友线程)、inbox 注入(Lead 接收队友消息并注入 history)。
子 Agent vs 队友:
工作原理
)
MessageBus: 文件收件箱
每个 Agent(包括 Lead 和队友)有一个 .jsonl 邮箱。发消息 = 往对方的文件里 append 一行 JSON。读消息 = 读文件 + 删除(消费式):
为什么用文件而不是内存队列?教学版选文件是因为直观、跨线程可观察。真实 CC 也用文件收件箱(~/.claude/teams/{team}/inboxes/),但加了 proper-lockfile 防并发写冲突。教学版的 read_inbox 有 read + unlink 竞态,多线程同时读可能丢消息,对教学场景可以接受。
spawn_teammate_thread: 启动队友
Lead 调用 spawn_teammate 工具启动一个队友。队友跑在自己的 daemon 线程里,有自己的 system prompt、自己的 messages、自己的简化工具集:
关键设计:
- 队友有简化工具集:bash、read、write、send_message。教学版省略了任务和 cron,聚焦通信机制。真实 CC 的队友也有 TaskCreate、TaskUpdate 等工具,任务系统是团队共享的
- 教学版限 10 轮:防止队友无限循环。真实 CC 用 idle loop:跑完一轮后发
idle_notification,等 inbox 消息,收到后继续,直到shutdown_request才退出 - 完成后自动汇报:
BUS.send(name, "lead", summary)把最终结果发到 Lead 的收件箱
Lead 的 inbox 注入
Lead 在每轮主循环结束后检查收件箱。队友发来的消息注入到 history 里,让 LLM 能看到并做出反应:
教学版在用户输入循环外注入。CC 更精细,Lead 的 useInboxPoller 每 1 秒检查一次,有消息就提交为新的 turn,不需要等用户输入。
权限冒泡
教学版省略了权限冒泡。真实 CC 的流程(permissionSync.ts、useSwarmPermissionPoller.ts):
- 队友遇到需要审批的操作 → 发
permission_request到 Lead 收件箱 - Lead 的
useInboxPoller检测到请求 → 路由到审批队列 - 用户审批后 → Lead 发
permission_response回队友 - 队友的
useSwarmPermissionPoller(每 500ms 轮询)收到回复 → 继续或拒绝
合起来跑
两个队友并行工作。
相对 s14 的变更
试一下
试试这些 prompt:
Spawn alice as a backend developer. Ask her to create a file called schema.sql with a users table.Check your inbox for alice's result.Spawn bob as a tester. Ask him to check if schema.sql exists and list its contents.
观察重点:Lead 如何启动队友?.mailboxes/ 目录下的 JSONL 文件长什么样?队友完成后 Lead 的 inbox 有没有注入到 history?
接下来
队友能干活、能通信。但如果 Lead 想让 Alice 关机,直接杀线程会留下写到一半的文件。需要一个体面的关机协议:Lead 发 shutdown_request,队友收尾后退出。
s16 Team Protocols → 关机握手与消息约定。
深入 CC 源码
以下基于 CC 源码
spawnMultiAgent.ts、useInboxPoller.ts(969 行)、useSwarmPermissionPoller.ts(330 行)、teammateMailbox.ts、teamHelpers.ts的完整分析。
一、没有中央消息总线,是文件系统
教学版用 MessageBus 类收发消息。CC 的做法更直接,每个 Agent 直接写其他 Agent 的收件箱文件。
收件箱路径:~/.claude/teams/{teamName}/inboxes/{agentName}.json
写入时用 proper-lockfile 文件锁保证并发安全(最多重试 10 次)。每个文件是一个 JSON 数组,append 新消息时读→追加→写回。
二、15 种消息类型
CC 的团队通信有 15 种结构化消息(teammateMailbox.ts):
文本消息被包装在 <teammate-message> XML 标签中交付给模型。
三、权限冒泡:双向轮询
教学版省略了权限冒泡。CC 的实际流程(permissionSync.ts):
- 队友遇到需要审批的操作 → 发
permission_request到 Lead 的收件箱 - Lead 的
useInboxPoller(每 1 秒轮询)检测到请求 → 路由到ToolUseConfirmQueue - Lead 的 UI 显示审批对话框,带队友名字和颜色
- 用户审批后 → Lead 发
permission_response回队友的收件箱 - 队友的
useSwarmPermissionPoller(每 500ms 轮询)收到回复 → 继续或拒绝执行
四、队友生命周期
CC 的队友由 spawnTeammate()(spawnMultiAgent.ts)创建:
- Spawn:创建 tmux 窗格(或进程内),分配颜色,写入 team config
- Work:
useInboxPoller每 1 秒检查收件箱 → 有消息就提交为新的 turn - Idle:Stop hook 触发 → 发
idle_notification给 Lead - Shutdown:Lead 发
shutdown_request→ 队友回复shutdown_approved→ Lead 清理
五、Team Config
团队注册表在 ~/.claude/teams/{teamName}/config.json(teamHelpers.ts):
队友之间不能嵌套(AgentTool.tsx:273 明确禁止 "teammates spawning other teammates")。
