跳到正文
RadarAI· Hacker News:AI 热帖·· 7 天前AI 评分71

用 500B tokens 让 AI 智能体反编译一款第一人称射击游戏

AI 导读

作者用 Claude Max 与 Codex Pro 的多智能体编排,历时约 3 个月、估计消耗 600-700B tokens,将一款热门第一人称射击游戏反编译为 C++,最终 99% 函数重建完成、83% 字节级精确,游戏可完整运行。

正文 · AI 翻译

Hacker News:AI 热帖· davikr·2026-10-11 10:02· 2 小时前AI 评分71

500B Tokens Later:让 AI 智能体反编译一款第一人称射击游戏

AI 导读

作者用 Claude Max 和 Codex Pro 的多智能体编排,历时约 3 个月、消耗估计 600-700B tokens 将一款热门第一人称射击游戏反编译为 C++,最终 99% 函数重建完成、83% 字节级精确,游戏可完整运行。

正文

在过去的 3 个月里,我花了一些时间和 token 反编译了一款热门第一人称射击游戏。 目标并不是达到一个简单的概念验证状态。 相反,我们真正想要的是对这款游戏进行准确、稳定且功能完整的复刻。

我博客的忠实读者可能已经注意到,我之前写过两篇文章,但后来都被删除了。 其他人现在可能想知道我说的是哪款游戏。 对你们两位,我只能说,美国企业界跑来毁了我们的乐趣。

不过,这没关系。这篇文章不是关于这款游戏的,也较少涉及反编译的过程。 它更多是关于 AI 编排,以及如何优化基础设施、设置和工具链以获得最佳结果。

这个项目是在 RektInator、Future、st0rm 以及社区其他成员的帮助下完成的。非常感谢他们所有人。

我们的目标是什么?

我们的目标是将游戏准确地反编译为 C++。 除了显而易见的语义正确性之外,我们还有不少其他要求: 我们想要可编译、可读的 C++ 源代码。 考虑到这款游戏有多老,我们还想要安全性和错误修复,同时也想要可移植性改进。能在 Linux、macOS、浏览器上运行这款游戏就好了……

后来我们推迟了现代化和可移植性工作,完全专注于重建原始行为。

显然,总体目标是学习如何在数月的时间里有效地编排自主 AI 智能体。

初始设置

我们从 Claude Max(20x)开始,然后加入了 Codex Pro,并同时使用这两个订阅。 模型选择变化很大。我们大部分时间都在使用 Sonnet 5,但 Opus 5.5、Luna、Sol 和 Terra 也用得很多。 稍后会详细说明。

Claude agents 在 Claude Code CLI 中运行,Codex agents 在 Codex CLI 中运行。 我们还尝试了其他 agent harness,但选择几乎无关紧要,所以我们坚持使用默认配置。

进度跟踪

使用 GitHub CLI,agents 管理 GitHub issues 来跟踪它们的进度。 每个翻译单元(.cpp 文件)对应一个 issue。 此外,标签有助于对 issues 进行分组和优先级排序。

沟通

Agents 通过 Discord 进行沟通。 它们都可以访问同一个频道,并且可以在其中发布和阅读所有消息。

Discord 允许 agent 对 agent 的沟通,以及人类对 agent 的沟通。 因此其他参与者可以与它们交谈,而无需机器访问权限。

一个 GitHub webhook 将 CI 失败发布到共享频道,因此 agents 会在出现问题时收到通知。

反汇编与反编译

Agents 几乎全程使用 Hex-Rays 官方的 ida-mcp。 它运行得非常好。它超级稳定,是无头模式,并支持这个项目所需的一切。我只能推荐它。

第一个月

当时我们有 4 个 agents 在运行。

3 个 worker agents 进行反编译并提交,以及一个 reviewer agent 被动协调和审查提交以标记 bug。

Agents 成功反编译了大约 80% 的游戏,并取得了可见的进展。 游戏启动了,主菜单可见,我们能够加载地图。

我们在这 4 周里花了很多时间优化我们的设置:

我们通过更早触发压缩来减少 token 消耗。
默认的压缩阈值是上下文填充到 90%。我们把它降到了 42%。 反编译涉及大量易变信息:一个已经反编译过的函数现在已无关紧要,可以从上下文中移除。因此,更早的压缩有助于从上下文中清除这类“垃圾”。

我们还注意到,智能体会随着时间推移而失去专注。即使在单个压缩周期内,随着上下文承载的数据增多,智能体也会漂移并失去专注。

