假设你的代码库里有 3 处写错的错误处理。

人类同事写到第 4 处的时候,code review 会把它拦下来。

AI 不会。它会认定这是你的项目约定,然后一口气写到第 30 处——每一处都工整、一致、通过测试,也每一处都是错的。

模型不是在偷懒。它是在忠实地跟随你代码库里已经存在的东西。

AI 代码腐烂机制


〇、元问题:模型的一致性,是它最大的优点,也是最危险的性质

先说清楚一件事:AI 生成代码时,它做的事情是推断你代码库里的模式,然后复制这个模式

这在绝大多数时候是你想要的行为。你不希望 AI 每写一个新功能就换一套错误处理风格;你希望它跟随项目约定。所以模型被训练成一个高度一致的模式复制器。

问题出现在一个特定条件下:当它复制的那个模式本身是错的。

Anuradha Weeraman 在《The Compounding Problem》里把这件事说得很准:

模型不是在偷懒。它是在和你给它的代码库保持一致。这正是你希望它做的事——直到它保持一致的那个东西本身是错的。

这句话是整个问题的核心。AI 代码腐烂不是因为模型笨,而是因为模型太一致了

传统技术债的形成机制是「人偷懒 + 时间压力」。AI 代码债的形成机制是「模型忠实执行 + 传播速度极快」。这两者需要完全不同的应对策略。

一、复制速度打破了「发现窗口」

在传统软件开发里,一个坏模式的生命周期大致是这样:

出现 1 处 → 出现 2 处 → 有人在 code review 里发现 → 讨论 → 制定规范 → 停止扩散

关键在于:人类的复制速度足够慢,慢到留出了发现窗口。

第 2 处、第 3 处出现的时候,团队里总会有人皱一下眉头:“我们为什么要这样写?“这个皱眉的动作,就是技术债的免疫系统。

AI 把这个免疫系统绕过了:

出现 1 处 → AI 在 30 秒内扩散到 30 处 → 已成为「项目约定」→ 修改成本超线性上升

Weeraman 的原文说得很直接:

AI agent 会毫不犹豫地把它扩散到代码库里的三十处,而每多一处,这个模式就显得更根深蒂固、更难回头。

坏模式一旦到了 30 处,它就不再是「一个 bug」,而是「架构」。

这就是「复合」(compounding)这个词的真实含义:不是错误变多了,而是修正的成本随传播数量超线性增长,而传播速度快了一个数量级。


二、为什么 code review 拦不住

标准答案是「加强 code review」。这个答案在 AI 场景下有一个结构性缺陷。

Weeraman 把它叫做 review gap(审查落差)

当一个模型在 30 秒内产出 500 行结构良好、语法正确的代码,认真审查它所需要的认知投入,和它看上去的生成成本完全不成比例。

这里有一个认知不对称:

生成成本审查成本
人写 500 行4 小时40 分钟
AI 写 500 行30 秒40 分钟

审查成本没变,生成成本降了 480 倍。

结果是:审查时间在总时间里的占比,从 14% 变成了 98%。这个比例在心理上是不可持续的,人会自然地降低审查强度,尤其是当代码「看起来很对」的时候——语法正确、结构清晰、命名规范、有注释。

一位 HN 用户 @ThePhysicist 描述了真实结果:

我正准备把一个副业项目里好几个月的 LLM 生成代码全部扔掉。我写 design spec 的时候非常小心,而且 LLM 动的还不是一个新代码库。但经过几个月的 AI 改动,我还是觉得我的代码退化了。

注意他强调的两点:他写了仔细的 design spec,而且不是绿地项目。这两个条件通常被认为是「用好 AI」的关键。他都做到了,结果依然是几个月后代码退化到需要丢弃。

另一位 @techpression 补充了一个更微妙的现象:

这和我的经验一致:长期使用之后,会开始出现一种单独看根本看不出来的不一致。

「单独看根本看不出来」 —— 这是 AI 代码债最难对付的地方。每一个 PR 单独看都是合理的。腐烂只在整体上可见,而没有人的日常工作是「审查整体」。


三、模型版本的地质分层

还有一个几乎没人讨论的问题:一个用了两年 AI 辅助开发的代码库,它的不同层是由不同代模型写的。

2024 早期基础模块  ← GPT-4 时代写的数据模型
2025 中间层        ← Claude Sonnet 4.5 时代的业务逻辑
2026 最新功能      ← Opus 5 / Composer 2.5 写的接口层

每一代模型有不同的强项、不同的失败模式、不同的风格倾向。Weeraman 指出这个问题的严重性远超「代码风格不统一」:

