没人审 AI 写的代码之后,语言该怎么选
过去半年,技术圈反复在吵同一件事:让 AI 写代码,到底该用什么语言。说 TypeScript 的、说 Python 的、说 Rust 的都有。理由也都听着有道理:类型系统能管住 AI 不乱来,AI 在 Python 上训练得最多、写得最熟,Rust 编译器严到「只要过编译就几乎没 bug」,等于白送一个自动审查员。不过这些说法默认的是同一件事,哪门语言 AI 写得最熟、最不容易错,哪门就最适合。我只能说,这个默认我现在挺怀疑的。
SWE-bench Multilingual 这个 benchmark,让 AI 自己改代码、自己跑测试,Rust 的解题率是 58%,所有语言里最高。换到 Multi-SWE-bench,同样让 AI 跑完整循环、同样用 claude,Rust 掉到 16%,连 Python 的三分之一都不到。同一门语言,同一个模型,两个 benchmark 差出三倍多,我第一次看到的时候觉得挺离谱的。这两个都是正经 benchmark,都在真实仓库里跑完整的「写—编译—改」循环,还能差这么远,说明问题多半不在语言身上,在测量方法本身。
一次交卷的准确率,量错了东西
2022 年有个研究叫 MultiPL-E,把一套 Python benchmark 翻译成 18 种语言,专门测 AI 一次性把代码写对的概率。结论挺反直觉的:静态类型存不存在,对一次写对几乎没有影响,统计上「既不帮忙也不碍事」。不过这个结论有个前提,它测的是一次交卷。真实开发里 AI 不是写完就走的,它要写、要编译、要读报错、要改、要再编译、要跑测试,整个是一个循环,一天转几百圈的那种循环。
从循环这个角度看,Go 就冒出来了。pandas 的作者 Wes McKinney 用了一年多 claude code,新项目全转去 Go,他给的理由很具体:瓶颈变了,测试套件跑多快、编译多快,现在比一门语言写起来爽不爽重要得多。Flask 的作者 Armin Ronacher 自己出来做 AI 产品,后端也选了 Go,他说 Go 的 test cache 对高效的 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% 的严重安全漏洞是内存安全问题——但这个 70% 只在 C/C++ 里成立。像 FastAPI 那种胶水服务,没有手动内存管理,也没有共享内存并发,这一整类漏洞直接就是零。连密码学都类似:MIT 统计过 269 个密码学 CVE,83% 是应用层把库用错了,证书没校验、随机数太弱、密钥写死在代码里,只有 17% 出在库本身。这又是一类编译器够不着的错。
所以「换 Go/Rust 就更安全」这个说法,对胶水代码基本不成立。胶水代码的主要 bug 是逻辑错和集成错,哪门语言的编译器都抓不到。换语言能动的顶多是那 15% 一档。剩下的 85%,在哪门语言里都得靠测试。
AI 自己写测试给自己盖章,这事不成立
接下来是把人从审查位置上拿掉之后,最容易踩进去的坑。没人审代码了,那顺手让 AI 自己写测试、证明自己写的代码是对的,不就行了吧?麻烦在于,测试和代码出自同一个模型,审查员和被审的是同一个人。这个事软件工程里早有名字,叫 oracle problem(验证器问题)。Barr 那篇被引上千次的综述里讲得挺清楚:一个从代码本身推导出来的检查器,它的权威性只等于它跟被测代码的独立性。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 能不能把它糊弄过去。
那什么样的检查 AI 糊弄不过去呢?最硬的是数学。Freivalds 算法验证矩阵乘法,靠的是一个线性代数恒等式成不成立,AI 编不出一个假的数学等式。这也是为什么密码学、数值计算这类核心,是少数几个真敢让 AI 全自动跑的地方,它的对错锚在 AI 没参与定义的数学上。往下一档是外部现实:第三方接口真实返回了什么、一份 schema 规定了什么、一段从生产环境录下来的真实响应,AI 改不了外面的世界。再往下是差分对照,拿第二个独立写的实现去对答案,两个各自独立犯的错很少撞成一样。再往下才是人写的规范,比如「余额永远不能为负」这一句,这也是人留在循环里的唯一位置——身份是规范的作者,不是逐行读 diff 的审查员。编译器单独算一档,权威来自语言语义,很硬,但它只管安全那几类性质,不管逻辑。最弱的就是 AI 给自己代码写的测试,那是个圈,没有权威可言。
这里还有个经常被忽略的工具,我觉得挺值的:往代码里塞一个个小改动,逼着测试集去把它们抓出来,这个东西叫 mutation testing(变异测试)。覆盖率 80% 的绿条可能什么都没证明,但 mutation 分数高,说明测试真的在约束行为。没人读代码的时候,它是唯一能不靠人就查出假验证器的办法。
回到 Go 和 Rust,这下能说清它们各自到底好在哪了。Go 在 benchmark 上解题率其实不高,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 test。判据从头到尾就一条:哪些错,能被一个 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 糊弄不过去的验证器。其他的,说实话都挺次要的。