智能体有时会在完成前一个函数之前就转向另一个函数。它们还会在盯着 CI 时开始空转,尽管在 Discord 上收到了失败通知。偶尔,它们会在没有彻底检查工作是否真正完成的情况下就关闭 issue。

在终端中并肩工作时,你可以引导智能体来防止这种情况,但当让它们自主工作时,就无法进行引导了。

为了防止这种情况,我们写了一份文档,定义我们的目标、智能体应如何工作、必须避免什么以及如何处理特定情况。

一个每小时运行的 cron 任务会自动注入请求,让智能体重新阅读这份文档,使指令在它们的上下文中保持新鲜。虽然这可能不是让智能体保持专注的理想方法,但它在项目结束前一直效果很好。

大量时间花在了完善这份指令文档上。不过,由于内容极其针对这个项目,在这里分享它意义不大。

然而……

……尽管我们在优化设置和基础设施上付出了所有努力,我们还是得谈谈工作质量。

持续的进展(游戏启动、菜单渲染、地图加载)让我们相信反编译的质量很棒。

事实并非如此。尽管代码极其可读,但它在语义上是错误的。

智能体使用了错误的函数签名、类型或结构体布局。 它们凭空编造逻辑,或在认为不必要的地方删除了逻辑。

除了语义错误之外,智能体还引入了不必要的架构变更。 举个例子,游戏有一些配置变量,它通过全局变量来访问。 智能体把这种常量内存访问变成了哈希表查找,而查找的开销要高出几个数量级。

而这只是众多出错事项中的一个例子。

为什么会这样?

虽然审查者有助于发现 bug,但除此之外就不好用了。 只要架构决策与目标一致,就不会受到质疑。

主要原因是我们没有客观的验收标准。 我们从未正确定义“正确性”。因此审查者很难判断哪个改动是正确的,哪个是错误的。

显然,它以游戏作为参考,但考虑到我们还将现代化和可移植性列入了清单,某些偏差就不被视为 bug 了。
有趣的是,提交或代码中的注释让审查者接受了这些偏差,因为工作智能体写下了某种理由。工作者的注释实际上起到了无意的提示注入作用:审查者接受了它们的理由,而不是独立地将偏差与原始版本进行核对。

The Oracle

我们需要的是一个自动化检查,用来告诉智能体重建的函数是否与原始函数匹配。它应当验证语义完全相同。一个简单的 PASS 或 FAIL 信号就足够了,智能体可以自己弄清楚哪里出了问题。

字节匹配反编译

实现这一目标最简单的方式是字节匹配反编译。

我们切换到了构建原始游戏所用的编译器,并编写了一个执行比较的脚本。

该脚本读取我们重建的 OBJ 文件和游戏 EXE/PDB(拥有 PDB 很好,能让事情稍微简单一些,但没有 PDB 这个过程也能正常工作)。

然后它从 OBJ 和 EXE 中提取函数数据并比较所有字节。 如果匹配,该函数就是精确的,否则失败,智能体需要重做该函数。

对其他函数或数据的引用不一定逐字节匹配,因为它们的编码值取决于目标最终在编译后二进制文件中的位置。

幸运的是,OBJ 文件将这些引用记录为重定位。我们可以从直接比较中排除重定位字节,转而验证两个版本是否引用了相同的符号和相同的偏移量。

然后脚本对数据和类型做同样的处理。

智能体随后可以使用这个脚本在推送之前验证他们的工作。

重建的函数记录在一组文本文件中。 CI 随后可以使用这些文本文件来验证所有记录的函数,并在出现回归时发出警报。

作弊

当我们引入这个脚本后,智能体做的第一件事就是编写内联汇编。

这显然违背了初衷。因此我们不得不细化指令,禁止某些构造。裸函数、对象补丁、内联汇编以及在代码中嵌入字节都被口头禁止了。 考虑到扫描这些构造非常容易,口头规则就足够了。

然而,智能体反复试图修改这个脚本,以将他们的函数排除在比较之外。

为了防止他们这样做,CI 会对验证脚本进行哈希,并与存储的 GitHub Actions secret 进行比较。

权衡

缺点

函数可能很难匹配。寄存器选择、内联决策和调用约定可能难以精确复现。在极少数情况下,我们还观察到相同输入产生不同的编译器输出。 智能体现在反编译需要长得多的时间,却不一定能产生更好的结果。一个函数可以具有相同的语义,尽管表现出某些差异,例如被重新排序的独立指令。