这种不一致比风格层面深得多。它是对问题的推理方式的不一致。老模型可能以某种方式误解了需求,而这个误解被固化进了数据模型。新模型把这个数据模型当成既定前提,在一个错误的基础上构建出正确的逻辑。下游的一切在技术上都成立,在根本上都是错的。

这是最难调试的一类问题。因为你去 review 任何一段新代码,它都无懈可击——它正确地实现了基于错误前提的逻辑。错误在前提里,而前提在两年前的一次需求误解里,被固化进了数据模型。

新模型越强,它在错误基础上构建的东西就越精致、越难拆。


四、“让 AI 自己检查"为什么不管用

HN 上有个高赞评论提出了一个很多人在用的方法:

@tim-projects:产品做出来之后,试试这个 prompt:「审查整个代码库,它能上生产吗?我要用 100 万美元把它卖掉,它够得上这个标准吗?」然后你就等着哭——AI 会告诉你,它做的东西跟它之前声称的完全不是一回事。

紧接着两条回复揭示了这个方法的局限。

@KronisLV 的回复:

你用 AI 生成代码,你让它生成代码,它就生成了。不管你写多少遍「你是一个专家开发者」或者「不要犯错」,都改变不了这个根本。

@geraneum 说得更精准:

然后你让它修。等它说「修好了」,你再问一遍同样的问题——你会得到一份差不多的回答。

这是一个无限循环。因为「找问题」和「修问题」用的是同一个模式匹配器。你让它找问题,它生成一份看起来很专业的问题清单;你让它修,它生成看起来修好了的代码;你再问,它再找出一批新问题。

这个循环永远不收敛,因为它缺少一个外部的、不可被模型说服的判据。

那个判据必须来自代码之外。


五、可以真正起作用的三件事

Weeraman 给出的核心原则是 curation(主动策展):你必须持续地修剪和纠正代码库,因为在 AI 辅助的项目里,延迟维护的成本增长速度比传统项目快得多。

具体到操作层面,有三件事的性价比最高。

1. 端到端测试必须先于任何重构

这是 Weeraman 强调的第一条,理由很关键:

AI 生成代码上的单元测试,往往测的是实现而不是意图,因为代码和测试都是同一个模型写的,它让两者互相吻合。

测的是它自己的实现,不是你的意图。 代码和测试都是它写的,必然互相吻合。这种测试通过了,什么都没证明。

端到端测试不同:它在系统边界上验证用户可见的行为。这个判据在模型之外,模型无法通过「调整实现」来让它通过。

Weeraman 的建议是:自己写这些测试,或者至少自己写测试规格并亲自审查。

2. 把「坏模式检测」变成定期动作,而不是 review 时的偶然发现

既然 code review 在认知上顶不住 AI 的生成速度,就不要指望它。

改成主动搜索:定期在代码库里搜索重复模式的实例数量。如果某个模式出现了 15 次,问一个问题:这是我们决定的约定,还是 AI 推断出来的约定?

区分这两者,是控制 AI 代码债最有效的单点动作。

3. 记录数据模型的决策理由,而不只是数据模型

模型版本地质分层最危险的部分是「被固化进数据模型的需求误解」。防止它的唯一方法,是让数据模型的理由是可查的。

不是 schema 文档,是决策记录:这个字段为什么这样设计,当时的约束是什么,被拒绝的方案是什么。

这样当新模型在这个基础上构建时,你有机会发现前提已经不成立。


总结

机制传统代码债AI 代码债
坏模式传播速度慢,留出发现窗口快,绕过发现窗口
审查/生成成本比约 1:6约 80:1
腐烂可见性单个 PR 可见只在整体可见
不一致的层次代码风格对问题的推理前提
有效的免疫系统code review端到端测试 + 主动模式审计

回到那场没人吵赢的争论。

「AI 能不能写生产代码」这个问题问错了,因为它把 AI 当成一个静态的质量水平在评估。而真实的问题是动态的:AI 的核心优点(模式一致性)在时间维度上会变成它的核心风险,而现有的工程免疫系统(code review)恰好是被这个风险绕过的那一个。

AI 代码腐烂不是质量问题,是速度问题——坏模式的复制速度,第一次超过了人类发现它的速度。


🔍 如果你在维护一个 AI 辅助开发的代码库——

  • 你的项目里有多少「约定」是团队定的,多少是 AI 推断出来的?
  • 你的测试是在验证用户行为,还是在验证 AI 自己的实现?
  • 你的数据模型有决策记录吗,还是只有 schema?

📬 关注梦兽编程,获取更多 AI 工程实践的深度分析。


参考来源: