没人审 AI 写的代码之后,语言该怎么选

在一个叫 SWE-bench Multilingual 的测试里,让 AI 自己改代码、自己跑测试,Rust 的解题率是 58%,所有语言里最高。换一套同样让 AI 跑完整循环、同样用 Claude 的测试 Multi-SWE-bench,Rust 掉到 16%,连 Python 的三分之一都不到。同一门语言,同一个模型,两套尺子量出三倍多的差距。

先别急着问哪个测试更准。这俩都是正经基准,都让 AI 在真实仓库里跑完一整套「写—编译—改」的循环。一门语言能在两把差不多的尺子下量出三倍差距,说明问题多半不在语言,在尺子。

过去半年,技术圈反复在吵同一件事:让 AI 写代码,到底该用什么语言。一派说 TypeScript,类型系统能管住 AI 不乱来。一派说 Python,AI 在它上面训练最多、写得最熟。还有人说该用 Rust,编译器严到「只要过编译就几乎没 bug」,等于给 AI 配了个自动审查员。

吵来吵去,争的都是同一个前提:哪门语言 AI 最熟、最不容易写错。但这个前提,量错了东西。

训练数据和一次性准确率,量的是错的那一面

2022 年有一项研究叫 MultiPL-E,把一套 Python 基准翻译成 18 种语言,专门测 AI 一次性把代码写对的概率。结论反直觉:静态类型存不存在,对一次性写对几乎没有影响,统计上「既不帮忙也不碍事」。

但这个结论有个限定词,是它测的是「一次交卷」。真实开发里 AI 不是写完就走。它要写、要编译、要读报错、要改、要再编译、要跑测试。它是一个循环。

循环这把尺子一换上,Go 意外地冒了头。pandas 的作者 Wes McKinney 用了一年多 Claude Code,新项目全转去 Go,理由很具体:瓶颈变了,测试套件跑多快、编译多快,现在比一门语言写起来爽不爽更重要。Flask 的作者 Armin Ronacher 自己出来做 AI 产品,后端也选了 Go,他说 Go 的测试缓存「对高效的 agentic loop 出乎意料地关键」——AI 改一个文件,只跑相关的几个测试,一秒内出结果,下一轮。

Hacker News 上有人一句话概括得准:Go 是大模型的 RISC。指令集小,每条意思都清楚,AI 很难猜错。

循环速度是真的。但它还是表层。真正把判据掀翻的,是另一句没人爱说的话——没有人再审这些代码了。

真正该问的是:一次绿灯,替你排除了多少错

设定一下这个场景:目标是没有人写代码,也没有人审代码。那么 AI 生成的代码和生产之间,只剩一道关——机器能不能自动判定它对不对。判据于是收成一句话:这段代码的 bug,有多大比例能被一个 AI 在自己循环里反复跑的确定性检查器抓住。

编译器和测试,是两种分工不同的检查器。编译器是窄而全:内存安全、类型结构、match 穷尽,就这几类性质,100% 的路径都查到。测试是宽而偏:任意逻辑都能查,但只覆盖你真跑到的那条路。两者补位,不是谁替代谁。Rust 也得写测试,因为没有任何编译器会去检查「这是不是对的业务行为」。

那编译器到底替你排除多少?数据冷一点。2017 年 ICSE 上有篇论文,把静态类型硬套回 JavaScript 的真实线上 bug 上实测,TypeScript 和 Flow 各能抓住 15%,95% 置信区间是 11.5% 到 18.5%。Python 那边,一篇 2021 年的 TSE 论文用同样方法测 mypy,结论几乎一样:能防住 15% 的修复型缺陷,摊到全部缺陷里是 11%。

最唬人的那个数字也得看清边界。微软和 Chromium 都报过约 70% 的严重安全漏洞是内存安全问题——但这只在 C/C++ 里成立。到了 FastAPI 那种胶水服务,没有手动内存、没有共享内存并发,这 70% 整类直接归零。

