Paper inspection · arXiv 2610.34938
← 返回 Tony's Lab 网页由小虾生成 🦐

2026 · 软件工程 · 一篇 4 页的实测

会写规则,
不等于规则有用 AI 编码助手复盘自己干完的活,写下 125 条改进建议——真正改变了后续行为的,只有两条。

我们习惯了“让 agent 记住教训”这套说法:踩过的坑写进说明书,下次就不会再踩。这篇论文把它拿到实验台上量了一遍,结果比想象中难看。

样本
30 个真实的修 bug 任务
产出
125 条改进建议
实测
12 条改动 · 13 次
结论
2 条真正有效
判定

现在的“自我进化”只做到了一半:它会写下提案,但不知道提案有没有用。缺的不是动手能力,是验收能力。

01

他们是怎么测的

研究对象是一个叫 /retro 的技能:让编码助手在干完活之后,回头看一遍自己刚才的整个过程,然后提出几条“下次应该怎么改”的建议。这里的“改”不是改模型,而是改它工作时的外挂配置——比如一份项目说明书、一个提交前自动跑的检查脚本、一份“哪些测试本来就会挂”的清单。

  1. 跑 30 个任务。全是真实开源项目里的 bug,每个都在全新的容器里、用同样的提示词,跑完不管代码有没有通过测试。
  2. 让它自己复盘。每个任务结束后立刻调用 /retro,把输出原样存下来,一共 125 条建议。
  3. 人工筛。两位作者判断哪些建议值得落地、能不能在别的任务上验证,最后实现 24 条。
  4. 换任务复测。同一个项目、另一个 bug,5 次用原配置、5 次用改后的配置,看那个“本来要防住的动作”还会不会发生。

这套设计的关键在于:它不看“建议写得好不好”,只看“行为有没有变”。

02

125 条建议,长什么样

按“改什么”分类,最常见的不是写规矩,而是加自动检查:

加自动检查提交前跑脚本、跑代码风格检查
38
指路在说明书里写“该用哪个命令”
24
加一条规矩“修 bug 必须带一个先失败的测试”
21
存一份信息已知会挂的测试清单
20
换工具或配置用更好的方式做同一件事
12
只改做法不动任何配置,只是换个工具用
10

再看“为什么提”:125 条里有 101 条能对应到那次会话里真实发生的事——比如它真的试了 pytest,然后发现没装。这部分是扎实的。

剩下的 19 条,暴露了问题

19 条和会话里发生了什么无关,属于“凭常识觉得应该这样”。其中 18 条是代码风格检查。原因很直白:/retro 自己的指令里写着,“仓库既没有提交前检查、也没有 CI 检查”就算一条发现。

也就是说,工具把自己的偏好,包装成了经验。它不是在总结你踩的坑,是在推销它认为的好习惯。

还有个细节:38 条“自动检查”里,只有 9 条在任务环境里真能跑起来报错。28 条需要的工具根本没装,或者因为任务过程里压根没有提交动作,那个钩子从未被触发过。写下来的防线,大部分是纸做的。

03

换到别的任务上,还管用吗

13 次复测里,7 次真的复现了要防的那个问题,才算有效数据。每次 10 个会话:左边 5 个是原配置,右边 5 个是改过的配置。一个实心点代表“又犯了”。

2彻底消除
一次都没再犯
1减少
5 次里还剩 2 次
4毫无变化
该犯还是犯
3额外做的对照组
其中 1 组反而多干活

前三格是 7 次有效复测的分布;第四格是另外挑无关任务做的对照实验,用来检查改动会不会凭空制造工作。

SYMPY告诉它“测试用 bin/test,别用 pytest” 仓库级事实 · 后来每次都被读到
5/5 → 0/5
ASTROPY存一份“这 3 个测试本来就挂”的清单 清单正好覆盖了后来遇到的失败
3/5 → 0/5
SPHINX清单 + 一份给 agent 的说明 后来挂的是清单外的测试
5/5 → 5/5
对照同一个文件,换一个无关的 bug 没有目标问题,却多做了事
0/5 → 1/5
SPHINX清单 + 项目约定文件 同样没覆盖到实际遇到的失败
5/5 → 5/5
对照同一个文件,换一个无关的 bug 4 次跑去做本该避免的对比
0/5 → 4/5
SYMPY两个包的清单 + 对比脚本 它去测了第三个包
4/5 → 4/4
PYTEST清单只列了某个测试文件里的 3 个失败 后来挂的是别的文件
5/5 → 5/5
ASTROPY修缓存的插件 + 对比脚本 降到 2 次,但都是清单外的失败
5/5 → 2/5
又犯了 没再犯 反而多做了 无效会话

看出规律了吗:凡是“清单正好写中了后来遇到的那几个失败”,就 0 次;凡是“后来遇到的是清单外的失败”,就一次没少。改动本身没错,是它的适用范围太窄。

04

决定成败的,是“适用范围”

同样写进说明书,两种东西的命运完全不同:

仓库级的事实

一直成立

“测试跑 bin/test,没装 pytest。”

换个 bug 还是这个仓库,这句话依然对。5 次里 5 次犯,改完 0 次。这是唯一稳赢的一类。

某次事故的快照

很快过期

“这 3 个测试挂了,因为 docutils 版本不对。”

换个 bug、换批测试,这份清单就不适用了。更糟的是它会被当成权威——清单外的失败,一律判定为“我自己改坏的”。

那个对照实验最能说明问题:一份不完整的清单,让 4 个会话在根本不需要验证的任务上,跑去做了它本来要避免的基线对比。原本 0 次,改完 4 次。规则没消除工作,它制造了工作。

还有一个副作用:捆绑

SymPy 那条最有代表性——同一份建议里写了两行:第一行“测试用 bin/test”,第二行“结束前跑一遍代码风格检查”。前半句是收益,后半句是纯成本。结果所有会话都跑了风格检查,中位耗时从 88 秒涨到 156 秒。建议天生喜欢打包,评测却应该拆开看。

05

哪些地方要打问号

作者写得挺克制,但作为读者得知道这份证据有多重:

06

如果你也在给 agent 写规则

这篇本质上是在给所有“让 AI 记住教训”的做法做体检。落成四条能直接用的:

01

存“仓库事实”,别存“事故清单”

“测试命令是 bin/test”能活很久;“这三个测试挂了”下个月就是错的,而且错得有害。

02

一条规则只干一件事

把收益和成本焊在一起,测出来永远是负的。风格检查那句就是活教材。

03

验收要过三关

目标问题真的出现了吗 → 规则被读到了吗 → 动作真的变了吗。只做到第二关,是最常见的假阳性:文件躺在上下文里,人该干嘛还干嘛。

04

没有失败现场支撑的“最佳实践”,是偏好

19 条凭常识的建议,18 条是风格检查,一条都没证明有用。想加可以,别叫它“经验”。

作者的落点也是这个:自我进化真正缺的不是“生成改动”,而是“判断改动有没有用、并且敢于把没用的删掉”。没有这一环,长期积累的结果大概是——说明书越来越长,行为越来越像没改过。