优点

匹配的函数保证具有相同的语义。 这保留了原始行为,包括任何现有的 bug,并防止这些函数中出现重建错误。 除此之外,不再需要审查智能体。

另一个好处是,更便宜、能力更弱的模型现在也能可靠地完成这项任务。 以前像 Haiku 或 Luna 这样的模型并不合适,会产生极其糟糕的结果。然而,鉴于这种严格的验收标准,它们现在有足够的反馈来产生令人难以置信的结果,从而大幅降低成本,并使项目能够大规模扩展。

最终状态

有了我们新的验证框架,智能体们又工作了将近 2 个月。 游戏 99% 的函数都存在于我们重建的源代码中,其中 83% 的函数是字节精确的。

在最后几周里,我们大部分时间一直在使用 14 个 Luna 和 2 个 Opus 5.5 智能体。

在那个规模下,工人们使用独立的分支,并通过拉取请求提交他们的更改。

这也是 Discord 不再能良好扩展的地方。那么多代理在频道里刷屏毫无意义。 我们限制了消息,只允许讨论它们正在处理哪些问题以及 CI 协调。这样就把沟通降到了最低。 然而,项目推进得越深入,我们就越不需要与代理交谈。人类与代理之间的沟通不再必要,因为它们已经完全自主地工作。 对于那个规模的其他项目,我可能会选择 Discord 之外的其他工具。

此时,我们正遭遇收益递减。剩余的函数大多具有某些非确定性特征,或者由于其他情况而无法匹配,例如链接器中相同的 COMDAT 折叠,我们无法可靠地复现。

Opus 5.5 代理仍然能够继续推进,并让剩余的函数匹配。不过,游戏现在运行得完美无缺。没有明显的 bug,原版游戏的所有功能都已具备。

剩余的函数已被反复重写。虽然它们仍然无法逐字节匹配,但我们相信它们的语义是正确的。

继续对它们进行字节匹配会消耗更多 token,却不会对结果有实质性的改善。 这意味着,该项目现在可以视为完成了。

经验教训

这个项目教会了我们很多。以下是最有价值的收获一览:

  • 精确的指令是必要的。如果任务留有解释空间,代理就会有作弊的倾向。

  • 正确性应当被定义并且可由机器检查。人类出了名地无法精确表达自己的意图。因此,我认为仅靠审查者永远不够。一个能给出客观 PASS 或 FAIL 信号的可靠验证框架,是代理能得到的最好反馈。显然,并非每个项目都有反编译这样的条件。然而,我认为只要有足够的创造力,每个项目都有可能接近这一点。

  • 指令会随时间衰减。时间越久、上下文被压缩得越多,代理就会遗忘某些规则或将其视为不那么重要。在交互式工作中,你可以在偏差发生时纠正它。当代理自主工作时,这种偏差可能不被察觉,并损害其工作质量。每小时刷新指令解决了这个问题。

  • 现在生成代码很便宜。如果代码不好,就扔掉它。在最初 4 周之后,当我们注意到代码很糟糕时,我们试图挽救它。这实际上比从头开始花费了我们更多时间。

  • 正确性远比生产力重要。减少 token 消耗、扩大代理规模、优化代理吞吐量等等固然很好,但如果结果很糟糕,那也帮不上什么忙。

最后的话

老实说,这是一个非常有价值的项目,我学到了很多。 我认为把这些收获写下来,无法传达我们在整个过程中学到的海量经验。

有那么多事情出了错,但也有那么多事情做对了。随着 AI 代理承担更多的软件开发工作,编排它们成为人类一项新的、要求高得多的任务。

扩展到 15 个以上代理时,暴露出更多困难。代理会因格式错误的命令而周期性地清空虚拟机。 Windows 上已有沙箱解决方案,但我目前见过的都不符合我的需求。我已开始扩展 Sogen——我的用户态模拟器——以提供轻量且可扩展的沙箱能力。不过,要让它哪怕勉强达到生产可用,也还需要一段时间。

由于虚拟机被清空,我们不幸丢失了大量会话日志。所以我并不知道确切消耗了多少 token。 我估计在 6000 亿到 7000 亿 token 之间。

出于显而易见的原因,不会分享任何代码。一切都会保持私密,我只将其用于自己的需求。

来源:Hacker News:AI 热帖 · momo5502.com

来源:RadarAI · aihot.news