后台编码智能体

11 分钟读完

U12
实战手册 · 编码与计算机操作智能体

后台编码智能体:队列才是产品。

一个每天开十二个 PR 的后台编码智能体,如果团队只合得进四个,就什么也没增加;等剩下那八个放旧了、开始互相冲突,它甚至是在做减法。把智能体从编辑器里拆出来,瓶颈就从"写代码"搬到了"复核代码",而随后的每一项设计决策——任务挑选、环境复现、并发、失败处理——要么是在让一次运行能自我验证,要么是在把复核队列压短到工作真能落地。

STEP 1

循环里没有人,就意味着这次运行必须自己验证自己。

交互式编码智能体可以问。它把 diff 摆出来、等着、被纠正、然后继续。这里的每一次往返,都是开发者顺手完成、自己毫无察觉的一次修复,而把智能体拆出来会把它们一次性全部删掉。剩下的东西必须足以独自把活干完。

  • 挑选标准是"完成与否机器可判",不是"难不难"。"修好这个不稳定的测试""补上 linter 标出的空值检查"之所以是好的后台任务,不是因为它们简单,而是因为最后有一条命令会以 0 或非 0 退出。"为了可读性重构支付模块"在任何能力水平上都是糟糕的后台任务,因为仓库里没有任何东西能告诉智能体它做完了。
  • 测试套件就是规格,而它的覆盖率就是你的可靠性上限。后台智能体会心安理得地交出一份改动,通过一套根本没测到它所破坏行为的套件。团队通常会发现,后台智能体逼出的第一项正经投资不是提示词——而是他们一直想写却没写的那些测试。见补丁生成与测试
  • 歧义必须在派发之前消解。一件人类在 Slack 上一句话就问清的事,在脱离式运行里要么变成一次猜测,要么变成一个卡住的进程。把它前置:任务描述要写到一位新来的外包无需提问就能执行的程度,而写出这份描述,正是你真正在付钱买的那件工作。
  • 给这次运行一条大声失败并停下的路。你想要的失败模式是"四分钟后带着一段书面理由放弃"。默认拿到的却是"接着跑了四十分钟,基于错误的假设产出了一大坨自信的 diff",而后者让复核者付出的代价,远高于那次放弃。

有用的重构视角:后台智能体不是一个更快的开发者,而是一位没有沟通渠道的异步外包。它问不出口的每一个问题,都必须事先在任务里、在测试里、或在仓库约定里回答掉——而值得派发的任务,正是你能在五分钟内做到这一点的那些。

STEP 2

大多数后台运行死在环境上,不是死在代码上。

跑脱离式智能体的头一个月里,最常见的失望不是推理糟糕,而是一次运行把全部预算花在装依赖失败上,然后交出一段看着像模像样的、关于"我本来会怎么做"的总结。

  • 智能体的沙箱不是你的笔记本,也不是你的 CI。它没有缓存好的包仓库、没有预授权的 registry 凭据、没有跑着的数据库,也没有你那份入职文档始终没来得及提的那十七件事。你的初始化脚本没覆盖到的,智能体都会试着自己重新发明——发明得很糟,而且在计时。
  • 把环境写成一份产物,并单独测试它。一份签入仓库、能让全新容器一路跑绿的初始化脚本,是整份手册里回报最高的投资。它对新同事也有好处,这是个给它找预算的好理由。
  • 对准备好的环境做快照,而不是每次运行重建一遍。在多数仓库上,装依赖占掉了大部分墙钟时间,而它每次都一模一样。一个预热镜像或文件系统快照,把五分钟的税变成只付一次的启动成本,这比沙箱冷启动的原始数字重要得多。
  • 刻意决定出站网络,因为默认是敞开的。后台智能体需要一个包仓库,大概还需要你的代码托管。它不需要任意的出站访问,而出站访问正是"被投毒的依赖"或"issue 评论里被注入的指令"变成数据外泄的那条通道。默认拒绝加白名单,是这里能用的最高杠杆控制——见沙箱与代码执行沙箱与隔离模式
  • 给它刚好够把活干完的最窄凭据。一个能推分支、能开 PR 的令牌,不等于一个能合并、能删分支、能读生产密钥的令牌。范围规则见为智能体划定凭据范围,而脱离式执行恰恰是"没人看着这些凭据被怎么用"的那个场景。
  • 把初始化失败与任务失败记成两类。如果你的指标里分不开这两者,你会花整整一个季度调提示词去修一个 Docker 问题。
