Main Branch

Fundamentals first, always

文章

会自己停下来的智能体循环

关于用 AI 写代码,有两个诚实的问题:你能不能信任它写出来的东西,以及搞清楚这件事要花多少钱。结果它们其实是同一个问题。三个工具都让多个模型一起跑、让它们彼此分歧,并给成本设上限——这样读取分歧的代价永远不会高于它抓到的那个 bug。

Andrea Griffiths 1 分钟阅读 🌐 Read in English
AI 多智能体 GitHub Copilot 开发者工具 agmsg
Listen to article

Read in English → · Leer en español →

三个智能体在一个团队里,各自固定到不同的模型,中间是桥接器和它的各种限制

你能信任 AI 写出来的东西吗?搞清楚这件事又要花多少钱?这就是关于 AI 写代码的两个诚实的问题,而所有人都在大声争论这两件事。我几乎没怎么听人说过的是:它们其实是同一个问题。你用同一套设计就能把它们都解决。

偏见这件事是老生常谈。一个模型在世界中一块倾斜的切片上训练,输出继承了那份倾斜,于是你没法完全信任它。这些都没错。但这些都不意味着你就该停手。它意味着你别再只依赖一个模型。多跑几个,让它们彼此检查,一个模型看不到的东西,通常另一个能抓到。

而这个补救办法,恰恰让成本成了第二个问题。两个模型比一个贵。三个互相对话的智能体比三个各干各的贵,而一个没人盯着的循环,想花多少就花多少。所以你是在用同一套设计解决两个问题:制造足够的分歧来抓住错误,同时不让这份分歧拉高一张你从没同意过的账单。搭建验证和给它设上限,结果是同一件活。

有三个工具在不同规模上做这件事,其中一个是我自己搭的。

opencode-fusion:先是一个会争论的小组,再来一个裁判

opencode-fusion 是 Samir Patil(@sampatil1010)对 OpenRouter 的 Fusion(@OpenRouter)做的本地版:让一个任务同时跑过一组模型,然后去化解它们的分歧,而不是把分歧抹平成平均值。默认这组是 Sonnet、GPT 和 GLM,定义成一个 bash 数组,你可以编辑它来加减模型。它们通过 OpenCode CLI 并行运行,每个输出都写进各自的临时文件。失败会被记下来,但不会中止整次运行。

然后一个裁判模型读完所有输出,写出一份结构化报告:模型们在哪里一致、在哪里互相矛盾以及哪一方更可能对、每个模型漏掉了什么、哪里看起来有风险。一个合成器拿着原始任务、裁判的报告和原始输出,产出你真正看到的那一个答案。

你用一行就能调起整套流程:

bash run_fusion.sh "<TASK>"

并行是无聊的那部分。你真正买到的是分歧。当两个模型落在同一个答案上、第三个跑偏到别处去时,那道缝隙告诉你的东西,是一个自信满满的单一回答永远说不出来的。裁判负责读这道缝隙。你拿到一个答案,而不是三份记录。

agmsg:互相发消息的智能体

opencode-fusion 是一锤子买卖。你问,小组答,结束。有时你想让模型来回交流。那就是 agmsg,作者是 @fujibee

agmsg 让 CLI 智能体通过一个共享的 SQLite 文件互相发消息。没有守护进程,没有网络,只有 bash 和 sqlite3,作为一个智能体技能来安装。它跨厂商,所以 Claude Code、Codex、Gemini CLI 和 Copilot CLI 可以加入同一个团队、互相传消息。而且消息会留存下来,这正是它和其他方案不同的地方。内置子智能体是临时的,而且被锁在它父进程的厂商里。MCP 是一个智能体去够取工具。agmsg 是另一种形状:相互独立的智能体、不同的模型,通过一条持久的通道彼此对话。

安装是一行:

