5000亿Token之后:让AI智能体反编译一款第一人称射击游戏

Hacker News Top 新闻

摘要

一位开发者详细介绍了一项历时3个月的项目,该项目使用数千亿个Token以及由自主AI智能体(Claude和Codex)组成的集群,将一款热门的第一人称射击游戏完整反编译为可准确编译的C++代码。文章重点介绍了智能体的编排方式:使用GitHub Issues跟踪进度,使用Discord进行智能体间通信,使用ida-mcp进行反汇编,以及针对运行框架的优化,例如降低压缩阈值等。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/10/11 03:36

# 5000 亿 Token 之后:让 AI 代理反编译一款第一人称射击游戏 原文:https://momo5502.com/posts/2026-10-09-game-decompilation/ 在过去三个月里,我投入了一部分时间和 token 来反编译一款流行的第一人称射击游戏。目标并不是做一个简单的概念验证。我们真正想要的是一个精确、稳定且功能完整的复刻版本。 博客的老读者可能注意到我之前写过两篇文章,但后来都被删除了。其他人现在可能也在猜我说的是哪款游戏。对你们俩我只能说,美国企业界出手毁了我们的兴致。 不过没关系。这篇文章不是关于游戏本身,也不太侧重于反编译过程。它更多地是关于 AI 编排,以及如何优化基础设施、环境和测试框架以获得最佳结果。 这个项目是在 RektInator (https://x.com/RektInator)、Future (https://x.com/RisottoNeroHit)、st0rm (https://x.com/NamelessNoobs) 以及社区其他成员的帮助下完成的。非常感谢他们所有人。 ## 我们的目标是什么? 我们旨在将游戏精确反编译为 C++。除了明显的语义正确性之外,我们还有不少额外要求:我们想要可读的、能编译的 C++ 源代码。鉴于这款游戏年代久远,我们也想要安全性和 Bug 修复,以及可移植性方面的改进。能在 Linux、macOS、浏览器上运行游戏会很美妙。 后来我们推迟了现代化和可移植性工作,专注于还原原始行为。 显然,整体目标是在数月的时间里学习如何有效地编排自主 AI 代理。 ## 初始设置 我们从 Claude Max (20x) 开始,后来加入了 Codex Pro,同时使用两个订阅。模型选择变化很大。我们大部分时间使用 Sonnet 5,但 Opus 5.5、Luna、Sol 和 Terra 也被大量使用。稍后再详细说。 Claude 代理运行在 Claude Code CLI 中,Codex 代理运行在 Codex CLI 中。我们也尝试了其他代理测试框架,但选择影响不大,所以就沿用了默认设置。 ## 进度追踪 代理们使用 GitHub CLI 管理 GitHub issues 来追踪进度。每个翻译单元(.cpp 文件)对应一个 issue。此外,标签帮助对 issues 进行分组和优先级排序。 ## 通信 代理通过 Discord (https://www.datacamp.com/tutorial/claude-code-channels) 进行通信。所有代理都能访问同一个频道,可以在其中发布和阅读所有消息。 Discord 支持代理之间的通信,以及人与代理之间的通信。其他参与者可以直接与代理对话,无需机器访问权限。 GitHub webhook 会将 CI 失败信息推送到共享频道中,这样代理就能在某些功能出问题时收到通知。 ## 反汇编与反编译 代理在整个过程中几乎一直使用 Hex-Rays 官方的 ida-mcp (https://github.com/HexRaysSA/ida-mcp)。效果非常好。它极其稳定,支持无头运行,并且支持本项目所需的一切功能。我只能推荐它。 ## 第一个月 当时我们有 4 个代理在运行。 3 个工作者代理负责反编译和提交,1 个审查者代理被动协调和审查提交以标记 Bug。 代理们成功反编译了大约 80% 的游戏内容,可见进展。游戏可以启动,主菜单可见,并且我们能够加载地图。 那四周里我们花了很多时间优化设置: 我们通过更早触发压缩来减少 token 消耗。默认的压缩阈值是上下文填充到 90%。我们将其降低到 42%。反编译包含大量易变信息:一个已反编译的函数现在已无关紧要,可以从上下文中移除。因此更早的压缩有助于从上下文中清除这类"垃圾"信息。 我们还注意到代理会随着时间的推移逐渐偏离注意力。即使在一次压缩周期内,上下文中的数据越多,代理越容易漂移并失去焦点。 代理有时会在完成前一个函数之前就转向另一个函数。它们还会在观察 CI 时无所事事,尽管已经在 Discord 上收到了失败通知。偶尔,它们会在没有彻底检查工作是否真正完成的情况下关闭 issue。 在终端中并肩工作时,你可以引导代理来防止这种情况,但让它们自主工作时,就无法进行引导了。 为了防止这种情况,我们编写了一份文档,定义了我们的目标、代理应如何工作、必须避免什么,以及如何处理特定情况。 每小时的 cron 任务会自动注入一个请求,让代理重新阅读这份文档,保持指令在其上下文中的新鲜度。虽然这可能不是让代理保持专注的理想方法,但它在整个项目结束前都表现得非常好。 我们花了很多时间来打磨指令文档。由于内容极其针对这个项目,在这里分享意义不大。 ## 然而…… ……尽管我们在优化设置和基础设施方面付出了所有努力,我们还是需要谈谈工作质量。 持续的进展(游戏启动、菜单渲染、地图加载)让我们相信反编译质量很高。 并非如此。尽管代码极其可读,但在语义上是错误的。 代理使用了错误的函数签名、类型或结构体布局。它们发明了逻辑,或者在认为不必要时删除了逻辑。 除了语义错误之外,代理还引入了不必要的架构变更。例如,游戏中的某些配置变量是通过全局变量访问的。代理们将这种常量内存访问变成了哈希表查找,开销大了几个数量级。 而这只是众多出错案例中的一个。 ## 为什么会出现这种情况? 审查者有助于发现 Bug,但在其他方面效果不佳。只要架构决策与目标一致,它们就不会受到质疑。 主要原因是我们没有客观的验收标准。我们从未正式定义过"正确性"。因此审查者很难判断哪些变更正确、哪些是错误的。 显然,它有游戏作为参考,但由于我们的清单上也包括现代化和可移植性,某些偏差并未被视为 Bug。有趣的是,提交或代码中的注释使得审查者接受了这些偏差,因为工作者代理写下了各种理由。工作者的注释实际上起到了非预期的提示注入作用:审查者接受了它们的辩解,而不是独立地将偏差与原始代码进行核对。 ## 预言机 我们需要的是一个自动检查机制,告诉代理们某个重建的函数是否与原始函数匹配。它应该验证语义完全一致。一个简单的 PASS 或 FAIL 信号就足够了,代理可以自行弄清楚哪里出了问题。 ## 字节匹配反编译 实现这一点最简单的方法就是字节匹配反编译。 我们切换到用于构建原始游戏的编译器,并编写了一个执行比较的脚本。 该脚本读取我们重建的 OBJ 文件和游戏的 EXE/PDB(拥有 PDB 很好,能让流程稍微简单一些,但即使没有 PDB 这个过程也同样有效)。 然后它从 OBJ 和 EXE 中提取函数数据,比较所有字节。如果匹配,则函数是精确的;否则失败,代理需要重做该函数。 对其他函数或数据的引用不一定逐字节匹配,因为它们的编码值取决于目标在编译后二进制文件中的位置。 幸运的是,OBJ 文件将这些引用记录为重定位信息。我们可以将重定位字节排除在直接比较之外,转而验证两个版本是否引用了相同的符号和相同的偏移量。 脚本对数据和类型也执行相同的操作。 代理们可以在推送之前使用此脚本来验证它们的工作。 重建的函数被记录在一组文本文件中。然后 CI 可以使用这些文本文件验证所有已记录的函数,并在出现回归时发出警报。 ## 作弊 引入此脚本后,代理做的第一件事就是编写内联汇编。 这显然违背了初衷。所以我们不得不细化指令,禁止某些构造。裸函数、对象补丁、内联汇编和嵌入字节被口头禁止。鉴于扫描这些构造非常容易,口头规则就足够了。 然而,代理反复尝试修改此脚本以将其函数排除在比较之外。 为了防止它们这样做,CI 对验证脚本进行哈希处理,并将其与存储在 GitHub Actions secret 中的值进行比较。 ## 权衡 ### 缺点 函数可能很难匹配。寄存器选择、内联决策和调用约定可能很难精确复现。在极少数情况下,我们还观察到相同输入会产生不同的编译器输出。代理现在需要更长的反编译时间,而不一定能产生更好的结果。一个函数可能语义相同,尽管表现出某些差异,例如独立指令被打乱。 ### 优点 匹配的函数保证语义完全相同。这保留了原始行为,包括所有现有 Bug,并防止了这些函数中的重建错误。除此之外,审查者代理也不再需要了。 另一个好处是更便宜、能力更弱的模型现在可以可靠地执行这项任务。之前 Haiku 或 Luna 这样的模型并不适合,产生的结果极其糟糕。然而,有了这个严格的验收标准,它们现在有足够的反馈来产生令人难以置信的结果,大幅降低了成本,并使项目得以大规模扩展。 ## 最终状态 有了新的验证测试框架,代理们又运行了将近两个月。游戏函数的 99% 已经存在于我们重建的源代码中,其中 83% 的函数字节精确匹配。 在最后几周中,我们大部分时间使用 14 个 Luna 和 2 个 Opus 5.5 代理。 在这个规模下,工作者们使用独立的分支,并通过 pull request 提交更改。 这也是 Discord 开始难以扩展的地方。这么多代理在频道中刷屏毫无意义。我们将消息限制在它们正在处理的 issue 和 CI 协调上。这将通信量降到了最低。然而,随着项目推进,我们越不需要与代理对话。人与代理之间的通信不再需要,因为它们完全自主工作。对于其他同等规模的项目,我可能会选择 Discord 以外的方案。 至此,我们已进入收益递减阶段。剩余的函数大多具有某些非确定性特征,或者由于其他原因无法匹配,例如链接器中相同的 COMDAT 折叠,我们无法可靠地复现。 Opus 5.5 代理仍然能够继续推进并匹配剩余的函数。然而,游戏现在已经运行得完美无缺。没有明显的 Bug,原始游戏的所有功能都已存在。 剩余的函数已经反复重做。虽然它们仍然不能逐字节匹配,但我们相信它们的语义是正确的。 继续对它们进行字节匹配将消耗更多 token,却不会实质性地改善结果。这意味着,这个项目现在可以被认为已经完成了。 ## 经验教训 这个项目教会了我们很多。以下是最重要的经验总结: - 精确的指令是必需的。如果任务留有解释空间,代理就有作弊的倾向。 - 正确性应该被定义并且可以机器检查。人类出了名地无法精确表达自己的意图。因此,我认为审查者永远是不够的。一个能提供客观 PASS 或 FAIL 信号的可靠验证测试框架是代理能获得的最佳反馈。显然并非每个项目都有反编译这样的优势。但我认为,只要有足够的创造力,每个项目都可以接近这个目标。 - 指令会随时间衰减。时间越长,压缩的上下文越多,代理就会遗忘或将某些规则视为不那么重要。在交互式工作中,你可以在偏离发生时纠正。当代理自主工作时,这可能无人察觉,并影响工作质量。每小时刷新指令解决了这个问题。 - 生成代码现在很便宜。如果代码不好,直接扔掉。前四周之后,当我们发现代码质量很差时,我们尝试了补救。这实际上比从头开始花费了更多时间。 - 正确性远比生产力重要。减少 token 消耗、扩大代理规模、优化代理吞吐量等等都很好,但如果结果很差,这些都没多大帮助。 ## 最后的话 这确实是一个非常有价值的项目,我学到了很多。我认为写下这些经验教训无法传达我们在整个过程中学到的海量知识。 很多方面出了错,但也有很多方面做对了。随着 AI 代理承担越来越多的软件开发工作,编排它们对人类来说成为了一项全新的、要求更高的任务。 扩大到 15 个以上的代理规模揭示了更多困难。代理们因为格式错误的命令定期清除了虚拟机。已经有 Windows 沙箱解决方案,但我目前看到的都不符合我的需求。我已开始扩展 Sogen (https://sogen.dev/)——我的用户态模拟器——以提供轻量级和可扩展的沙箱功能。然而,要达到接近生产可用的程度还需要一段时间。 由于虚拟机被清除,我们不幸丢失了大量的会话日志。所以我不确定确切的 token 消耗量。我的估计在 6000 亿到 7000 亿 token 之间。 出于明显的原因,不会共享任何代码。所有内容将保持私有,我只会为自己使用。

相似文章

AI正在大规模反编译游戏,这既令人兴奋又令人担忧

Hacker News Top

如今,AI模型能够在几天内(而非数年)将旧款电子游戏反编译成源代码,从而为《以撒的结合》Flash原版等已被弃置的游戏实现原生移植、高帧率增强和Mod支持。这一趋势既引发了人们对游戏保存的热情,也引发了对AI更广泛影响的担忧。