
重点:这一课让一个 Lead 同时拉起多个会干活的队友

- 第 15 课当前要做的是:
- Lead 仍然是主 Agent。
- Lead 遇到局部任务时,可以拉起一个队友。
- 队友有自己的
messages。 - 队友用
文件邮箱把结果发回 Lead。 - Lead 下一轮模型请求前,把邮箱消息注入成
[Inbox]。
- 这节课新增 3 个主 Agent 工具:
spawn_teammate:- 启动一个异步队友。
send_message:- 向某个 Agent 的邮箱发消息。
check_inbox:- 显式读取 Lead 的邮箱。
- 队友只拿到 4 个工具:
bashread_filewrite_filesend_message
- 这一课的关键判断:
- 第 6 课的
task子代理像临时外包,做完一次就把结论交回来。 - 第 15 课的
teammate像长期队友,有自己的上下文,可以一边干活一边发消息。
- 第 6 课的
具体案例:Lead 让 Alice 写 schema,再让 Bob 检查结果
- 这节课用一个最小但真实的团队案例:
- Lead 负责协调。
- Alice 是
后端队友,负责创建schema.sql。 - Bob 是
测试队友,负责检查schema.sql是否存在、内容是否像一张 users 表。
- 单个 Agent 当然也能做这件事。
- 但第 15 课要看的不是 SQL 文件本身,而是这条协作链:
- Lead 不把所有中间过程塞进自己的上下文。
- Alice 自己请求模型、自己调用工具、自己完成局部任务。
- Alice 只把结果发回 Lead。
- Bob 后面可以再基于文件现场做第二个独立检查。
文件邮箱是这节课最小的消息总线
- 这次没有引入数据库、Redis、WebSocket 或真正的多进程队列。
- 教学版只用一个目录:
bash
.mailboxes/- 每个 Agent 一个文件:
bash
.mailboxes/lead.jsonl
.mailboxes/alice.jsonl
.mailboxes/bob.jsonl- 发消息就是追加一条消息记录。
- 这条记录本质上只有 5 个字段:
- 读消息就是:
- 读出这个文件。
- 解析每一行 JSON。
- 把这批已读消息标记为已经消费。
- 所以它是消费式 inbox:
- 消息被 Lead 读到以后,就不再留在邮箱里。
- 这让课堂上能直接看到“消息从文件进入 messages”的动作。
- 当前教学版用最简单的做法:
- 每个邮箱文件只保存“还没交付给模型的消息”。
- 读完以后直接移除这个待处理文件。
- 下一次有新消息,再重新创建同名文件。
- 这里删的不是长期通信记录,而是“这批待处理消息的临时队列文件”。
- 真正生产系统不能这么粗糙:
- 更稳的做法是先加文件锁,或者把
lead.jsonl原子改名成 processing 文件。 - 这样读取期间如果又有新消息写进来,新消息会进入新的 inbox,不会和已读消息混在一起。
- 更稳的做法是先加文件锁,或者把
Lead 怎么感知队友结果
- 模型不能直接访问本地邮箱目录。
- 模型也不会自动知道 Alice 做完了什么。
- HarnessX 做了一层注入:
- 每一轮请求 DeepSeek 前,程序先读
lead邮箱。 - 如果有消息,就把它格式化成
[Inbox]。 - 再把
[Inbox]当成一条新的role: "user"消息追加到messages。
- 每一轮请求 DeepSeek 前,程序先读
- 这就是本课最重要的一来一回:
- 队友结果先进入本地文件。
- 本地文件再进入
messages。 - 模型通过
messages感知团队协作状态。
设计决策:这版先让 Lead 当队长,不急着做复杂团队
- 决策一:由 Lead Agent 负责协调。
- Lead 决定什么时候创建队友、给队友发什么任务、怎么解释队友回来的结果。
- 队友可以独立工作,但最后面向用户的回答仍然回到 Lead 循环里。
- 这样学起来最清楚:
- 总有一个地方负责收口。
- 如果一开始就做点对点团队,每个队友都能自己决定下一步,系统会更灵活,但学员很难判断“最终答案到底归谁负责”。
- 决策二:用邮箱文件记录团队通信。
.mailboxes/*.jsonl不是最快方案,但它最直观。- 学员可以直接打开文件,看见 Alice 给 Lead 发了什么。
- 这比内存队列更适合教学:
- 内存队列跑得快,但进程一停就没了,也看不见历史。
- 文件邮箱让团队通信变成一个能检查、能讲清楚的中间产物。
- 决策三:队友只拿受限工具集。
- 队友只需要完成局部任务,所以只给
bash、read_file、write_file、send_message。 - 这样队友不会接管整个系统,不会自己建任务板、定时任务、加载 skill 或继续拉新队友。
- 给每个队友完整工具池当然更省事,但角色边界会糊掉。
- 一旦出问题,也更难看清是 Lead 的协调问题,还是某个队友越权做错了事。
- 队友只需要完成局部任务,所以只给
和第 6 课 task 子代理的区别
| 能力 | 第 6 课 task | 第 15 课 teammate |
|---|---|---|
| 生命周期 | 同步执行一次 | 异步运行,教学版最多 10 轮 |
| 通信方式 | 只返回最终结论 | 文件邮箱,可互发消息 |
| 上下文 | 子代理独立,父代理只收结论 | 队友独立,Lead 通过 [Inbox] 接收消息 |
| 工具范围 | 基础文件和 shell 工具 | bash、read_file、write_file、send_message |
| 适合场景 | 局部阅读、一次性探索 | 多个角色分工、持续协作 |
- 用一句话区分:
bash
task 是一次性请人查一件事。
teammate 是给团队增加一个能持续发消息的队友。怎么跑
- 沿用第 0 课的
npm link和 DeepSeek 配置。 - 这节课要用无参数
hx agent,因为队友是异步的,常驻会话更容易观察 inbox。
bash
hx agent- 进入常驻会话后输入:
bash
# 先让 Alice 写文件
启动 alice 作为后端开发队友,让她创建一个名为 schema.sql 的文件,里面包含 users 表。
# 等 Alice 完成后,让 Lead 读取 inbox
检查 inbox,查看 alice 的结果。
# 再让 Bob 检查 Alice 写出来的文件
启动 bob 作为测试队友,让他检查 schema.sql 是否存在,并列出文件内容。
# 再读取 Bob 的结果
检查 inbox,查看 bob 的结果。- 关键预期输出:
bash
# Lead 启动队友
> spawn_teammate name=alice role=后端开发
[TEAM] spawned alice role=后端开发
# Alice 自己调用工具
> teammate:alice:write_file path=schema.sql bytes=...
# Alice 给 Lead 发消息
> teammate:alice:send_message to=lead type=message content=...
[TEAM] completed alice
# Lead 下一轮读到队友消息
[TEAM] injected lead inbox messages=...
[Inbox]
From alice ...- 判断跑通看三件事:
- 终端出现
spawn_teammate。 - 终端出现
teammate:alice:*这类队友工具日志。 - Lead 下一轮能看到
[Inbox]并基于 Alice 的结果回答。
- 终端出现
这一课真正要记住
spawn_teammate:- Lead 创建一个有独立
messages的队友。
- Lead 创建一个有独立
send_message:- 把消息追加到对方的
.mailboxes/{agent}.jsonl。
- 把消息追加到对方的
check_inbox:- 显式读取 Lead 邮箱,读完消费。
[Inbox]:- 本地程序把邮箱消息注入到
messages后,模型才能看到的团队消息。
- 本地程序把邮箱消息注入到
activeTeammates:- 进程内记录正在跑的队友,教学版不做持久 team config。
bash
第 15 课的一句话原理:
Lead 不再把所有事都塞进自己的上下文,而是把局部工作交给独立队友,再用文件邮箱把结果带回下一轮 messages。源码
这节课源码要看的是“队友结果怎样进入 Lead 的下一轮模型请求”。
源码大流程图
代码概览
第 15 课新增的是 4 组运行时对象。
这几组对象对应到文件:
src/agent-loop.js- 管 Lead 主循环、队友循环、工具分发表、inbox 注入。
src/teams.js- 管邮箱文件、消息写入、消费式读取、
[Inbox]格式化。
- 管邮箱文件、消息写入、消费式读取、
src/system-prompt.js- 告诉模型 teammate 和 task 的区别,以及队友只能用哪些工具。
代码细分
Lead 拉起队友这一步,只改变运行状态,不阻塞主循环。
队友循环和 Lead 循环是两份上下文。
工具池要分开看。
最终只有一个关键动作:把邮箱消息放回 messages。
这一版刻意没有做后面的协议层。
- 没有 shutdown 握手。
- 没有权限冒泡。
- 没有 team config 持久化。
- 没有文件锁。
- 没有
tmux或真正多进程隔离。
这些都留给后面的 Team Protocols。第 15 课先把最关键的链路跑明白:
bash
Lead spawn 队友
→ 队友独立跑模型和工具
→ 队友写文件邮箱
→ Lead 把 [Inbox] 注入 messages
→ 模型基于队友结果继续工作