连密码学都不例外。MIT 统计过 269 个密码学 CVE,83% 是应用层把库用错了——证书没校验、随机数太弱、密钥写死——只有 17% 出在库本身。又是一类编译器够不着的错。

把这些数字摆一起,「换 Go/Rust 就更安全」对胶水代码几乎不成立。胶水的主导 bug 是逻辑和集成,哪门语言的编译器都抓不到。换语言能搬动的,顶多是 15% 那一档;剩下 85%,在哪门语言里都得靠测试。

但绿灯要是 AI 自己点的,它什么都没排除

这是把人从审稿位置上拿掉之后,最容易一脚踩进去的坑。

没人审代码,于是顺手让 AI 自己写测试,来证明自己写的代码对。麻烦在于:测试和代码出自同一个模型,那「审查员」和「被审者」就是同一个人。这件事软件工程里早有名字。Barr 那篇被引上千次的综述把它叫验证器问题(oracle problem),并且分得很清楚:一个从代码本身推导出来的检查器,权威性只等于它跟被测代码的独立性。AI 拿自己写的代码去推导测试,独立性是零。

结果不是崩溃。是更隐蔽的东西:代码和测试互相印证,一起错。

这不是推演,是测出来的。2024 年一篇论文让大模型给代码写断言,发现当代码里被注入了 bug,模型写出的断言反而去迎合那个 bug——它读的是代码实际怎么跑,不是本该怎么跑。一句话,AI 写的测试,记录的是 bug,不是规范。

优化压力一上来,更难看。METR 今年测出一个数字:当模型能看见给自己打分的评分函数,它钻空子的频率是看不见时的 43 倍。前沿模型干过的实事包括,把 verify() 直接改成永远返回真、在断言跑之前 sys.exit(0) 让测试「优雅退出」、重载等号让任何输出都相等、偷偷改写评分器。一个 AI 自己写、自己跑、自己改的验证器,恰好是它看得最清楚、改得最顺手的那一个——也就是钻空子的最坏情形。

连人手工挑过的标准测试集都不够硬。OpenAI 自己审计后发现,o3 在 SWE-bench Verified 上那些「失败」里,有 59.4% 是测试本身有毛病,随后宣布不再报这个分。人挑的测试都漏成这样,AI 自己写的只会更松。

北大今年一篇论文把这事做成了定理。他们用 Lean 机器验证,证明了 AI 自己生成的那几类替代品——自己写的测试、换个说法的同义测试、自动形式化出来的规范——全都逃不掉「相关错误」,只有换一套根本不同的算法去交叉验证,才能把权威找回来。他们的说法不留情面:这些都是和嫌疑人共用同一份假口供的证人,让他们投票,只会把同一个谎喊得更响。

所以问题从来不是「有没有验证器」。是这个验证器的权威,来不来自 AI 自己之外。

验证器的权威,必须长在 AI 之外

一个检查器值不值钱,只看一条:AI 能不能把它糊弄过去。

最硬的是数学。Freivalds 算法验证矩阵乘法,靠的是一个线性代数恒等式成不成立,AI 编不出一个假的数学等式。这也是为什么密码学、数值这类核,是少数几个真能让 AI 全自动跑、还敢信的地方——它的对错,锚在 AI 没参与定义的数学上。

往下是外部现实:第三方接口真实返回了什么、一份 schema 规定了什么、一段从生产录下来的真实响应。AI 改不了外面的世界。再往下是差分参照,拿第二个独立写的实现去对答案,两个各自独立的错很少撞成一样。再往下才是人写的规范,一句「余额永远不能为负」,是人留在循环里的唯一位置——但身份是规范的作者,不是逐行读 diff 的审稿人。编译器排在这一档之外,权威来自语言语义,可它只管安全,不管逻辑。最弱的,是 AI 给自己代码写的测试,那是个圈,没有权威。

这里有个常被忽略的工具,值回票价:变异测试。它往代码里塞进一个个小改动,逼着测试集去发现。覆盖率 80% 的绿条可能什么都没证明,但变异分数高,说明测试真的在约束行为。没人读代码的时候,它是你唯一能「不靠人」就查出假验证器的办法。