STEP 3

每次运行都隔离,并把墙钟时间当作正确性风险。

脱离式运行天然是并发的,而仓库是共享的可变状态。隔离本身很直接;不那么显然的是,延迟本身会让产出变差。

  • 一次运行,一个分支,一个工作树。永远不要让两个智能体共用一个检出。这很便宜,而且它消掉了一整类令人困惑的失败——运行 A 改了一半的文件被运行 B 当作上下文读了进去。
  • 陈旧程度是耗时与仓库速度的函数。09:00 从 main 切出、16:00 才被复核的分支,得挺过别人一整天的合并。在繁忙的仓库上,一份 diff 还能干净落地的概率掉得很快,而买单的是复核者——所以一个花一小时产出略好补丁的智能体,很容易净收益不如一个六分钟就交活的。
  • 宁可多次短跑,不要一次长跑。更短的运行冲突更少、复核更快、失败更便宜,也更早给你可用的信号。"把相关改动打包进一次大的自主会话"这种直觉,优化的是错误的变量。
  • 提前定好 rebase 策略并把它自动化。要么基线一动智能体就 rebase 并重跑套件,要么关掉这个 PR、从当前 head 重新派发任务。两种都行;一摞悄悄偏离 main 的分支不行。
  • 让触及同一片区域的运行串行。三个智能体各自改同一个模块,产出的是三份互相冲突的补丁,和一个要手工调和它们的复核者。按归属做路由:每个文件簇同时只允许一次在途运行,其余排在后面。
  • 永远不要让后台运行自己合并。开 PR 是一次提议;合并是对共享状态的不可逆动作,它属于人这一侧的决定——这就是人在回路里那条放置规则,落到仓库上的样子。
STEP 4

复核队列才是吞吐上限。给输入设闸。

这是决定整个项目能不能回本的部分,而它是一个排队论问题,不是一个 AI 问题。合并吞吐由复核产能决定。派更多智能体只是提高到达率,而到达率高于服务率并不会产出更多已合并的代码——它产出的是一队越来越旧的分支。

  • 量已合并的 PR,永远不要量已开的。已开 PR 数是每个后台智能体产品都会给你看的指标,也正是那个可以一边上升、一边让交付价值下降的指标。如果"已合并 / 已开"的比值在往下漂,你是在制造复核债。
  • 显式给在制品设上限。挑一个团队一天真能清完的"在途智能体 PR"数量,超过就拒绝派发。有上限的队列是一个系统;没上限的队列是一个垃圾填埋场。
  • 在派发时约束 diff 大小,而不是在复核时。复核时间随 diff 大小快于线性增长,而一份 600 行的智能体补丁被"扫一眼"而非"读一遍"的概率格外高——这就把你的安全机制变成了橡皮图章。如果一个任务没法表达成一份小 diff,就在派发前把它拆开。
  • 让每个 PR 自带证据。要求是什么、改了什么以及为什么、跑了哪些命令与其输出,以及智能体刻意没做什么。一个必须从 diff 反推意图的复核者,花掉的正是你本想省下的时间;成本模型见人工复核的成本
  • 把机器可判的活儿彻底从人这里挪开。格式化、lint、类型检查、生成文件一致性与测试结果,都应当是智能体在人看到任何东西之前必须通过的闸。每一项流到复核者面前的,都是花在机器本可以了结的事情上的复核产能。
  • 提防复核者变成瓶颈的所有者。如果所有智能体产出都由一个人复核,他就成了单点故障,还拿着团队里最无趣的活儿,而质量会随着量的上升而衰减——衰减的方式没有任何看板会显示出来。
