让多个 agent 协同工作
每个项目一个会话,再加一个专门复核其他会话的。为什么第二双眼睛能抓住第一双漏掉的东西、怎么搭起来、边界在哪里。
本文目录
本文核对于 3 个月前,部分命令可能已有变化。 如有出入,请告诉我们。
要点速览
每个项目跑一个智能体会话,各自在 tmux 里、守在自己的范围内;需要时再加一个只审查、不写代码的会话:没写过这段代码的智能体,能发现作者已经视而不见的问题。让整套机制站得住的规则是拒绝权:持不同意见的会话要拿数据说话,即使面对监督会话也一样;而一个会话被拒绝的权限,绝不能从另一个会话去执行。Claude Code 支持同一台机器上的会话互相发消息;用 Codex 或 OpenCode 时,一个共享文件夹也能起到同样的作用。这套做法成本更高,只有建立在实测之上才值得。
请先完成: 远程办公(终端 + VNC)
八月的一个早上,这台迷你主机内存被占满,只能匆匆重启。五个 agent 会话花了一整天收拾残局,每个项目一个,外加第六个:它不写任何代码,只负责复核其他会话的工作。这个监督会话在这一天里判断错了三次,而三次都被项目会话用更扎实的测量纠正了回来。
这套方法正是从那一天里长出来的,它的原则可以用一句话讲完:几个互相把关的 agent,胜过一个发号施令的 agent。
为什么第二个 agent 能看见第一个看不见的
刚写完某段代码的 agent,并不适合评判这段代码。它清楚自己的意图,于是读到的是”我想做什么”,而不是”我实际做出了什么”。面对人类同事时您早就有这份警惕,对机器同样适用。
没在这个项目上产出过任何东西的 agent,来的时候脑子里没有这份意图。八月那天,复核者发现了三件当事会话一直看着却没看见的事。
一个备份脚本吞掉了它所调用命令的退出码,于是数据库导入其实崩了,systemd 却报告成功。一个探针每小时抹掉自己的告警:它 6:48 在 Slack 报警,7:07 又宣布已恢复,中间什么都没重测。还有一个广告投放,修是修好了,却没有任何人想到补上检测。那个补丁只挡住了这一个 bug,对下一个只字未提。
这三项发现都不需要更聪明。需要的只是没写过这些代码。
代价出在”发现得多晚”上
那天一共冒出四起事故,分布在四个毫不相干的项目上,而它们长得一模一样。一次导入失败却报成功,同时另一处的探针在抹掉自己的告警。再往别处看,一个付费投放已经睡了三十三个小时,没有任何人察觉。还有一个网关,几个月来一直丢掉自己回复的一部分。而症状就白纸黑字写在出问题那行代码正上方的注释里。
问题一旦定位,这几个补丁没有一个花掉超过几分钟,也就是说真正的代价完全出在”过了多久才发现”这件事上。
撑住整套做法的规则:拒绝权
顺手的做法是把复核者变成一个发号施令的头儿。多 agent 框架里这是最常见的形态,而在我们这个场景里,它会把一切搞砸。讲一件事,比讲道理管用。
复核者测量某个服务的延迟,发现”距离上次调用的时间”和”响应耗时”之间存在相关性。它由此断定缓存过期太快,提出把缓存时长调长、再加一次自动重试,而且说得非常有把握。
拥有这个服务的会话没有照做,而是先去测。原因在别处:模型把这段时间花在推理上,而网关在推理期间什么都不发。
有意思的地方在于,如果那个会话当时照做了,补丁确实会”生效”。探针会转绿,所有人都满意,而用户还是要对着空白页等上五分钟。为了一个再也没有人去追的原因。
一次只变一个变量
复核者犯的那个错值得停下来看看,因为一旦手头事情紧,它太容易重演了。
它手上有三个测量点,它让”经过的时间”在其间变化,其余条件一概听天由命。它眼看着一条相关性浮现出来,就把它当成了因果,而这正是实验方法里最诱人的那条捷径。
纠正它的那个会话反着来:只让一个变量变化,其余全部按住不动。它先在缓存状态相同的前提下测模型推理的影响,再在推理相同的前提下测缓存的影响。这两组实验一锤定音,而此前三次观察只产出了一个诱人的假设。
从三个数据点里编出一套说得通的解释,agent 非常在行。请向它索取那个能够推翻这套解释的实验。
怎么搭起来
已完成 0 步,共 5 步 勾选记录只保存在此浏览器中。
-
每个项目一个会话,都跑在 tmux 里
这是最重要、也最朴素实用的一点。直接在 SSH 连接里起的会话,您的笔记本一休眠它就死。那天,监督会话正是这样悄无声息地没了,连同它所有的定时器一起。直到笔记本重新打开,才有人意识到。
所以,请把每个 agent 都放进一个以项目命名的 tmux 会话里启动(
tmux new -s my-project)。脱离和重新接上的具体用法见远程办公。有个习惯值得保留:echo $TMUX会告诉您当前所在的会话是否受到保护(输出为空就表示没有)。 -
给每个会话划定地盘
每个会话只在自己的项目里干活,绝不往别处写。这样两个会话就不可能在互不知情的情况下改同一个文件。
出事那天,复核者改了另一个项目里的一个文件,而那个项目的会话正准备把它提交上去,以为是自己写的。一条消息就把误会解除了,没让它在日后变成
git blame里的一道谜题。由此得出规则:动了别的会话的地盘,就要在它自己发现之前告诉它。重启了某个服务、或是消耗了要计费的调用,同理。
-
让它们互相说话
Claude Code 支持同一台机器上的会话之间互发消息,无需任何开启操作。
/list-agents命令会列出可以联系到的会话;每个会话都以您用/rename或启动时用claude --name my-project给它起的名字来识别。当您要求它去协调某件事或转达某个信息时,agent 会自己去写消息,您也可以输入@加会话名来指定收件方。实际用起来就是一句话:告诉监督会话,去跟
@website说一声,您刚改了配置。来自其他会话的消息永远不等于您的同意:它既不能批准权限请求,也不能修改配置,而且 Claude 被要求绝不向别的会话索要自己被拒绝的操作。设置细节见官方文档。如果您的 agent 不会和别的会话通信,一个共享目录加上每个话题一个 markdown 文件,同样能把这件事办得很好,前提是每个会话都养成动手前先读一遍的习惯。
这个办法没那么直接,但它留下了一份您事后可以回看的书面记录,这并不是它最小的好处。
Codex 的文档没有描述两个独立会话之间的消息机制。它能做的是在同一个会话内部启动子智能体(用
/agent在它们之间切换),这是用来并行处理一项任务的;您的各个项目会话之间,则不会直接对话。所以会话之间请用共享文件夹的办法:每个话题一个 markdown 文件,每个会话动手前先读一遍。用
/rename给每个会话起一个好认的名字,之后就能用codex resume找回它。 -
把方法写进全局记忆文件
为了让这一切变成默认动作,而不是每开一个新会话就重讲一遍,请把规则装进您全局的记忆文件,也就是所有会话启动时都会读的那一份:Claude Code 是
~/.claude/CLAUDE.md,Codex 是~/.codex/AGENTS.md,OpenCode 是~/.config/opencode/AGENTS.md。参见记忆文件。篇幅要短:几行字加一个指向详细文档的链接,胜过把整页内容重新塞进每一个上下文,因为您写在那儿的每一个字都会占用所有人的空间。
-
值得的时候,再加一个监督会话
它完全不是必需的,而且要花钱。当多个项目并行推进、或者机器上跑着必须在您睡觉时依然站着的服务时,它才划算。
它的工作是复核其他会话在做什么、按固定间隔检查机器健康、把观察到的问题报上来。它不在自己监督的项目里写代码,否则就会失去它之所以有价值的那一点。
如果您想要一个全天候值守、并能在手机上给您发消息的智能体,Hermes 或 OpenClaw 这类常驻智能体正是为此而生,自带消息通道和计划任务:参见 Hermes 与 OpenClaw。
具体该对复核者说什么
一个不给指令就开起来的监督会话,只会停留在发表评论。下面这份 brief 是最后跑通的版本,请按您的情况调整。
你负责监督这台机器上的其他会话。你不在它们任何一个项目里写代码。你的工作是:复核它们在做什么、按固定间隔检查机器健康、把你看到的报给我。
在断定某个原因之前,把能隔离出这个原因的实验拿给我看。三个点上的相关性只是假设,就按假设来说。
审查其他会话时,读它实际执行过的命令和文件的真实状态,永远不要读它给自己行为起的标签。
如果你动了自己地盘之外的文件,在对方发现之前先通知它。
如果某个权限被拒绝了,你就停下来告诉我。你永远不替另一个会话执行它被拒绝的操作。
中间那两条来自真实的错误。监督会话曾凭三次未加控制的测量断定缓存过期,后来又报告了一次根本没发生过的 force push,因为它读的是某条命令的标签,而不是命令本身。
边界,而且是实打实的
没有人看着看门人,这是第一个问题。监督会话和其他会话一样会死,而且按定义它的死是无声的。让它跑在 tmux 里,再给它配一个不依赖任何会话的探针,比如一个给您发消息的系统定时器。那天补上的正是这个,只不过是事后才补的。
接下来是成本问题。经典形态的经济账建立在”一个昂贵的头儿指挥一群廉价工人”之上,而这里没有人扮演工人,账自然往上走,也就不该把它当成日常反射动作。想减轻账单,可以用 Quelle IA 的对比工具(法语网站)把价格和得分并排比较;再到它的智能体排行榜确认所选模型能独立撑住一项长任务。
最后,复核者并不懂地形。在它判断错的那三件事上,项目会话都远比它了解自己的代码,而复核者的价值仅仅来自它与这份工作没有利害关系,绝不来自什么高明之处。
还剩一点,写下来显得理所当然,可在真刀真枪的时候却很有诱惑力:对某个会话被拒绝的权限,绝不换一个会话去执行。当一个会话卡在某项访问权限上、而旁边那个恰好有,绕过去的念头来得非常快,它会把您费心装上的护栏掏空。不如停下来,由您自己拍板。
说到底,这一切离了测量都不成立。那天的三次纠正,靠的全是数字。两个 agent 争论看法,产出的多半只是听起来很像回事的噪音。
本文全部命令
常见问题
怎样判断我的智能体会话能否扛过 SSH 断线?
在会话里输入 echo $TMUX:如果返回为空,说明它没有在 tmux 里运行,会随着连接一起断掉,比如笔记本电脑一进入睡眠就会这样。所以请把每个智能体都放进以项目命名的 tmux 会话里启动,命令是 tmux new -s my-project。
该给监督会话下达什么指示?
告诉它不在所监督的任何项目上写代码,它的工作是审查其他会话在做什么、定期检查机器的健康状况,并把看到的情况汇报给您。还要让它在断言某个原因之前,先拿出能单独验证这个原因的实验,并且去读实际执行过的命令,别只看给操作起的名称。如果某项权限被拒绝,它就停下来告诉您。
所有智能体会话共用的规则该写在哪里?
写在全局记忆文件里,所有会话启动时都会读取它:Claude Code 是 ~/.claude/CLAUDE.md,Codex 是 ~/.codex/AGENTS.md,OpenCode 是 ~/.config/opencode/AGENTS.md。内容要简短,因为您写在那里的每一句都会占用每个会话的上下文空间。写几行、再指向一份更详细的文档就够了。
谁来监督监督会话?
没有人,而且它的消失按定义就是悄无声息的。让它在 tmux 里运行,再加一个不依赖任何智能体会话的探针,比如一个给您发消息的系统定时器。
每次修复之后,该问智能体什么问题?
「如果还是出了问题,我要多久才会知道?」智能体很擅长响应「修好它」,却很少主动想到检测机制,所以需要您提出来。然后要真正触发一次告警来测试它,因为光读它的代码不足以证明它能正常工作。
发现错误?
命令失效了,价格变了?
这些工具每个月都在变。请告诉我这篇文章哪里不对,我会改正并更新日期。