Agent Teams
s04 的子 Agent 是临时工——干完活就消失了。
s09 的队友是正式员工——有名字、有身份、有收件箱,干完活 standby,随时待命。
s04 的子 Agent 是一次性的——为什么不够?
回顾 s04:父 Agent 调 task(prompt="...") → 子 Agent 启动 → 干活 → 返回摘要 → 销毁。子 Agent 的整个 messages 上下文在函数返回后被丢弃。下一次再派子 Agent,又从零开始。
s04 子 Agent(临时工)
🔹 每次调用都是新的(messages=[])
🔹 没有名字,没有身份
🔹 做完一个任务就销毁
🔹 不能接收后续消息
🔹 不能跟其他 Agent 通信
s09 队友(正式员工)
🔹 持久存在,状态在 config.json 里
🔹 有名字("alice")、角色("coder")
🔹 做完任务变 idle,随时再派活
🔹 有收件箱,能接收别人发来的消息
🔹 能给其他队友发消息
真实场景:一个"临时工"搞不定的情况
Lead Agent 说:"Alice 你负责写前端组件,Bob 你负责写后端 API。Alice 写完组件后通知 Bob 接口格式。Bob 确认格式没问题后告诉 Alice。两个都完成后我来联调。"
这需要什么?① Alice 和 Bob 都持久存活(不能做完一件事就消失);② 他们之间能互相发消息(不是只能跟 Lead 通信);③ 他们有收件箱(能接收和读取别人发来的消息)。
s04 的子 Agent 一个都做不到。s09 的队友三个都能做到。
解决方案:有名字的 Agent + 文件邮箱
s09 的核心就两个东西:① 一个有名字、有身份、持久存活的Agent 线程;② 一个基于文件的消息邮箱。
总指挥
status: working
coder
status: idle
tester
status: working
文件结构:所有信息在 .team/ 目录下
config.json 长这样:
status 的变化:idle(空闲中,等任务)→ working(正在干活)→ idle(干完了,再等)→ ... 可以反复循环。和 s04 的"一次用完就丢"完全不同。
🔬 深度对比:什么时候用 Subagent,什么时候用 Teammate?
这是新手最常问的问题——"我已经有 s04 的子 Agent 了,为什么还需要 s09 的队友?"答案取决于任务的特性:
| 特征 | 用 Subagent (s04) | 用 Teammate (s09) |
| 任务独立性 | 完全独立,不需要中途通信 | 需要和其他Agent沟通协商 |
| 时间跨度 | 一次性,几分钟内完成 | 跨多轮对话,可能持续数小时 |
| 状态持久 | 不需要,做完就忘 | 需要记住自己的进度 |
| 可重用性 | 每次新任务都从空白开始 | 同一Agent做同类任务,积累经验 |
| 协作复杂度 | 单向:接收任务→返回结果 | 多向:A↔B, B↔C, Lead↔All |
简单判断法:问自己"这个 Agent 需要和别人说话吗?"如果不需要 → subagent。如果需要(问问题、确认格式、协商方案)→ teammate。
真实场景映射:"帮我搜一下这个项目用什么测试框架" → subagent(读 5 个文件,返回一个词"pytest")。"你负责写前端,Bob 写后端,写完你们互相确认接口格式" → teammate(需要双向通信)。
🏗️ Agent 团队的三种经典架构模式
s09 实现的是最简单的"Lead + Workers"模式。但在真实世界中,多 Agent 系统有三种主流架构:
模式一:Hierarchical(层级制)—— s09 采用
一个 Lead Agent 分配任务,多个 Worker Agent 执行。Lead 做决策,Worker 做执行。优点:简单、可控。缺点:Lead 是单点瓶颈。适用:任务边界清晰、Worker 之间不需要深层次协作。
模式二:Peer-to-Peer(对等制)
没有 Lead。所有 Agent 平等,自发协商分工。例如:Agent A 看到任务池里有"写前端",Agent B 看到"写后端",各自认领。完成后互相发消息确认接口对齐。优点:无单点瓶颈,适合大规模。缺点:需要更复杂的协商协议(s10-s11 会涉及)。
模式三:Blackboard(黑板制)
所有 Agent 共享一块"黑板"(s07 的 .tasks/ 目录就是黑板)。Agent 不看别人在哪,只看黑板上的任务和状态。谁空闲就 claim 一个 ready 任务。完成就标记+解锁下游。优点:Agent 之间完全解耦。缺点:不适合需要实时对话的场景。
s09 是模式一(Lead 分配)。s10-s11 会向模式二和三演进(peer-to-peer 协商 + 黑板任务池自动领取)。
案例:一个三人团队怎么协作?
Lead 接到任务"开发一个登录页面"——它派出 Alice(写前端)和 Bob(写后端),自己协调全局。
完整协作流程
① Lead 派队友:spawn_teammate("alice", "coder", "写登录页面的前端组件") → Alice 的线程启动。同样派 Bob 写后端 API。
② Alice 工作:Alice 在自己的 agent loop 里读写文件、执行命令,和单 Agent 一样。但多了两个工具:send_message(给别人发消息)和 read_inbox(看有没有人找我)。
③ Alice 遇到问题:前端写完,但不确定后端接口格式。Alice 调 send_message(to="bob", content="你的 API 返回什么字段?我需要知道")。
④ Bob 收到:Bob 在自己的 agent loop 里,下一轮调 LLM 前,read_inbox("bob") 返回了 Alice 的消息。Bob 看到后调 send_message(to="alice", content="字段是 {username, token, expires_at}")。
⑤ Alice 继续:收到 Bob 的回复,更新前端代码。
⑥ Lead 检查:Lead 在合适的时候检查各位的进度——看 config.json 里的 status,或直接发消息问。
TeammateManager:团队名册 + 线程管理
spawn():创建队友并在线程中启动 agent loop
关键设计:如果 Alice 已经在 working 状态,再次 spawn("alice", ...) 会报错——不能同时让一个人做两件事。但如果 Alice 是 idle(干完活了),再次 spawn 就可以——这相当于给空闲队友派新任务。和 s04 的"每次创建新子 Agent"不同,s09 的队友是可重用的。
MessageBus:地球上最简单的消息系统
MessageBus 可能是你见过的最极简的消息中间件——没有队列服务,没有 WebSocket,没有数据库。就是文件夹里的 .jsonl 文本文件。
send():往收件人文件末尾追加一行 JSON
追加模式("a"):文件不存在就创建。存在就追加到末尾。不读旧内容,不改旧内容。O(1) 的写操作。
read_inbox():读全部消息,读完就清空
"读完就清空"(drain-on-read):这个设计选择有两个含义——
✅ 好:Agent 不会重复处理同一条消息。每次读到的都是新消息。
❌ 代价:如果 Agent 读了但中途崩溃了,消息就丢了(不可恢复)。s10 会讨论更稳健的协议。
broadcast():群发消息
给团队中除自己外的所有人发一条相同消息。底层就是循环调用 send()——给每个人的 .jsonl 文件追加一行。
使用场景:Lead 说"大家都停下手头工作,看一下这个紧急 bug"——一条 broadcast 就够了。
🔬 为什么选择 JSONL 格式?
JSONL(JSON Lines)是 s09 邮箱系统的核心设计选择。每个消息是文件中的一行独立 JSON——不需要解析整个文件,不需要维护索引。理解为什么选它,就理解了简单系统设计的精髓:
对比其他方案:
❌ 一个大 JSON 数组:要读新消息得解析整个数组(越来越慢)。要写新消息得重写整个数组(对几百条消息来说很慢)。
❌ SQLite 数据库:功能强大但增加依赖。需要 schema、需要连接管理、多线程访问更容易出错。
✅ JSONL 文件:追加一行 = 一次文件写入(O(1))。读全部 = 逐行解析(和消息数量线性相关,但十几条消息只要几毫秒)。清空 = 写空字符串。零依赖,人类可读。
JSONL 的真实应用:Docker 的容器日志、nginx 的访问日志、机器学习的数据集——都用类似的行分隔格式。s09 的邮箱系统是这种成熟模式的最简实现。
📬 Agent 团队的四种通信模式
s09 的消息系统支持了四种不同的通信模式——从最简单的到最复杂的:
① 直接消息(Direct Message):A → B。一条 send_message,一个收件人。适用于:Alice 问 Bob 一个具体问题。
② 广播(Broadcast):A → 所有人。一条 broadcast,全体收到。适用于:Lead 宣布重要信息、紧急通知。
③ 发布-订阅(Pub-Sub):Agent 关注自己关心的消息。s09 没有显式的 topic 订阅,但你可以通过消息类型(message/broadcast/shutdown_request)来区分信息流——每个 Agent 只处理与自己相关的类型。
④ 请求-响应(Request-Response):A 发请求 → B 处理 → B 回复。s10 的协议系统就是这种模式的升级版。s09 的 message 类型可以做基础的请求-响应,但缺少 request_id 来关联一对消息。
四种模式递增了复杂度和能力。s09 实现了前三种,s10 实现了第四种的完整版(带 ID 关联和状态追踪)。
🔄 Teammate 的生命周期状态机
每个队友在 config.json 中的 status 字段不是一个简单的标签——它是一个状态机:
工作中
空闲中
又工作了
一个已经 idle 的队友可以被重新激活——Lead 再次 spawn 同一个名字,队友从 idle 变成 working,用新的 prompt 开始新一轮任务。这和 s04 的"每次新建子 Agent"完全不同——
s04:100 个任务 = 创建 100 个新子 Agent(每个从零开始,用完销毁)。
s09:100 个任务 = 3 个队友轮流工作(Alice 干完变 idle → 再派 Alice 干下一个 → 状态在 config.json 中累积)。
可重用的 Agent 节省了"冷启动"成本——不需要每次都重新初始化 messages 上下文、重新理解系统环境。而且可以在 config.json 中追踪每个 Agent 的"工作历史"(做了多少任务、每次什么状态)。
队友的 Agent Loop:带收件箱的 while 循环
每个队友的 agent loop 和 s01 的结构一样——while True → LLM 调用 → 工具分发 → 循环。但有两个不同:
不同一:每轮 LLM 调用前检查收件箱
在调用 LLM 之前,先 read_inbox(name)。如果有新消息,把它们作为 user 消息注入到 messages 里。和 s08 的 drain_notifications 完全一样的模式——被动接收,不是主动轮询。
不同二:跑完变 idle,不是销毁
队友的 loop 有 for _ in range(50) 的安全上限(防止无限循环),但没有 subagent 的"完成后被丢弃"。loop 结束后,status 被设为 idle——队友还在,config.json 里还有它的记录,收件箱还在。下次 Lead 再 spawn 同一个名字,队友可以重新开始。
s04: 函数调用
run_subagent(prompt) → return string → 函数结束,局部变量销毁。s09: 线程启动
thread.start() → 线程一直跑 → loop 结束 → status=idle → 线程对象还在,状态还在 config.json,收件箱还在。
Lead 的工具集 + s08 vs s09
Lead Agent 有 9 个工具
4 个基础工具(bash, read, write, edit)+ 5 个团队工具:
spawn_teammate(name, role, prompt):派出队友。
list_teammates():查看团队状态(谁在团队里、各自什么状态)。
send_message(to, content):给某个队友发消息。
read_inbox():看自己的收件箱(队友发来的消息)。
broadcast(content):给所有人(除自己)群发。
| 组件 | s08 | s09 |
|---|---|---|
| Agent数量 | 1 | 1 Lead + N 个 Teammate |
| 持久化 | 无 | config.json + JSONL inbox |
| 线程用途 | 后台跑 shell | 每个线程跑完整 agent loop |
| Agent通信 | 无 | send_message + broadcast |
| 生命周期 | 一次性 | idle ↔ working 可循环 |
| 新工具 | bg_run + bg_check | spawn + send + broadcast + read_inbox + list |
从 s09 带走的四个核心认识
持久身份 > 一次性
有名字、有状态、有收件箱的 Agent 比每次新建的子 Agent 能干得多。可重用性是团队协作的基础。
文件即通信
不需要消息队列、不需要 WebSocket。JSONL 文件的追加写 + 清空读就是一个完整的异步消息系统。
收件箱模式 = 被动接收
Agent 不轮询"有人找我吗",而是每轮被自动注入新消息。和 s08 的通知管道同一个哲学。
线程 = Agent 容器
s04 的 Agent 活在函数调用里(用完即弃)。s09 的 Agent 活在线程里(直到 shutdown)。线程给了 Agent 独立的生命周期。
落地案例:多 Agent 团队在真实系统中的应用
📋 Claude Code 的子 Agent 系统(你每次复杂任务都在触发)
Claude Code 在处理大型任务时会自动派发子 Agent(就是 s04 的 subagent 模式)。当你看到 Claude Code 显示 Task: "搜索代码库中的认证逻辑"——那就是一个子 Agent 在工作。
Claude Code 当前主要用 subagent 模式(s04),但在某些复杂场景下,多个子 Agent 会共享文件系统,通过 s07 的任务图状态隐式协调——这介于 s04 和 s09 之间。完全的 teammate 模式(s09 的 JSONL 邮箱)是 Claude Code 正在演进的方向。
🤖 CrewAI:工业级的多 Agent 团队框架
CrewAI 是 Python 生态中最流行的多 Agent 框架之一。它的核心概念和 s09 几乎一一对应:
CrewAI Agent = s09 的 Teammate(有 name + role + goal)
CrewAI Task = s07 的 Task(有 description + expected_output + dependencies)
CrewAI Crew = s09 的 Team(一组 Agent + 一组 Task + 执行策略)
你学完 s09 后去看 CrewAI 的文档,会发现它只不过是 s07+s09 的工业加强版——任务图 + Agent 团队 + 更丰富的通信协议。
🔬 Microsoft AutoGen:学术界的多 Agent 标杆
AutoGen 是微软研究院开源的多 Agent 框架。它的核心是 ConversableAgent——一个有收件箱、能收发消息、能调用工具的 Agent。和 s09 的 teammate 结构完全一致。
AutoGen 的 Agent 之间通过"对话"来协调——A 发消息给 B,B 决定是否回复、怎么回复、什么时候结束。这和 s09 的 send_message + read_inbox 模式是同构的。只不过 AutoGen 加入了更多协议(handoff、group chat、nested chat)。
学完 s09 再看 AutoGen = 你已经理解了它的核心数据流——Agent 在循环中读消息、调 LLM 决策、发消息给其他 Agent。框架做的是让这个流程更稳健、更可配置。
🏢 类比:从"一个人干活"到"一个团队干活"
s01-s08 = 单兵作战:一个 Agent 能干很多事,但总有上限。读代码、改代码、跑测试——全是一个人干。
s09 = 组队协作:Lead 管全局,Alice 写代码,Bob 做测试。互相通信,协同推进。
类比公司运营:Subagent(s04)= 外包临时工——给一个任务,干完交结果,不保留状态。Teammate(s09)= 全职同事——有自己的工位(收件箱)、有职位(role)、今天干完明天继续。
理解这个区别,你就理解了什么时候在 Agent 项目中用 subagent(一次性查询/探索),什么时候用 teammate(持续协作/需要通信)。
关停请求、计划审批——这些需要结构化协议来保证多 Agent 协作的安全性和一致性。
s09 打开了多 Agent 的大门,s10-s12 将让这个团队真正可治理。