来源:互联网 更新时间:2026-07-07 07:20
如果你已经尝试过“单 Agent + 工具循环”的编程模式,大概率会遇到一个挺尴尬的场景:模型去扫一圈代码仓库、读了一大段测试用例,结果主对话直接被工具输出的信息塞满;你想让它一边规划,一边派个人手去翻文档,却只能串行等待 subagent 跑完;后台任务明明完成了,还得你手动把结果粘贴回主对话里——这效率明显说不过去。

Agent Teams 的思路很直接:一个 Lead 负责统筹调度,Teammate 在独立的线程里跑自己的循环,彼此之间通过一个 MessageBus 互相传话;Lead 则通过 inbox 注入,把队友的结果接回自己的主上下文。一句话概括:谁干活,谁负责沟通,各行其道。
来,先看个对比。
很多教学示例里,subagent 都是这么跑的:Lead 调用 task 工具 → 等 subagent 跑完(这里会阻塞) → 整段历史作为 tool_result 塞回 Lead。干点小活还行,一旦任务复杂了,你就能感受到那种“等得心焦”的滋味——Lead 没法一边思考下一步,一边让队友去查资料。
Agent Teams 换了个思路:Lead 调用 spawn_teammate 时,不会傻等。后台线程直接启动 teammate_loop(不阻塞),Lead 可以继续对话或者做别的事。Teammate 完成后通过 BUS.send 把结果扔进 Lead 的 inbox,后台的 queue_processor 发现 inbox 里有消息后,自动唤醒 Lead 的 agent_loop。Teammate 不再是工具返回的临时变量,而是一个在后台真正跑起来的工人。
① 用户打字 → history → agent_loop
② Cron 到点 → _queue → inject → agent_loop
③ Teammate 回信 → inbox → inject → agent_loop
Cron 和 Teammate 都不会直接调用模型“乱入”,而是被打包成外部事件,由后台的 queue_processor 抢锁后统一交给 Lead 的 agent_loop 消费。说实话,这种机制是很多成熟 Agent Runtime 的共同形状,算不上新鲜,但对教学理解来说非常有用。
Lead agent loop MessageBus Teammate loop
+----------------+ +-----------+ +-------------+
| prompt + tools | --spawn----->| .jsonl | <---send---- | own history |
| inject inbox | <---send------ | 邮箱 | ---inbox---> | own tools |
+----------------+ +-----------+ +-------------+
这里有两个要点值得留意:
换句话说,队友干完活,只给 Lead 交一份最后的“报告”,不会把中间的一大堆调试信息也塞进去。
生产环境里,MessageBus 对应的通常是 Redis、Kafka 或者数据库队列表。但教学代码为了把机制讲清楚,直接用每个 Agent 一个 JSONL 文件来模拟邮箱,效果毫不含糊。
目录结构是这样的:
.mailboxes/
lead.jsonl
reviewer.jsonl
send() 操作就是向目标文件 append 一行 JSON:
{"from": "reviewer","to": "lead","content": "Parser looks good","type": "result","ts": 1779780000.0}
read_inbox() 则直接读光并删除文件——消费式操作,同一行消息不会重复注入。简单粗暴,但足够说清核心逻辑。
| 工具 | 作用 |
|---|---|
| spawn_teammate | 按 name / role / prompt 启动后台队友 |
| send_message | 给某个 agent 发消息(队友之间也能互相传) |
| check_inbox | 主动读 Lead 邮箱(自动注入时也可以不用) |
spawn_teammate 的底层其实只是一个守护线程:
threading.Thread(
target=teammate_loop,
args=(client, model_name, name, role, prompt),
daemon=True,
).start()
Lead 立刻就拿到“已启动”的信息,不会被卡在队友的十轮工具循环里。
Teammate 有自己的 system prompt 和 messages,入口任务来自 Lead 的 prompt。工具白名单在教学版里是这样定义的:
轮数上限被锁定在 10 轮工具循环,防止后台线程无限烧 token。任务结束——无论成败——都会通过 BUS.send 把结果发回 Lead,然后从 active_teammates 里注销。相当于一个人在后台默默干完活,递上报告就下线了。
Lead 每轮调模型前会执行 inject_inbox_messages(messages),也就是读 lead.jsonl → 删文件 → 追加一条 user 消息。注入的内容大概长这样:
你可能会问:为什么一定要是 role: user?
其实很简单——对 Agent Loop 来说,inbox、cron 触发、用户打字都是“外部世界发来的新事件”。模型下一轮统一按“用户侧输入”处理,完全不需要为每种事件单独设计 role。Cron 触发也是一样的逻辑,只不过用
这样设计的好处是:系统统一、实现简单,而且后续扩展事件类型时也不需要改核心 loop。
上一篇讲 cron 时,后台线程只盯着定时队列。这一版条件变宽了:判断 SCHEDULER 有没有任务待执行,或者 BUS 的 lead 邮箱里有没有新消息。如果两者都没有,就继续休眠;如果有一个有,就尝试非阻塞获取 agent_lock,拿到锁就跑一轮 agent_loop(history)。
agent_lock 解决了一个很现实的问题:用户正在终端输入时,后台不能同时改同一份 history。拿不到锁就 0.2 秒后再试一次,避免数据冲突。
这里没有替换掉 cron,而是直接把两者并入同一套“外部事件”模型里:
cron 到点 → tick 入队 → inject_cron_jobs →
持久化方面,cron 的 durable=True 会将任务写入 .scheduled_tasks.json,重启后 load() 恢复;已到点但未消费的队列仍在内存里,进程挂了就没了——这是教学版本的边界。
环境变量很简单,就是一个 .env 文件:
OPENAI_BASE_URL
OPENAI_API_KEY
MODEL_NAME
在仓库根目录执行:
python3 harness_agent/09_agent_teams.py
推荐你直接复制这一句到终端试试:
启动一个 teammate,名字叫 reviewer,角色是 code reviewer。让它阅读 harness_agent/09_agent_teams.py,用几句话说明 MessageBus 怎么工作。
预期效果是这样的:
全程不需要你动手去拷结果,prompt 写个任务,剩下的交给系统自动流转。
| 简化点 | 真实系统常见补法 |
|---|---|
| 文件 JSONL 邮箱 | MQ / DB / gRPC |
| 单进程锁 | 分布式锁、ack、重试 |
| Teammate 最多 10 轮 | 长期 worker、idle 唤醒 |
| 共享工作目录 | 沙箱、per-agent 权限 |
| 无取消/超时/成本上限 | lifecycle、budget、审计 |
知道这些边界,你才清楚下一版该往哪长。
从一个人干活到一个小队分工,这是 Coding Agent 走向工程化协作的第一步。后面还能叠加权限管理、结构化 schema、队友生命周期管理——但邮箱 + 注入 + 后台唤醒这条骨架,已经足够你跑通第一版了。
电视剧《小欢喜》剧情介绍
俄罗斯最大yandex入口外贸日报直达链接
二次元男生网名可爱(精选100个)
美好的简约网名男生(精选100个)
腾讯元宝怎么用来分析股票基金的基本面信息?
盖乐世社区怎么删除帖子?盖乐世社区个人发布内容撤回步骤
Bubbly无法连接服务器修复方法
欧易OKX官方网站直达入口 2026欧易官方App安卓版v7.1.0下载安装
免费观看国外短视频的app有哪些 观看国外短视频的软件下载
问题:CIA币好不?Cia Protocol币今日上线:价格预测、代币经济学和未来潜力
新浪人工智能热点小时报丨2026年06月20日02时_今日实时人工智能热点速递
国际贵金属走低,现货黄金价格跌0.49%
wallpaper壁纸声音怎么开启
倒数日怎么注册 倒数日账号注册教程
本田CR-V支持哪些手机互联功能
币安Binance交易所官方入口 币安App下载安装与实名注册教程
玉米名字网名大全男生(精选100个)
失落城堡2打完魔王后如何继续玩
短剧《退休金断供,女儿女婿慌了》剧情介绍
《梦幻西游》特殊鬼怪怎么抓-隐藏变异鬼应对要点
手机号码测吉凶
本站所有软件,都由网友上传,如有侵犯你的版权,请发邮件haolingcc@hotmail.com 联系删除。 版权所有 Copyright@2012-2013 haoling.cc