Agent Teams
Multi-Agent PlatformPersistent Specialist Teammates|350 LOC|10 tools
Teammates persist beyond one prompt, have identity, and coordinate through durable channels.
s00 > s01 > s02 > s03 > s04 > s05 > s06 > s07 > s08 > s09 > s10 > s11 > s12 > s13 > s14 > [ s15 ] > s16 > s17 > s18 > s19
子 agent 适合一次性委派;团队系统解决的是“有人长期在线、能继续接活、能互相协作”。
这一章要解决什么问题
s04 的 subagent 已经能帮主 agent 拆小任务。
但 subagent 有一个很明显的边界:
创建 -> 执行 -> 返回摘要 -> 消失
这很适合一次性的小委派。
可如果你想做这些事,就不够用了:
- 让一个测试 agent 长期待命
- 让两个 agent 长期分工
- 让某个 agent 未来收到新任务后继续工作
也就是说,系统现在缺的不是“再开一个模型调用”,而是:
一批有身份、能长期存在、能反复协作的队友。
建议联读
- 如果你还在把 teammate 和
s04的 subagent 混成一类,先回entity-map.md。 - 如果你准备继续读
s16-s18,建议把team-task-lane-model.md放在手边,它会把 teammate、protocol request、task、runtime slot、worktree lane 这五层一起拆开。 - 如果你开始怀疑“长期队友”和“活着的执行槽位”到底是什么关系,配合看
s13a-runtime-task-model.md。
先把几个词讲明白
什么是队友
这里的 teammate 指的是:
一个拥有名字、角色、消息入口和生命周期的持久 agent。
什么是名册
名册就是团队成员列表。
它回答的是:
- 现在队伍里有谁
- 每个人是什么角色
- 每个人现在是空闲、工作中还是已关闭
什么是邮箱
邮箱就是每个队友的收件箱。
别人把消息发给它,
它在自己的下一轮工作前先去收消息。
最小心智模型
这一章最简单的理解方式,是把每个队友都想成:
一个有自己循环、自己收件箱、自己上下文的人。
lead
|
+-- spawn alice (coder)
+-- spawn bob (tester)
|
+-- send message --> alice inbox
+-- send message --> bob inbox
alice
|
+-- 自己的 messages
+-- 自己的 inbox
+-- 自己的 agent loop
bob
|
+-- 自己的 messages
+-- 自己的 inbox
+-- 自己的 agent loop
和 s04 的最大区别是:
subagent 是一次性执行单元,teammate 是长期存在的协作成员。
关键数据结构
1. TeamMember
member = {
"name": "alice",
"role": "coder",
"status": "working",
}
教学版先只保留这 3 个字段就够了:
name:名字role:角色status:状态
2. TeamConfig
config = {
"team_name": "default",
"members": [member1, member2],
}
它通常可以放在:
.team/config.json
这份名册让系统重启以后,仍然知道:
- 团队里曾经有谁
- 每个人当前是什么角色
3. MessageEnvelope
message = {
"type": "message",
"from": "lead",
"content": "Please review auth module.",
"timestamp": 1710000000.0,
}
envelope 这个词本来是“信封”的意思。
程序里用它表示:
把消息正文和元信息一起包起来的一条记录。
最小实现
第一步:先有一份队伍名册
class TeammateManager:
def __init__(self, team_dir: Path):
self.team_dir = team_dir
self.config_path = team_dir / "config.json"
self.config = self._load_config()
名册是本章的起点。
没有名册,就没有真正的“团队实体”。
第二步:spawn 一个持久队友
def spawn(self, name: str, role: str, prompt: str):
member = {"name": name, "role": role, "status": "working"}
self.config["members"].append(member)
self._save_config()
thread = threading.Thread(
target=self._teammate_loop,
args=(name, role, prompt),
daemon=True,
)
thread.start()
这里的关键不在于线程本身,而在于:
队友一旦被创建,就不只是一次性工具调用,而是一个有持续生命周期的成员。
第三步:给每个队友一个邮箱
教学版最简单的做法可以直接用 JSONL 文件:
.team/inbox/alice.jsonl
.team/inbox/bob.jsonl
发消息时追加一行:
def send(self, sender: str, to: str, content: str):
with open(f"{to}.jsonl", "a") as f:
f.write(json.dumps({
"type": "message",
"from": sender,
"content": content,
"timestamp": time.time(),
}) + "\n")
收消息时:
- 读出全部
- 解析为消息列表
- 清空收件箱
第四步:队友每轮先看邮箱,再继续工作
def teammate_loop(name: str, role: str, prompt: str):
messages = [{"role": "user", "content": prompt}]
while True:
inbox = bus.read_inbox(name)
for item in inbox:
messages.append({"role": "user", "content": json.dumps(item)})
response = client.messages.create(...)
...
这一步一定要讲透。
因为它说明:
队友不是靠“被重新创建”来获得新任务,而是靠“下一轮先检查邮箱”来接收新工作。
如何接到前面章节的系统里
这章最容易出现的误解是:
好像系统突然“多了几个人”,但不知道这些人到底接在之前哪一层。
更准确的接法应该是:
用户目标 / lead 判断需要长期分工
->
spawn teammate
->
写入 .team/config.json
->
通过 inbox 分派消息、摘要、任务线索
->
teammate 先 drain inbox
->
进入自己的 agent loop 和工具调用
->
把结果回送给 lead,或继续等待下一轮工作
这里要特别看清三件事:
s12-s14已经给了你任务板、后台执行、时间触发这些“工作层”。s15现在补的是“长期执行者”,也就是谁长期在线、谁能反复接活。- 本章还没有进入“自己找活”或“自动认领”。
也就是说,s15 的默认工作方式仍然是:
- 由 lead 手动创建队友
- 由 lead 通过邮箱分派事情
- 队友在自己的循环里持续处理
真正的自治认领,要到 s17 才展开。
Teammate、Subagent、Runtime Task 到底怎么区分
这是这一组章节里最容易混的点。
可以直接记这张表:
| 机制 | 更像什么 | 生命周期 | 关键边界 | |---|---|---| | subagent | 一次性外包助手 | 干完就结束 | 重点是“隔离一小段探索性上下文” | | runtime task | 正在运行的后台执行槽位 | 任务跑完或取消就结束 | 重点是“慢任务稍后回来”,不是长期身份 | | teammate | 长期在线队友 | 可以反复接任务 | 重点是“有名字、有邮箱、有独立循环” |
再换成更口语的话说:
- subagent 适合“帮我查一下再回来汇报”
- runtime task 适合“这件事你后台慢慢跑,结果稍后通知我”
- teammate 适合“你以后长期负责测试方向”
这一章的教学边界
本章先只把 3 件事讲稳:
- 名册
- 邮箱
- 独立循环
这已经足够把“长期队友”这个实体立起来。
但它还没有展开后面两层能力:
第一层:结构化协议
也就是:
- 哪些消息只是普通交流
- 哪些消息是带
request_id的结构化请求
这部分放到下一章 s16。
第二层:自治认领
也就是:
- 队友空闲时能不能自己找活
- 能不能自己恢复工作
这部分放到 s17。
初学者最容易犯的错
1. 把队友当成“名字不同的 subagent”
如果生命周期还是“执行完就销毁”,那本质上还不是 teammate。
2. 队友之间共用同一份 messages
这样上下文会互相污染。
每个队友都应该有自己的对话状态。
3. 没有持久名册
如果系统关掉以后完全不知道“团队里曾经有谁”,那就很难继续做长期协作。
4. 没有邮箱,靠共享变量直接喊话
教学上不建议一开始就这么做。
因为它会把“队友通信”和“进程内部细节”绑得太死。
学完这一章,你应该真正掌握什么
学完以后,你应该能独立说清下面几件事:
- teammate 的核心不是“多一个模型调用”,而是“多一个长期存在的执行者”。
- 团队系统至少需要“名册 + 邮箱 + 独立循环”。
- 每个队友都应该有自己的
messages和自己的 inbox。 - subagent 和 teammate 的根本区别在生命周期,而不是名字。
如果这 4 点已经稳了,说明你已经真正理解了“多 agent 团队”是怎么从单 agent 演化出来的。
下一章学什么
这一章解决的是:
团队成员如何长期存在、互相发消息。
下一章 s16 要解决的是:
当消息不再只是自由聊天,而要变成可追踪、可批准、可拒绝的协作流程时,该怎么设计。
也就是从“有团队”继续走向“团队协议”。