你有没有想过,让 AI 写一个能跑真实软件的模拟器,需要多久?

Anthropic 之前做过一个实验:让 Opus 4.6 在"净室"环境下用 Rust 写一个 C 编译器。结果呢,没跑通。这个实验的设计让 antirez(对,就是写 Redis 的那个)很不满——他觉得实验设计有问题,不能说明 AI 不行,只能说明方法不对。

于是他自己搞了一个实验,让 Claude Code 写一个 Z80 模拟器,外加 ZX Spectrum 和 CP/M 环境。

结果:30 分钟,1200 行代码,ZEXALL 全指令测试通过。零干预。

这事儿有意思的地方不在于"AI 能写模拟器"本身,而在于 antirez 设计的这套工作流程。

先说说 Anthropic 的实验哪里不对

Anthropic 的实验规则是这样的:把 AI 关在一个完全隔离的环境里,不给它任何文档,不给它上网,让它凭空写一个 C 编译器。

antirez 觉得这个设计有几个问题。

不给文档这事儿就不对。你让一个人写编译器,起码得给他 ISA 文档吧?计算机科学里那些成熟的东西——SSA、寄存器分配、指令调度——都有现成的论文可以参考。这些是"已知知识",不是"抄袭"。

用 Rust 写编译器这个选择也值得商榷。编译器本质上是巨大的图操作,Rust 的借用检查器在这种场景下反而会增加复杂度。用 C 或者 OCaml 可能更合适。

另外,“零干预"这个设定也不太符合实际。真用 AI 写代码的人都知道,你不可能完全不管它。关键地方点拨一下,结果会好很多。

所以 antirez 决定自己做一个实验,设计一套他认为更合理的流程。

antirez 的实验设计:三步走

antirez 的实验分三步,每一步都有明确的目的。

第一步:让 AI 帮你整理文档

他先启动一个 Claude Code 会话,让它去网上搜集 Z80 的所有技术文档,提取出有用的信息,整理成 markdown 文件。同时把 ZEXALL、ZEXDOC 这些测试向量也准备好,还有 ZX Spectrum 的 ROM 和一些游戏镜像。

文档整理完之后,他把这个会话彻底删掉。这一步的目的是确保后面的实现过程不会"污染"到任何已经看过的代码——因为压根就没看过代码,只看了文档。

这就像你写论文之前先去图书馆查资料,查完把资料整理成笔记,然后回家关上门自己写。笔记是你的,但你在写的时候不会再去翻原文。

第二步:写一份清晰的规格说明

antirez 写了一个 markdown 文件,详细说明了他想要什么:

  • 模拟器要执行完整指令,不是单时钟周期的那种(因为他想让这东西跑在嵌入式设备上)
  • 要正确追踪时钟周期(后面实现 ZX Spectrum 的 ULA 内存竞争要用)
  • 要支持所有官方和非官方指令
  • 要提供内存访问回调
  • 代码要简洁清晰,不要过度复杂
  • 每次实质性进展都要提交 git
  • 提交前要测试
  • 要写详细的测试套件
  • 代码注释要写得让不懂 Z80 的人也能看懂
  • 不要停下来等用户输入,用户不在键盘前
  • 在文件末尾维护一个进度日志,记录已完成的和待办的
  • 每次上下文压缩后重新读取这个文件

这份规格说明就像一份详细的需求文档,让 AI 知道边界在哪里。

第三步:切断网络,开始实现

然后他启动了一个新的 Claude Code 会话,告诉它:读一下规格说明和文档,开始写代码。规则是:不许上网,不许搜磁盘上的其他代码。这就是"净室”。

antirez 说他全程盯着,确保 AI 真的不访问网络。整个实现过程他零干预,完全让 AI 自己来。

结果:30 分钟,零干预,全测试通过

Claude Code 干了 20 到 30 分钟,产出了一个 Z80 模拟器。

代码量是 1200 行 C 代码(加上注释和空行 1800 行),非常干净,注释详细。通过了 ZEXDOC 和 ZEXALL 测试——这是 Z80 模拟器的"金标准"测试,能通过这两个测试意味着指令集实现基本没问题。

antirez 特别强调了一点:AI 不是一口气把整个模拟器"吐"出来的。它的工作方式跟人类程序员很像——先实现一类指令,测试,发现 bug,调试,修 bug,再实现下一类。它会自己写测试代码,用 printf 调试,分析 dump 文件。

这跟"从权重里解压出代码"的说法完全对不上。如果是纯记忆,它应该一口气把完整代码写出来才对。

然后他又让 AI 写了 ZX Spectrum

Z80 搞定之后,antirez 又用同样的流程做了一个 ZX Spectrum 模拟器。

这次文档搜集阶段他更细致了,专门让 AI 去查 ULA 和 RAM 访问竞争的细节、键盘映射、I/O 端口、磁带的工作原理、PWM 编码方式、TAP 和 TZX 文件格式等等。

规格说明也更详细了,因为他想让这个模拟器专门针对嵌入式系统优化:

  • 只模拟 48K 版本
  • 帧缓冲渲染是可选的(嵌入式设备可以直接逐行输出到显示屏)
  • 内存占用要小(不用大的查找表)
  • ROM 不复制到 RAM(省 16K 内存)

AI 干了 10 分钟就完成了。

