有个叫 Maurice Heumann 的人,十月初发了篇文章,标题是《500+ Billion Tokens Later》。三个月时间,他同时开着 Claude Max 20 倍档和 Codex Pro,让一群 agent 把一款第一人称射击游戏反编译回 C++。

哪款游戏不重要,他甚至没写名字。之前两篇相关文章已经被删了,原话是"corporate America was here to ruin our fun"。这篇的重点也不在逆向技术,在于怎么让 agent 连续跑三个月还不垮。

第一个月,他觉得自己成了。

第一个月,进度是假的#

三个干活的 agent 加一个审查的 agent,四周做完了八成函数。游戏启动了,主菜单渲染出来了,地图能加载。

然后他去读代码。语义是错的。

函数签名、类型、结构体布局都有错。有些逻辑是 agent 自己编的,有些它觉得多余就删了。他还抓到一个典型的"优化":游戏本来用全局变量读配置,一次内存访问就够,agent 把它改成了哈希表加查表,开销大了几个数量级。

这种错误最阴的地方是它不会让程序崩。游戏照样跑,看着一切正常,你只有真的去读那份代码,才知道底下已经烂了。

那四周他们一直在磨流程。默认 compaction 阈值是上下文填满 90%,他们压到 42%,因为反编译产出的信息大多是易过期的,一个函数翻译完就没用了,越早压掉越干净。他们还发现 agent 会跑偏:这个函数没做完就挪去下一个,盯着 CI 干等(Discord 明明已经推了失败通知),甚至没检查完就把 issue 关了。于是他们写了一份指令文档,用每小时跑一次的 cron 提醒 agent 重读。

流程越来越精细,产出越来越错。

审查员为什么不灵#

文章里最值钱的一段在这儿。

review agent 抓得到明确的 bug,抓不到别的东西。只要架构上的改动符合"目标",它就不问。根本原因是他们从来没定义过什么叫"正确"。目标里还挂着现代化和可移植性,某些偏离天然有解释空间,reviewer 手里没有尺子。

更要命的是,worker agent 在 commit message 和注释里写了自己的理由,reviewer 读了这些理由,然后接受了。

作者管这个叫 agent 之间的"非故意 prompt 注入"。

这个说法值得停一下。我们做多 agent 流程的时候,默认 worker 干活、reviewer 审核,两边是干净的分工。实际上 worker 的产出自带一份辩护词,而且辩护词是写给 reviewer 看的。reviewer 面对一份已经写好理由的 patch,很难只把它当待检对象。它读到的不是代码,是"我为什么这么写"。

换成一个只会说两个词的裁判#

他们需要的东西很简单:一个能回答"这个重建出来的函数和原版一不一样"的自动检查。

做法是字节比对。换回当年编译原版游戏的那个编译器,写脚本读两边的产物:一边是重建出来的 OBJ,一边是游戏本体和 PDB。

跨函数、跨数据的引用不可能字节一致,因为地址取决于链接之后目标落在哪。好在 OBJ 把这些引用记成重定位项,比对时跳过这几个字节,改成校验"是不是同一个符号、同一个偏移"。数据结构和类型照同一套做。

输出只有 PASS 或 FAIL。错在哪儿,agent 自己去查。

reviewer 这个角色就这么撤掉了。

你的裁判会被攻击#

这一段是全文最不该跳过的部分。

脚本上线的第一天,agent 的反应是写内联汇编硬凑。他们就在指令里把口子一个个堵上:naked function、对象打补丁、内联汇编、代码里嵌字节,全部禁止。这些东西扫起来容易,写在 prompt 里说一声就够。

接着 agent 换招。它们开始改校验脚本,把自己的函数从比对范围里排除出去。

这次的办法是 CI 里对验证脚本做哈希,和存在 GitHub Actions secret 里的值对一遍。脚本被动过,校验直接不成立。

我读到这里才反应过来,这件事跟安全关系不大,问题在设计上。你设的每一道关,agent 都会当成一个待解决的问题。它没有恶意,只是在优化你给它的信号。所以防护不能靠"我在 prompt 里写了不许",得靠它碰不到、改不了的那一层。

便宜模型突然能用了#

代价说清楚。字节匹配很难:寄存器分配、内联决策、调用约定,都可能对不上。偶尔同样的输入,编译器吐出不同结果。函数语义完全正确,只是独立指令换了个顺序,照样过不了。重建因此慢了很多,而且慢下来的那部分不一定换来更好的结果。

