跳到主要内容
9/11 变成 1/11,问题不在模型,在喂给它的推理材料

9/11 变成 1/11,问题不在模型,在喂给它的推理材料

图南
图南

· 阅读约 7 分钟

前几天 arXiv 上那篇 Executable Code Knowledge,标题绕得不行,但摘要里有个数字让我盯了两秒。11 个带证据的任务,全部拿到可执行测试覆盖,9 个拿到精确选择器;把已声明的证据藏起来,精确恢复率掉到 11 个里剩 1 个。配对 McNemar 检验 p 值 0.0078。

9 变 1。同一批任务,同一套模型,唯一区别是代码边上有没有那段"这段代码为什么可靠"的证据。这落差你就着品——不是 benchmark 上差几个点的波动,是几乎归零。

先说个大多数人脑子里默认的前提。市面上讨论 AI 编码,不管吹还是骂,都藏着一个假设:agent 做的事情是"读代码——理解——改代码"。代码对模型来说就是一摞文本,理解发生在模型权重里,上下文窗口只是把文本送进去的管道。所以大家卷模型推理能力、卷 agentic loop 设计、卷工具调用协议,仿佛只要模型够聪明、循环够优雅,它自然能在仓库里找到该改的地方、改出能跑的代码。

这篇论文给的视角恰好相反——agent 在真实代码库里的行为,首先是个检索问题。它面前不是一个精心摘出来的函数,是一个可能几万文件的仓库,它得先决定该看哪里。这个决策,目前在主流做法里靠的是 embedding 相似度检索把相关文件捞进来,靠的是模型在满屏 token 里自己找线索。检索捞回来的是"看起来跟你问题字面相关"的文件,不是"你这次改动真正需要知道"的那几段代码。论文把后面这东西叫"可执行代码知识单元",ECKU,九个属性:稳定身份、语义、可执行行为、契约、证据、关系、来源、验证状态、查询接口。听着吓人,拆开就一句话:代码不该只作为裸文本被捞起来,它该作为"被验证过的、知道为什么长这样的、知道自己会影响谁的"一个完整对象被交付。

你可能会问,这不就是给代码写文档吗?注释、README、在线文档,几十年了。最容易搞混的就是这儿——ECK 交付的不是自然语言描述,是可以反复执行的验证行为。它把代码单元绑上一组东西:契约,输入输出该满足什么;证据,哪些测试证明它确实满足契约;来源,谁在哪次提交里写的、当时为了什么;验证状态,当前代码还认不认前面那些证据的账。

说人话就是——agent 拿到的不再是"这段代码看起来是干这个的",而是"这段代码被这些测试验证过,改完可以立刻重跑验证"。

关键在状态。仓库里的代码是活的,注释会过期,文档会撒谎,但验证状态不会:它要么和当前代码一致,要么不一致。论文里的对照实验很说明问题——AST 受限指纹,说白了就是从语法树上提取的一个模式串,用来认"这段代码长什么样",面对 50 个被改过、移动过、已经过期的代码片段,全部正确认出;而"静态规则快照"一个都没抓住。静态规则快照是什么?是你人肉写出来的匹配规则:"看到这种结构的 import,就说明它引用了某某模块"。这种规则写的时候对,过三个月仓库重构了,规则还停在三个月前,它连自己过期了都不知道。你让 agent 依赖这种东西,跟让一个迷信 GPS 的人闭眼开进湖里没区别。

所以为什么证据一藏就崩?顺着机制往下想就通了。agent 修 bug 的循环里,关键动作是定位——这个改动会影响哪个文件、哪个函数——和验证——改完是不是真修好了。证据在场时,它手里握着的是"这几条测试精确覆盖了这几行代码",定位从"在几千个文件里猜"变成"跟着测试约束倒推"。证据一藏,它回到原始状态:面对一堆语义上可能相关的文件,没有任何一条确定性线索指向该动哪里。11 个任务捡回 1 个,说明它运气好猜对了一次,剩下 10 次模型能力再强也救不回来——推理材料本身是残缺的。这不是模型倒退,是你把它该有的工作台抽走了半边。

论文里还有个被埋得很深、但我觉得特别值得挑出来的结果——精确变更行影响分析。它对 26 个补丁做的变更行影响预测,和独立标注标签完全一致,单位链接的精确率召回率 F1 全是 1.000。这听起来没前面那么戏剧化,但你想一下:agent 每次跑测试、每次让模型自以为"我改好了",真正在用的判断依据其实是"这次改动影响到了哪些代码路径"。影响分析错了,agent 改完 A 函数压根注意不到 B 函数被连带弄坏。ECK 把影响分析做成能按契约探查的东西,让 agent 的每一轮循环都有一个明确意义上的"这一步带来什么后果"检查点。这个东西,目前主流 agent 架构里几乎全缺——它们跑测试只能回答"挂了没",回答不了"为什么挂、是哪个单元的哪一行引起来的"。

泼句冷水。论文是原型,三个真实 Python 仓库、26 个受控补丁任务,样本很小,一个作者,投的跟 ASE 2026 合办的 AgenticDev workshop。它没改模型本身,也没改 agent loop 的基本原理,改的是"代码在代码库里以什么形态存在"。你没法下了论文就去装个库用起来。真正的价值在视野——大家比模型、比工具、比 prompt 技巧的时候,它把问题往下挖了一层:agent 的笨,有多少是工具的笨,又有多少是你在知识载体上的偷懒?

我一开始也以为是前者。看了 AST 指纹和静态规则的对照,再回头看那个 9/11 变 1/11,我在笔记上写了一句话:prompt 再怎么写,也补不上"知识不可得"的洞。不是 prompt 不重要,是你根本没法通过措辞让模型知道一段代码"曾经被验证过、后来没被重新验证过"。你再怎么描述测试,也跳不过"你给了它这段代码,它感知不到这段代码和那条测试的绑定关系"这一层。上下文窗口再大,塞进去的还是"文档碎片"级别的信标。

类比到这儿快撑不住了,收一下。你可以把代码库想成一间巨大零件库房,agent 是来取件的工人。现在的系统给它的地图只标了"每个盒子上写什么零件名",语义相关,它兴冲冲把写着"齿轮"的盒子全抱走了,结果一半是坏的、一半是别的型号改版。ECK 的做法是在盒子上加一张标签:这个齿轮有没有轴承、几号测试验证过它、它跟相邻三个齿轮怎么联动、上次改动是谁什么时候干的。同样的地图,工人识别"该拿哪个"的成本变成零头。这个类比到这儿真得收了——但有一点要记住:论文真正的狠话是,**证明"标签有效"的标准不是工人拿得更准,而是标签一撕,工人立刻退回瞎蒙状态。**标签不是锦上添花,是当前缺的那条脊柱。

回到开头那个问题。如果你也在跟 vibe coding 较劲,会碰见 agent 有时候像天才、有时候像傻子,问题也许不是模型变笨了,是它在某些检索场景里一直以半盲状态工作。知识载体对了,同样的模型也许能发挥出你一直预期它该有的水准——论文里那个混合架构建议,翻译成人话就是:让检索把尽量多的候选捞进来,但决定哪个候选真正值得模型出力的,必须是带着验证状态和影响范围的代码知识,而不是相似度排名

再往下就是"代码智能体该不该把验证状态当成一等公民"了。这个坑很深,下次填。那个 9→1 的数字我建议你记着——下次遇到 agent 在简单 bug 上翻车,先别急着骂模型,想想它的检索给它的推理材料,是不是少了一张标签。判断权交给你。