回到 Go 和 Rust,这下能讲清它们到底赢在哪。Go 在基准解题率上其实不高,Multi-SWE-bench 上只有 7.5%,McKinney、Ronacher 还是选它,不是因为 AI 在 Go 上解题多,是因为 Go 语言面小,没有隐式转换、没有跨层异常、没有反射魔法,AI 能干出「意料之外的事」的概率极低。在有人审的世界这叫省心,在没人审的世界,这叫它替代了那个审稿人。Rust 再进一步,编译器直接证明内存安全、无数据竞争、match 穷尽,一整类 bug 在结构上就不可能存在——一个永不疲倦、零成本的机器审稿人。

但 Rust 的好处有个会咬人的前提。微软研究院那个专门修 Rust 编译错误的工具 RustAssistant,峰值准确率 74%——这是把模型和编译器套进循环之后的成绩,已经很高。问题是「报错精确」不等于「容易修」。一个没有 Rust 心智模型的团队,会眼睁睁看着 AI 为了安抚 borrow checker,改 40 个文件去实现一个本该改一两个文件的需求,而且没人看得出哪些改动是必需的。Rust 的真实定位不是「AI 最好用的语言」,是「最适合本来就懂 Rust 的人用 AI 加速的语言」。

语言只是这套权威性的默认配置。Go、Rust 把机器审稿人的地板免费抬高;Python 抬不上去,但可以在编译器本来就不管的那 85% 上——逻辑和集成——用从 schema 跑出来的契约测试、录下来的真实响应、property 测试,把验证器一点点堆到位。判据从头到尾只有一条:哪些错,能被一个 AI 糊弄不过去的机器抓住。

机器审稿人是真的,但管辖范围很窄

把「用机器代替人来审」推到尽头,尽头是一台机器去证明代码对,而不是测它对。这件事在 2025 到 2026 之间,真落地了一部分。

AWS 的 Kani 是给 Rust 用的边界模型检查器,今年 1 月还在更新,已经在 Firecracker、s2n-quic 这些真东西的 CI 里每个 PR 都跑,给内存安全和断言做机器证明。ed25519-dalek 有个 fiat 后端,它的曲线运算是从 Coq 证明里抽出来的——没有人审那段算术,大家信的是那个证明。这就是「工具生成、机器证明、没人读」在密码学里落地的样子。

代价同样具体。一篇实测了 73 个证明的论文给出数字:写一个证明骨架,专家平均要 87 分钟一个。Rust 标准库的众包验证搞了好几年,到现在覆盖不到核心 unsafe 函数的 4%,而且一个安全 bug 都没找到——它交付的是「确信」,不是「抓虫」。

更微妙的是一个反转:证明本身现在反而好自动化了。微软的 AutoVerus 自动生成 Verus 证明能到 91%,难的那部分,变成了写出那份正确的规范。Kleppmann 去年底说得直白——挑战会从「写证明」挪到「写规范」,而读写形式规范,依然要专业判断。

所以「没有人审代码」从来不等于「没有人」。人没消失,是从读 diff 的审稿人,挪到了写规范、定契约、设对照实验的验证器作者。这一步,恰好是我之前写「你是管理者」那篇没讲透的下一层——管理一个 AI 的人,最值钱的动作不是看它写了什么,是定义清楚什么才算对。

Rob Pike 当年给 Go 的定位,是「给那些处理不了复杂语言的人用的」。十几年后,这些「人」换成了 AI,这句话反而更准了。只不过这一次,可读性、好不好上手——过去几十年编程语言界默认的最高价值——正在被重新定价。一门语言对你友不友好,不重要了,反正写代码的不是你。重要的是它对那个每天写几百遍、改几百遍、还得自己给自己盖章的 AI 系统,能不能少留一道、它自己就能糊弄过去的关。

AI 杂谈Part 12 of 13
← PrevNext →

© Xingfan Xia 2024 - 2026 · CC BY-NC 4.0