工作标题,待定稿后替换
上个月有个事,挺有意思。
Linus——就是那个骂了三十多年别人代码有问题的 Linus——自己用 Claude Code(Anthropic 出的 AI 编程工具)写了组 Linux 内核补丁。先交代一句:内核是操作系统的核心部分,内存怎么分、硬件怎么访问,都归它管。
他修的问题叫页面缓存的引用计数瓶颈。页面缓存是内核拿来加速文件读取的一块内存;引用计数是管这块内存的记账方式——每块内存被谁用着就记一笔数,数归零才允许回收。这个瓶颈卡了社区两年多,AI 出手,基准测试里读取吞吐量直接翻了 23 倍。
按剧本,这该是个”AI 编程吊打人类”的爽文。但剧情拐了个弯:补丁还没合入,一个人类审查者 Kiryl Shutsemau 抓出了一个竞态(race condition,两个操作抢同一份数据,结果取决于谁先谁后)。
这个 bug 藏得有多深?读取文件的时候,内核存数据的内存页刚被替换掉(内存在内核眼里是一页一页管的),文件大小又恰好在这个时候扩展了。两件事一交错,读取代码就把文件里新扩出来的、压根没写入内容的空白区域,当成有效数据返回给了程序。它只在特定时序下出现,跑一百次测试可能都安然无恙。
最扎眼的是:这组补丁在提交前,已经经过了一轮初步审查,Linus 本人也过了一遍。都没看见。
写代码的 AI 没有问题,有问题的是:AI 现在能稳定造出人审不动的 bug 了。
而整个行业的应对方式,目前就一句话:AI 写,人审。Google 今年四月份公开的数字是,公司内部 75% 的新代码由 AI 生成,工程师负责 approve(点通过)——半年前这个数还是 50%。
问题就卡在这了。我干这行十三年,review 别人的代码是我每天的真实工作。我越来越确定一件事:“审”这个字,被严重高估了。
今天这篇,把”审”拆开看。AI 写代码这件事,从头到尾其实有五层约束手段,每一层我都去找了实测数据。看完你会发现一个让人不舒服的规律。
第一层:写之前,先立规矩(spec)
现在流行 spec-driven development,spec 就是”规矩”:先写清楚规格说明,让 AI 按规格写代码。GitHub 出了 Spec Kit,AWS 搞了 Kiro,工具链很热。
这一层可靠吗?看 Linus 这个案子就明白了。
他的 spec 约束得非常清楚:优化页面缓存的引用计数路径,目标、范围、测试基准全有。补丁也确实照着 spec 写了,性能目标超额完成。但 bug 不长在 spec 里写的任何地方——它长在”两个事件恰好同时发生”的缝隙里,而 spec 根本描述不到那个层面。
一句话:spec 管的是”写什么”,管不住”怎么执行”。Linus 算是这个星球上最会给 AI 立规矩的人之一,照样中招。
第二层:写之时,机器先替你读一遍(静态检查)
不运行程序、纯读代码找毛病,这叫静态检查。语法错、类型错、一眼假的低级错,编译器、类型系统、风格检查器(linter)在你跑起来之前就拦下了。这条防线总该靠谱吧?
有个老牌事实可能让你意外:美国国家标准与技术研究院(NIST)从 2008 年起办 SATE 评测,专门考静态分析工具抓安全漏洞的能力——拿埋了已知漏洞的代码给工具扫,看能抓出几成。办了十几年,结论很稳定:工具的检出能力有明确天花板,一直没有实质突破。
这不是说静态检查没用。低级错它抓得很稳。但竞态这种需要理解”执行顺序”的 bug,静态分析基本瞎。
第三层:写之后,让 AI 审 AI
既然 AI 会写,业界自然想到让 AI 审。先摆数据。
AI 审查能抓到的 bug 比例在 33% 到 80% 之间大幅波动,取决于 bug 类型——这是 AI 编程厂商 Augment 自己公布的实测。不同工具之间的差距同样悬殊:Augment 2026 年 3 月的博客里贴过一轮基准测试,表现最保守的工具,在 137 个埋入 bug 里只抓出了 12 个。
再算上那个绕不过去的词:同源盲区。
Linus 的补丁就是活证据——提交前过了初步审查,竞态还是漏了。而业界现在主流的”AI 审 AI”,还有个绕不开的机制问题:模型生成代码时建立的那套推理,审查时还是同一套。它写的时候瞎的地方,审的时候一样瞎。这就是同源盲区的意思——上面的检出率数据,有一部分就栽在这上头。
还有一组对照数据来自 CodeRabbit:他们分析了自己平台上的代码合并申请(pull request,业内叫 PR),AI 生成的 PR 里出现的问题数,是人类写的 1.7 倍。
第四层:跑之前,靠测试
测试是金标准——对普通 bug 是。
对竞态这类 bug,有个残酷的常识:测试跑过的代码行占比拉满,竞态照样漏。因为这种 bug 看运气:同样的输入,这次跑和下次跑,结果可能不一样。你的测试跑一百遍全绿,线上第一万个请求时,两路同时执行的线程(程序里并行跑的几路任务)恰好撞上,就爆了。
这有多难搞?看看内核社区怎么做的:他们今年专门造了个叫 MAccConc 的测试工具,功能是强制编排线程的执行顺序,人为制造”恰好同时”的时序,就为了能把这类 bug 稳定地复现出来。连全世界最顶级的工程团队,都得靠专门造工具才能审这类问题。
你我手上的项目,有这个配置吗?
第五层:跑之后,灰度和开关
最后一层:灰度发布、功能开关(feature flag),新功能先放 5% 流量观察。
这层是真有用,但它的边界也清楚——它能控制”爆”的范围,控制不了”错”的性质。竞态这类 bug 的阴险之处在于不爆炸:它不报错,不宕机,只是悄悄把没写入过的数据返回给用户。灰度盯着错误率看,一切正常,错误已经发生了。
所以规律是什么
把五层摆在一起,一个清晰的事实浮出水面:
约束手段的可靠性,和 bug 的隐蔽程度负相关。 翻译成人话:bug 越隐蔽,每一层防线越靠不住。
| 防线 | 手段 | 实测可靠性 |
|---|---|---|
| 写之前 | spec 约束(Spec Kit、Kiro) | 管”写什么”管不住”怎么执行”,Linus 照样中招 |
| 写之时 | 静态检查(编译器、linter) | 有明确天花板,对执行时序类基本无效 |
| 写之后 | AI 审 AI + 人审 | 检出率 33%–80% 大幅波动;同源盲区 |
| 跑之前 | 测试 | 行覆盖拉满也漏竞态,需专门工具强制时序 |
| 跑之后 | 灰度、功能开关 | 限爆炸半径,防不住”不爆炸”的错误 |
一眼假的错(语法、类型、低级逻辑),每一层工具都抓得又快又准,AI 时代这层防线反而更强了。但越隐蔽的 bug——并发时序、边界条件、安全漏洞——每一层都在漏。几个实测数字:
- Veracode 今年的 GenAI 代码安全报告:44% 的 AI 代码生成任务引入了带安全风险的漏洞。他们测了 100 多个模型,这个比例四年没怎么动过。
- GitClear 分析了 2 亿行代码:AI 时代代码改动返工率上升了 39%,重复代码块涨了 81%。
这些数字翻译成人话就是:AI 写的代码能跑,而且在以你看不见的方式变烂。
而与此同时,代码的产量已经是机器速度,审查还是人类速度。Linus 那个补丁,人类审查者靠”专业直觉”把它拦在了合入前——这是好事。但你想想,如果这是你的项目、你的团队,没有 Linus 级别的审查者坐镇呢?
产量和审查能力之间撕开的这条缝,就是竞态这类 bug 的藏身之处。而且随着 AI 写得越来越多,这条缝只会越来越宽。
那普通人怎么办?下篇写实操:这五层防线每一层具体怎么用才能物尽其用,以及——当所有手段都失效之后,兜底到底靠什么。
