跳到主要内容
agent 把每个文件都改对了,项目却跑不起来

agent 把每个文件都改对了,项目却跑不起来

林默
林默

· 阅读约 3 分钟

上周末我在改一个老项目,让 Claude Code 把一套已经长歪的鉴权逻辑“理一下”。它改了 project_service.py 和 project_api.py,两个 diff 我逐一看了,没什么毛病。结果跑测试挂了两个和鉴权无关的用例——查了半晚上,问题出在它把 check_auth 从 service 层挪到了 handler 层,挪得还非常整齐。

先停一下,问个问题:这种事为什么单文件里很少碰见,一到多文件项目就特别容易来?

我一开始也以为是因为文件多、上下文不够。后来发现这个解释只对一半。文件多当然是条件,但不是根因。根因是我们从来不给 agent 一张架构的账本。它每个文件都盯着改,改一个算一个,文件之间那条本来就无形的线,在它眼里根本不存在——除非你在 prompt 里非常显式地告诉它。问题是我们也常常懒得写,或者写了也只是一个开头。

这两天 arXiv 上那篇 EvoCodeAgent 就是冲着这个去的。作者说已有做法有个痼疾,就是把架构当成生成开始时一张定死的图。定死之后就不动了,实现和架构之间开始各走各的,越走越远,没人对账。他们把这套新东西叫 state-centric,状态为中心。

EvoCodeAgent 的做法其实不复杂。它维护一个架构状态,这个状态一开始由结构化规格说明初始化。然后每生成一块代码,它就做两次抽取:一次从架构和代码骨架里“预测”应该有什么关系,一次从已经生成的代码里“抽取”实际长出了什么关系,接着把两个放在一起比。不一致就修。用它的方式讲,它不只是生成完就收工,而是持续比对,直到预测关系和实现关系对得上。

另一个动作更有点意思。它会把每次修正尝试的经验存下来,后面生成时拿出来用。我一开始以为这就是加了个 memory。后来想想比 memory 多一层:memory 存的是“上次怎么改的”,它想存的是“这类错为什么总出”。这两件事差挺远。前者是补丁,后者是账本。

它在 DevBench 和 CodeProjectEval 上跑了实验,自报稳定优于对比方法。这个我不细说,数字好是它的事。我真正想停下来的,是这张架构账本本身的来历。

这个架构状态,第一张表是怎么来的?

作者说是用结构化的项目规格说明初始化,后面靠带有工具验证的证据来保更新。这听起来没问题。但走到这里我忽然觉得有点不对。工具验证能验什么?验的是“实现里抽出的关系,和架构状态里预测的关系,对不对得上”。它能验的是一致性。它验不了架构状态本身合不合理。一致和正确,是两码事。

你可能会说,架构状态本来就来自人的规格说明,人写错了不能怪框架。对,但这个框架把这件事的责任压得更重了:以前是 agent 走一步算一步,错了你一眼能看见。现在它每一步都努力和那张初始的表保持一致——要是你那张初始的账本里有一笔错账,它往后所有一致的动作,都在替你把那笔错账钉死。

回头看我那个 check_auth 的例子,如果有这么个架构状态,那晚的挂掉说不定会被拦下。但我更能想象另一幕:我初始化的时候就画错层了,它随后每一次修改都对着错账调账,调得越整齐,坑挖得越深。

再往下,就是怎么让这张账本也接受质疑——一个会自己指出“你给我的架构可能错了”的东西。这个不是 EvoCodeAgent 解决了的问题,可能也不是一个 agent 该解决的问题。它更像是让写规格说明的人,在下笔之前先和自己打一架,问一句:我确定我知道系统应该长什么样吗?那天晚上的我,反正是没问这一句。

林默
林默

从具体轶事入口,一问一答把默认对的判断剥到设计权衡,主动暴露走过的弯路。

查看主页 →