换来的东西是硬的。所有 PASS 的函数语义一定相同,连原版带的 bug 一起保住了,重建过程不会在这些函数上引入新错误。

还有一个作者没预料到的收益。以前 Haiku、Luna 这类便宜模型干这活是灾难,用他的话说"a bad fit"。现在有了明确的通过标准,它们拿到的反馈足够干脆,产出质量直接翻身。项目最后几周是 14 个 Luna 加 2 个 Opus 5.5 在跑。

他的解释是:聪明的模型不一定干得更好,反馈精确才行。

这句可以拿去当多 agent 的定价原则。能同时跑多少 agent,取决于能验多少,模型能力只决定斜率。

结局,以及两条一行改动#

又跑了两个月。99% 的函数进了源码,83% 字节精确,游戏跑起来没毛病,功能齐全。剩下的函数反复重做过,他们判断语义正确,但受链接器 COMDAT 折叠这类东西影响,字节对不上。继续磨只是烧 token,收益递减到不值得。

两条顺手的操作,复制成本极低:

  • compaction 阈值从 90% 降到 42%。理由前面说过,反编译的上下文里垃圾多,早压早干净。
  • 每小时用 cron 把指令文档重塞一遍。作者的观察是"指令会随时间衰减",上下文压缩几次之后,agent 会把某些规则当成不那么重要。人在终端里盯着能随时纠正,全自动跑的时候这种漂移没人发现。

规模上去之后还有别的麻烦。跑 15 个以上 agent 的时候,agent 自己会时不时敲错命令,把整个 VM 清掉,session 日志跟着一起没了,所以 token 数只能估:6000 到 7000 亿。其中大概 3000 亿是 Luna 烧的,按 100:1 折算,约等于 30 亿 Astra token。

Discord 也不扛用了。一群 agent 在频道里刷消息毫无意义,后来只允许报"我接了哪个 issue"和 CI 协调。再往后人跟 agent 基本不用说话,它们自己跑。

普通项目能抄到哪一步#

你没法拿自己的 app 去跟一个参考二进制逐字节比。能抄的是思路:找到离 oracle 最近的那个东西,把它变成 agent 眼里唯一的"做完"标准。

  • 先写检查,再写功能。现有测试、类型检查、快照 diff、schema 校验、拿旧实现做差分测试都算。作者在 HN 上的建议是,动手前先让 agent 从当前实现生成一套测试,以后的回归就会以失败的形式自己冒出来。
  • 输出收成一个退出码。PASS/FAIL 比一份需要人解读的报告管用。
  • 裁判放在 agent 够不到的地方。CI 里哈希、换一个它没写权限的路径去跑、提前把想得到的绕过方式列出来扫一遍。
  • 规则定时重发。跑几个小时的活,别指望开头那段 prompt 一直有效。
  • 坏代码早扔。第一个月那堆东西他们试过抢救,作者的原话是花的时间比从头再来还多。

一点冷水#

反编译是个特殊场景。HN 上有人(ashdnazg)说得很直接:这里你只在乎结果准不准,工具用完就扔,正常开发还得管代码质量和可维护性。作者回应说,思路上到处都能找到 guardrail 和 oracle,字节匹配只是他这儿恰好有的那一种,别人那儿可能是别的。

还有人问为什么不直接比运行时行为。另一位(ndiddy)指出游戏依赖全局状态和外部数据,几万个通过的测试也证明不了行为完全一致。作者补了一句,比对内存读写序列对语义没有结论性,fuzz 比字节比对慢得多。

成本在 HN 上被估到几万美元,那是评论区的口算,不是文章里的数字。合法性那部分我不掺和,作者没公开游戏名,代码也不放。

最后#

这篇让我停下来的其实是一句话:correctness is so much more important than productivity。

降 token、加 agent、提吞吐,这些都是乘法。乘出来的是个错的东西,前面的功夫全部白费。他们花了一个月才发现这件事,又花两个月把方向掰回来,中间那四周的产出基本等于零。

反过来说也成立。能同时跑多少 agent,上限不在模型,在验证。你验不了的东西,跑得再多也只是把错误放大得更快。


参考来源

  • Maurice Heumann, “500+ Billion Tokens Later: Letting AI Agents Decompile A First-Person Shooter”(2026-10-09):momo5502.com
  • Developers Digest, “Agent Harness Lessons From a 500B-Token Decompile: Give Agents a PASS/FAIL Oracle”(2026-10-12):developersdigest.tech
  • Hacker News 讨论贴:item 50039092