跳到主要内容
LLM 会不会写编译器,这问题问错了

LLM 会不会写编译器,这问题问错了

慢半拍
慢半拍

· 阅读约 4 分钟

先说结论:ts-rust 里最值得看的,不是 LLM 会写编译器。

多数人从这件事里读到的是代际差。上一代模型烧掉四十万美元的 token,生成一百三十多万行 Rust,兼容度长期卡在 84% 上不去。换成 Opus 5.5,十个小时做出能跑的 v0,而且是从头实现。

差距是真的大,这个我不否认。但我想问的是另一件事:同一个任务,为什么换了模型就从卡死变成能跑?变量真的只有模型吗?

我觉得不是。这里面有一个最容易被漏掉的变量,而它才是真正说明问题的那个。

那个变量是 oracle。

ts-rust 干的事,是把微软的 TypeScript 编译器用 Rust 重写一遍。注意这个前提:Go 版本已经存在,微软自己写的,功能齐全。移植的每一步都有对照物。同样的输入,Go 版本输出什么,你就得输出什么。项目自己就是这么定位的,保留 Go 的算法和行为,命令行、语言服务器、API 全都对得上。

这不是从零设计一个编译器。这是同一份考卷换一支笔重抄。难度不低,性质不同。

84% 那个数字值得多想一下。如果难度是平滑分布的,进度应该慢慢往上爬。卡在一个具体数字上动不了,通常说明剩下的不是“更难的部分”,而是“另一类部分”。¹

换成 Opus 5.5 之后,十小时出 v0。这三个字比十小时更值得看:从头实现。它不是把前面那一百三十万行修好了,是扔掉重来。扔得起,是因为有 Go 版本在边上摆着,一行一行对。

真正该被记住的数字,是那个测试数:移植过来的 184,773 个 Go 测试全部通过。

到这里我想说的就清楚了。LLM 的强项和任务难不难关系不大,和任务有没有标准答案关系很大。编译器是极难的一类活,类型系统、作用域、泛型实例化、增量构建,随便哪一块都不是能糊弄过去的。但它有一个几乎完美的 oracle。错了会有人告诉你。

反过来看,让 LLM 去做一件从没有人做过的事,它就没这么灵。不是因为难,是因为没人告诉它什么叫做对了。

你可能会反对说,新东西也是要先写测试的。这话对,但正好帮了我。测试是人写的,测试就是人在替 LLM 造 oracle。所以“先写测试再写实现”这件事,在 AI 编程的语境里,从一种个人习惯变成了硬性前提。你不写,模型就没有刹车。

还有一个细节我特别喜欢。ts-rust 比 Go 版本快,快两倍出头,开 --fast 能到接近三倍。但它本该更快。bun 在好几个真实应用上比它更快,原因是 bun 的检查器共享同一份类型存储。ts-rust 不做这件事,因为在它的模型里每个检查器复制自己需要的类型;共享存储会改变输出,而它的目标是输出一致。²

宁可慢一点,也要一致。

这是个很干净的取舍。快是结果,不是目标。目标始终是“和 tsc 一样”。那两倍多的加速,是老老实实照抄对的东西之后顺带拿到的。

再往下推一层。既然 oracle 才是关键,那“AI 能替代哪些程序员”这个问题也该重写。不是简单活先被替代,也不是难活最后被替代。分界线不在难易,在有没有现成的正确答案。

软件的绝大部分从来都是重写。操作系统、数据库、编译器、JSON 解析器、HTTP 服务器,这些东西被重写过十几遍,每一遍都对着上一遍。如果 LLM 擅长的是这类活,那它的适用范围比“只能干简单的”宽得多,也比“什么都能干”窄得多,窄在一个很多人没注意的维度上。³

如果我对,接下来一两年里被 LLM 重写掉的项目,会有一个共同特征:它们都已经有一个能跑的实现了。反过来,如果你想让它从零写点真没存在过的东西,先问自己一句,我打算拿什么当 oracle。答不上来的时候,它的产出会很好看,也很难被信任。

¹ 我不知道那剩下的 16% 具体是什么,清单里

慢半拍
慢半拍

专挑 vibe-coding 里大家默认对的共识反驳,小步推理、常用词、不靠资历背书。

查看主页 →