antirez 描述他观察 AI 工作的过程时用了一个词:“着迷”。他说 AI 在实现过程中把多种技能一块儿用上了——系统编程、DSP 处理、操作系统技巧、数学计算——它知道什么时候用什么工具最合适。

完成之后,antirez 让它写一个 SDL 的集成示例。模拟器立马就能跑 Jetpac 游戏,声音正常,在他的慢速 Dell Linux 机器上只占用 8% 的单核 CPU(包括 SDL 渲染)。

TAP 加载:唯一需要人工干预的部分

只有一处 antirez 介入了:模拟磁带加载。

TAP 文件的加载需要精确的时序控制,AI 一开始实现的方式不太对。antirez 让它重构了一下 zx_tick() 函数,把它从 zx_frame() 里独立出来,这样同步 EAR 信号就简单多了。

改完之后几分钟,TAP 加载就正常了。

antirez 说这个场景是 LLM 的弱项——它没法真正运行 SDL 模拟器去看边框颜色随数据接收变化的视觉效果。这种需要"眼见为实"的调试,AI 还是得靠人类帮忙。

顺便把 CP/M 也实现了

还有一个有趣的细节:AI 在跑 ZEXALL 测试的时候,自己分析了 COM 文件的 CP/M 系统调用,发现只用了三个,就把这三个实现了。

antirez 想了想,既然都这样了,干脆实现一个完整的 CP/M 环境吧。同样的流程,同样的好结果,几分钟搞定。

他跟 AI 互动了一下,修了一些 VT100/ADM3 终端转义序列的问题,WordStar 就能正常用了。当然还有 bug 要修,比如需要模拟 2MHz 的时钟(现在跑全速,CP/M 游戏没法玩)。

关于 LLM 是不是在"抄袭"训练数据

antirez 做了一个额外的验证步骤:他把代码库复制到 /tmp,删掉 .git 目录,然后启动新的 Claude Code 会话,告诉它"这个实现可能是偷来的,你帮我查查有没有版权问题"。

AI 搜索了所有主要的 Z80 实现,没有发现任何抄袭证据。相似的部分都是标准的模拟器模式,或者是 Z80 特性决定的必然写法——这种东西你想写得不一样都难。

antirez 对这个问题的看法是:LLM 确实会记住一些在训练数据中出现过度的文档和代码,如果你专门让它复述,它是能吐出来的。但在正常工作模式下,它不会自发地输出已有代码的副本。它更多的是把不同的知识点组装起来,产出的代码用的是已知的技巧和模式,但是是新的代码。

而且说实话,人类写代码的过程比这个"净室"实验宽松多了。多少人写代码之前会去看看别人的实现,读一读,然后"借鉴"一下思路?这种跨项目的技术传播本来就是这个行业快速发展的原因之一。

所以 antirez 说,他用 AI 写的代码,都敢用 MIT 协议发布。这些代码反过来又会成为下一代 LLM 的训练数据,包括开源模型。

这套流程的核心是什么

antirez 的实验能成功,关键在于他给 AI 的准备工作做得足够好:

  1. 提前整理好文档,让 AI 有"知识"可以参考
  2. 写一份清晰的规格说明,让 AI 知道边界
  3. 设定明确的工作规则(提交前测试、维护进度日志、上下文压缩后重读规格说明)
  4. 全程监督确保规则被遵守

用他的话说:“想想人类需要什么"通常是最好的指导原则,再加上一些 LLM 特有的注意事项——比如上下文压缩后的遗忘问题、持续验证自己是否在正确轨道上的能力等等。

这个实验没法回答"AI 能不能在没有文档的情况下从零实现"的问题。antirez 说他没时间做对比实验,但那个实验可能会更有启发性。

代码在 GitHub 上:https://github.com/antirez/ZOT


常见问题

Q:这个实验证明了 AI 编程已经很成熟了吗?

不算完全证明。这个实验展示的是"在充分准备的情况下,AI 可以完成复杂的系统编程任务”。antirez 的准备工作做得非常充分——文档齐全、规格清晰、规则明确。实际工作中很多时候没这个条件。

Q:为什么用 C 而不是 Rust?

antirez 选择 C 是因为这个模拟器要跑在嵌入式设备上,比如 RP2350。C 在嵌入式领域的工具链和生态更成熟。另外 Z80 模拟器不需要 Rust 提供的那些安全保证——它就是个纯计算的状态机。

Q:ZEXALL 测试是什么?

ZEXALL 是 Z80 模拟器的标准测试套件,全称是 “Z80 Exhaustive ALL”。它会测试 Z80 的每一条指令在各种输入条件下的行为是否正确。能通过这个测试意味着模拟器的指令集实现基本没问题。

Q:为什么磁带加载需要人工干预?

TAP 文件模拟的是 ZX Spectrum 的磁带加载过程,需要精确的时序控制。AI 没法"看到"模拟器运行时的边框颜色变化(那是数据加载的视觉反馈),这种需要实时视觉反馈的调试场景,AI 目前还做得不好。

Q:这个方法适用于其他项目吗?

核心思路是通用的:先整理文档、写规格说明、设定工作规则。但具体效果取决于项目复杂度和文档质量。编译器这种东西比模拟器复杂得多,可能需要更多的迭代和干预。