乐于分享
好东西不私藏

陶哲轩的 AI 考古之旅:AI 智能体怎么从 30 年老代码里挖 bug,还补完了一个 27 年前没做成的项目

陶哲轩的 AI 考古之旅:AI 智能体怎么从 30 年老代码里挖 bug,还补完了一个 27 年前没做成的项目

2026 年 7 月 11 日,陶哲轩发了一篇很有意思的博客。

他没有让 AI 去写一个新项目,而是把自己 1999 年写的 Java 1.0 小程序交给现代 AI coding agent 去迁移,让这些老程序重新在现代浏览器里跑起来。

结果很反常:

一批两打左右的老 applets,在几个小时里就活过来了。

更离谱的是,AI 还顺手找出了两个陶哲轩自己当年都没注意到的 bug。

但我最想写的,不是“AI 会写代码了”。

而是这句话:

AI 现在已经会替你翻旧账了,前提是你知道哪些旧账值得它翻。

先把几个词翻成大白话:

applet = 嵌在网页里的小程序retained-mode = 你描述一次对象,运行时帮你记住并重画immediate-mode = 每一帧都要自己重新画audit trail = 把过程也留下来,方便回放和检查vibe coding = 人描述需求,AI 反复试,人看效果后再调整方向

一、最重要的不是 AI 找到了 bug,而是他先判断了哪些地方可以让 AI 碰

陶哲轩这篇博客最有方法论价值的地方,不是 bug 数量,而是他的风险判断。

他没有把所有代码都当成同一类任务处理。

在他看来,这些 applets 主要是教学和可视化辅助工具,不是数学证明本身。

这意味着什么?

就算一个图形 applet 画错了,最多是展示不对;但如果一个证明出了问题,那就是完全不同级别的事故。

这就是他真正做的第一步:风险分级。

如果一段代码出错,用户能不能马上看出来?能不能手工纠正?后果是不是局部的、可逆的?

如果答案是“是”,那这种任务就适合交给 AI 去反复试。

如果答案是“不是”,比如核心数学论证、不可逆业务、或者会直接影响结果真假的模块,那就不能靠这种方式冒进。

如果把它写成一张工程判断表,会更直接:

模块类型
适合 AI 先动吗
为什么
教学可视化、交互演示
适合
错了能看出来,也容易回滚
内部工具、原型代码
适合
主要成本是维护,不是事故
核心证明、结算、权限
不适合
一旦错了,后果通常不可逆

陶哲轩挑的,就是前两类。

这给工程团队的启发也很直接:

先拿低风险、可观察、可回滚的模块试手,不要一开始就拿最核心的系统开刀。

二、Java 到 JavaScript 难的,不是语言,而是图形和事件的工作方式变了

很多人会把这次迁移理解成:

Java 改成 JavaScript。

这其实低估了难度。

真正难的,不是语法翻译,而是图形模型变了。

1. 旧世界是 retained-mode

Java AWT 这一类老系统,更像是:

你先把“有哪些对象”告诉系统,系统帮你保存这些对象,然后在需要的时候重画。

这叫 retained-mode。

你可以把它理解成“请助手记着这张图怎么长”。

2. 新世界是 immediate-mode

现代 JavaScript 可视化,尤其是 Canvas,更像是:

每一帧都自己重新画,系统不会替你记住图形对象,你得在渲染循环里把它们再画一遍。

这叫 immediate-mode。

你可以把它理解成“每次都重新在白板上画一遍”。

对工程师来说,更准确一点是:

retained-mode 里,你在操作对象;immediate-mode 里,你在操作每一帧的结果。

3. 所以迁移不只是改 API

从 retained-mode 到 immediate-mode,迁移 agent 必须做四件事:

  1. 1. 读懂旧代码里到底有哪些“图形对象”
  2. 2. 把这些对象映射成一帧一帧的绘制命令
  3. 3. 把旧的鼠标监听器改成浏览器的 DOM 事件
  4. 4. 跑起来,再靠实际执行检查有没有画歪

这就是为什么这不是普通翻译。

它是在把“对象记忆型程序”改写成“帧循环型程序”。

如果你把它再往下拆,AI 还得做一件更难的事:从源码里识别“这段程序到底画的是什么”。

很多老 applet 里的绘图调用,不只是装饰,而是在表达一个数学对象、一个几何结构,或者一个状态变化过程。

所以迁移 agent 不能只会把 drawLinefillRect 翻成 Canvas API;它还得知道这些线段、箭头、坐标轴、颜色变化,到底是在表示什么。

否则代码虽然能跑,原来的意义却被你改没了。

对不懂技术的人来说,可以把它理解成:

旧程序像是让系统替你保管一张画,新程序像是每次都要自己重新画一张。

这两种思路完全不同。


三、AI 迁移老代码,做的其实是“行为对齐”,不是“字面翻译”

陶哲轩让 AI 迁移的,不是随便一段文本代码,而是有明确交互行为的老 applet。

所以 AI 真正在做的是四层对齐:

1. 语法层

把 Java 1.0 的写法翻成 JavaScript 能接受的写法。

2. 运行时层

把老 API、老绘图接口、老事件模型,映射到现代浏览器环境。

3. 交互层

把旧系统里的拖拽、点击、松手、失焦这些行为,改成浏览器里的 pointer / mouse / DOM 事件。

4. 行为层

让迁移后的程序不只是“看起来像”,而是“跑起来真的一致”。

这里最难的地方,是交互层和行为层。

比如拖拽一个图形的时候:

鼠标按下后,光标离开窗口怎么办?拖拽过程中坐标要不要做归一化?页面刷新后对象状态怎么恢复?旧浏览器以前默认替你处理的边界,现在谁来补?