STEP 5

把失败路径设计出来,因为你不会在旁边看着。

交互式智能体是当着一个会纠正它的人失败的。脱离式智能体是失败进一份日志里。在这里,"设计良好的失败"与"设计糟糕的失败"之间的成本差距,比编码智能体手册里任何其他地方都大。

  • 每次运行都对步数、墙钟与花费设硬上限。一个人打断不了的循环,需要能被算术打断。把上限设得足够低,让一次病态运行的代价低于一杯咖啡;并且对"撞上限的运行占比"告警,而不是对单次撞上限告警。
  • 被放弃的运行必须产出有用的东西。"复现不了这个失败的测试;tests/conftest.py 里的 fixture 需要一个连不上的数据库",比一片沉默更有价值,往往也比那份补丁更有价值。把"放弃"做成一种设计好的输出,而不是一个错误态。
  • 绝不原样重试失败的运行。同样的任务、同样的环境、同样的模型,通常会以同样的方式失败,同时再收你一次钱。只在输入里有东西变了的时候重试——并且给次数设上限,因为一个已经挫败了三次运行的 issue,是在告诉你问题出在任务描述上。
  • 把 issue 与评论文本当作不可信输入。由 issue 触发的后台智能体,正在读攻击者可控的文本,然后带着仓库凭据执行代码。那是标准的注入面,而防御在边界上——最窄的凭据、出站白名单、不许自合——不在一段更好的系统提示词上。见提示词注入
  • 隔离反复横跳的任务。被一次次重新派发的任务,消耗的预算与复核注意力远超其应得。按任务跟踪派发次数,把惯犯拉进人的队列里去。

一次以"我停下了,这是我学到的,这是需要人来决定的"收尾的运行,是一次成功。评判这支队伍时,看"抵达干净终态(合并,或带理由放弃)"的运行占比,而不是"产出 diff"的占比。那些产出了无人能评估的 diff 的运行,才是贵的那些。

STEP 6

值得上看板的五个数字。

后台智能体工具报的是活动量。活动量不是那件事。下面这五个能说明项目是否奏效,而其中四个会比厂商给的数字更难看——这正是重点。

  • 合并率——已合并除以已开。头条指标。健康的项目之所以数值高,是因为任务挑得好,不是因为复核松;把它和你复核流程里的拒绝率信号一起看。
  • 派发到合并的时间,中位数与 p90。这是决定陈旧程度与冲突成本的数字,而它包含排队时间——通常排队占大头。
  • 初始化失败占比。还没碰到任务就死掉的运行。如果这个数高过百分之几,你下周的工作是初始化脚本和快照,不是提示词。
  • 每个已合并 PR 的复核者分钟数。真正的单位成本。拿它对比这项任务由开发者直接做要花多久;如果比值不是明显划算,就收窄任务组合,而不是扩大队伍。
  • 合并后的回滚与补丁跟进率。复核给不了你的质量信号,因为它量的是复核漏掉了什么。这个数上升,意味着 diff 变得太大,或者套件根本没在测那些被改动的东西。

从一类窄而测试完备的任务起步:一份签入仓库、能让全新容器跑绿的初始化脚本,一个让运行在数秒内开始的快照,默认拒绝的出站策略,一个只能推送的令牌,以及一个在途智能体 PR 的硬上限。然后只在加压时合并率与派发到合并时间双双守住的前提下,才扩大队伍。约束从来不是智能体能开多少个 PR——而是你的团队真能读完多少个,而这里的每一项设计决策,都值得朝"缩短复核"的方向去做。

相关:编码智能体架构讲底下那个循环,沙箱与执行讲运行时,异步智能体体验讲脱离式运行需要什么样的界面,代码复核智能体讲同一条队列的另一端。