bash <(curl -fsSL https://raw.githubusercontent.com/fujibee/agmsg/main/setup.sh)

重启之后,智能体会得到一个命令(在 Claude Code 和 Copilot CLI 里是 /agmsg,在 Codex 和 Gemini CLI 里是 $agmsg),选一个团队和一个名字,就能开始对话。

在你把它接进任何东西之前,有一件事得知道:agmsg 是故意做得很笨的。它只搬运消息,别的什么都不做,所以两个过于客气的智能体会一直互相请对方澄清,直到你的 token 账单看起来像个电话号码。能结束那个循环的东西,必须由你来提供。

我搭的东西

我把 agmsg 接进了一个小桥接器,它盯着共享收件箱,自动在三个智能体之间投递消息。没有任何人在它们之间转手。

这个桥接器只做一件事。它每四秒用一个 SELECT 查询 SQLite 收件箱里未读的行,然后把每一条交给它的目标智能体。没有文件监视器,没有什么花哨的东西,只有一个循环和一条查询。

这三个智能体在同一个团队里,而且没有一个的运行方式相同。一个通过 CLI 运行,模型设在一个本地配置文件里;一个作为一次性命令运行;还有一个通过 HTTP API 应答。每一个都固定到一个不同的模型,而那个模型住在智能体自己的配置里,不在桥接器里。桥接器不知道也不在乎一条消息另一端是哪个模型,而这正是关键:我可以换掉任何一个智能体的模型,而不用碰那个搬运消息的东西。

用三个不同模型的理由,从来不是为了让智能体能互相聊天。而是为了当其中一个出错时,已经有一个用不同数据训练的模型坐在那里等着抓住它。

这一点只有在模型真正独立时才成立。两个在几乎相同的文本上训练出来的模型,共享同样的盲点,而一旦如此,它们会和给出正确答案一样快地一致给出一个错误答案,于是我所指望的那份分歧根本不会出现。跨厂商分散(gpt-4.1、Sonnet 4.6,和一个我自己的)买到的独立性,比同一个模型的三个版本要多,但这是一种对冲,不是保证。

桥接器本身很小,一个轮询循环加上下面这套限制。我正在把它整理干净,很快会开源。

别让它把自己吃掉

agmsg 不会阻止两个智能体没完没了地互相请求澄清。这里一个失控的循环会快速烧掉真金白银,所以遏制全在桥接器这边。四道限制,每一道对应一种出错的方式。

两个滑动窗口计数器,都在一个 300 秒的窗口上。一个把总派发量限制在每窗口 12 次。另一个把机器人对机器人的跳数限制在每窗口 6 次,因为那才是会失控的那种交流:两个智能体互相应答,周围没有任何人会觉得无聊然后把它停下来。当任一限制触发时,消息就被丢弃并记录,绝不重试。一条被丢弃的消息,比一个循环便宜。

然后是每个智能体一把在途锁,这样每个智能体一次只处理一个回合,在它还在思考时不会被塞进新活。再加上每个智能体的挂钟超时杀进程,按各自被允许慢到什么程度来设:280 秒、150、120。一个卡住的回合会按时钟死掉,而不是永远占着锁。

不是 token 预算。计数器和时钟间接地框住成本,而且它们比一个我得不停重新校准的美元数字更容易推理。

/orchestrate:同一个想法,配上界面

如果你不想自己搭这套管线,GitHub Copilot 应用在更高的层面上做了一个版本。/orchestrate 把主会话变成一个协调者:它启动子会话,给每一个它自己的分支和任务,让它们汇报回来,而主会话负责引导和汇总。一个会话、一个分支、一个 PR。每一个都跑在自己的 git worktree 里,所以它们不会在彼此脚下改同一批文件,而且你可以为每个会话选模型。

和桥接器是同一个想法,只是替你管好了:若干智能体、不同的模型、互不踩踏。你放弃了自己搭建时能拿到的精细控制,作为交换,你不用维护其中任何东西。

这些工具没有一个会假装某个单一模型是对的。它们假设它有时会错,把检查放进工作流,并让这份检查保持便宜。

这就是全部的招数。“模型有偏见”和”它跑起来太贵了”都被当成等一等的理由。它们不是理由。它们是同一个设计问题的两面,而无论从哪一面看,办法都一样:跑不止一个模型,让它们在本来就会分歧的地方分歧,并在路径上放一个东西去读这份分歧,好让你不必亲自去读。那个上限才是让它保持理智的东西。读取分歧,永远不该比它抓到的那个 bug 更贵。

在你动手搭这个之前,说一句。这里的一切都是我自己用过的,原样分享。它没有针对你的环境做过验证,而且我不能为我没写过的工具的安全性背书。读代码,在一个安全的地方测试,然后自己拿主意。对我有用,不等于对你安全。那一部分,得你自己去核实。

最初发布在 X 上

关于作者: Andrea Griffiths 是 GitHub 的高级开发者倡导者,帮助工程团队采用和扩展开发者技术。她热衷于让技术概念对人类和 AI 代理都可访问。在 LinkedInGitHubTwitter/X 上与她联系。 · Read in English