这些不是语言问题,而是系统行为问题。

所以 AI 迁移老代码,本质上不是“翻译句子”,而是“翻译一个旧程序的操作习惯”。

更进一步说,它还要在迁移过程中维持原来的语义不变。

也就是说,代码不仅要“能跑”,还要“仍然在讲同一个故事”。


四、为什么迁移过程反而会挖出隐藏 bug

这件事最值得写。

陶哲轩迁移了二十来个老 applets,最后不仅完成了迁移,还顺手发现了原始代码里两个自己以前没注意到的 bug。

原因不是 AI 多神。

原因是迁移本身会强迫系统重新接受一次审计。

老 bug 之所以能活很多年,通常不是因为它聪明,而是因为没人再碰它。

没人再跑没人再对比没人再把默认行为显式化

AI 一旦开始迁移,老代码就被迫重新回答这些问题:

输入是什么状态怎么传事件怎么触发边界条件有没有处理新行为和旧行为是否一致

这就像把一个沉睡很久的机器重新通电。

只要它开始转,之前看不见的卡点就会暴露出来。

这也是为什么视觉类老系统特别适合先迁:

同样的输入,旧版和新版画出来是不是一样?拖拽轨迹有没有偏?边界行为有没有变?

视觉结果天然可比较,所以它能很自然地充当迁移的 oracle。


五、最完整的审计,不只是看代码,还要看 AI 是怎么想的

陶哲轩还有一个很有意思的动作:他把与 AI 的对话记录也公开了。

这意味着什么?

意味着他审计的不只是结果,还有过程。

这很重要。

因为对工程团队来说,AI 最危险的地方往往不是“它最后写错了”,而是“你不知道它为什么会这么写”。

所以真正应该保留的,不只是最终代码,还有:

提问中间尝试失败回退修正原因最终决策

把这些留下来,AI 的“思考过程”才进入可审计范围。

对团队来说,这意味着:

AI 对话记录,不只是聊天记录,它也可以是设计文档的一部分。

更具体一点,实际操作中可以把 AI 对话记录和代码一起提交到仓库,作为 PR 的附属材料。这样不仅代码变了,连“代码为什么变成这样”的过程也被记录了。


六、AI 甚至帮他补完了 27 年前没做成的项目

这次最让我觉得有意思的,不只是修旧。

陶哲轩还借助 AI 完成了一个 1999 年就想做、但当年没做完的狭义相对论可视化项目。

可以把它理解成:

1999 年他有一个想法,但当时复杂度超出了人力范围。2026 年,AI 把这个旧愿望补上了。

这就让这件事不只是“考古”,而变成了“重建”。

AI 不是只在翻旧代码,还在把多年以前搁置的技术愿景重新拉起来。

这比单纯修 bug 更有意义,因为它说明 AI 在某些边界清楚的任务里,已经能从“帮你补一个小问题”,走到“帮你把一整块搁置项目做完”。

更重要的是,这种“补完”不是直接交付成品,而是把原本昂贵的探索压缩成了几小时的高频试错。

很多老项目不是死在“不会做”,而是死在“试一次太贵”。

AI 的价值恰恰在于把这个成本压下来:

原来要两个月才能判断值不值得继续做,现在几个小时就能知道这个方向有没有戏。

七、陶哲轩对 AI 编程的定位,其实很清楚

他并没有把 AI 描述成全能程序员。

更准确的说法是:

高层级的设计决策,人来做;低层级的语法和实现细节,交给 AI 反复试。

这就是他对 vibe coding 的边界理解。

你可以把它理解成一句很实在的话:

AI 负责搬砖,人负责画图纸。

这不是保守,而是分工。

因为真正难的通常不是把代码敲出来,而是知道这段代码应该长什么样、应该解决什么风险、应该在哪个边界停住。

所以它更准确的分工其实是:

人负责定义问题、风险和边界,AI 负责在边界里高频试错。

这也更接近陶哲轩对 vibe coding 的理解:不是随便让 AI 写,而是人通过不断看结果来收窄方向。


八、如果你自己也有老系统,应该怎么用这个方法

如果你们手里也有类似的老系统,我会建议这样下手:

  1. 1. 先挑一个低风险的可视化模块
  2. 2. 用截图和交互脚本把旧行为固定下来
  3. 3. 让 AI 只迁移这一小块
  4. 4. 反复对比旧版和新版的视觉结果
  5. 5. 把对话记录和代码一起作为 PR 材料留档
  6. 6. 稳定以后,再往更核心的模块扩

这套方法最重要的,不是“让 AI 一口气全改完”,而是先把迁移做成一个闭环。


结尾

陶哲轩这篇博客最有价值的地方,不是“AI 找到了两个 bug”。

而是它把一套很实用的方法讲出来了:

先做风险分级,再让 AI 迁移可见、可控、可逆的模块,最后把过程也一起留下来审计。

这才是工程上真正能复用的东西。

给技术负责人的一句话建议:让 AI 动手之前,先判断这个模块的失败后果是不是可见、可控、可逆;如果不是,就不要把它当成普通迁移任务。

参考资料

  • • 陶哲轩博客:old and new apps via modern coding agents[1]
  • • TechTimes 报道:AI agents ported Tao's 27-year-old math code[2]

引用链接

[1] 陶哲轩博客:old and new apps via modern coding agents: https://terrytao.wordpress.com/2026/07/11/old-and-new-apps-via-modern-coding-agents/[2] TechTimes 报道:AI agents ported Tao's 27-year-old math code: https://www.techtimes.com/articles/320238/20260712/ai-agents-ported-taos-27-year-old-math-code-hours-found-two-bugs-he-had-missed.htm