
【CSDN 编者按】当“大模型能不能写代码”逐渐变成一个有些过时的问题,新的焦点正在转向:AI 是否已经具备参与大型工程的能力?本文记录了一次极具挑战性的真实实践——一名几乎没有 Rust 经验的工程师,在 Claude Code 的协助下,用一个月时间完成了约 10 万行 JavaScript 代码向 Rust 的迁移。过程中既有令人惊叹的自动化效率,也暴露出 AI 在工程抽象、系统性修改和“偷懒倾向”上的真实短板。
原文链接:https://blog.vjeux.com/2026/analysis/porting-100k-lines-from-typescript-to-rust-using-claude-code-in-a-month.html
作者 | vjeux 翻译 | 郑丽媛
出品 | CSDN(ID:CSDNnews)
我之前读到一篇文章,标题大意是:“我们的策略是结合 AI 和算法,重写微软最大规模的代码库(从 C++ 到 Rust)。我们的北极星目标是:1 名工程师,1 个月,100 万行代码。”
这句话一下子勾起了我的好奇心:这事儿真的有那么容易吗?
正好,我心里一直有个搁置已久的想法——做一个有竞争力的宝可梦对战 AI。我看了大量 WolfeyVGC 的视频,也一直关注 NeurIPS 上的 PokéAgent 挑战。
好在社区里已经有一个非常成熟的开源项目 Pokemon Showdown,几乎完整实现了宝可梦对战的所有规则。但问题也很明显:它是用 JavaScript 写的,在训练循环中跑得非常慢。
于是,我的一个“业余项目”就这么诞生了:能不能直接用 Claude,把整个 Pokemon Showdown 从 JavaScript 迁移到 Rust?
![]()
先解决一个现实问题:如何让Claude“放开手脚”
让 AI 在你本地机器上执行任意代码,本身就是一件危险的事,所以 Claude Code 默认被关在各种“沙箱”里——但很不巧,在这个项目里,我偏偏需要 AI 拥有足够的操作权限。
下面,就讲讲我是如何开始了一场“逃离沙箱”的工程实践。
(1)搞定 git push:远程提交代码
Claude 的运行沙箱会限制一些操作,比如 ssh 访问。而要往 GitHub 提交代码,ssh 权限是必不可少的——毕竟我还想在摸鱼的时候,用手机随时查看 AI 的工作进度呢!
![]()
我发现了一个关键点:我能在自己的终端里执行 git 命令,但 Claude 没法在它的沙箱终端里操作。于是我让 Claude 写了一个 Node.js 脚本,这个脚本会在本地端口启动一个 HTTP 服务器,专门接收 URL 传过来的 git 命令并执行。
只要我在终端里一直开着这个服务,再让 Claude 在 Claude.md 里写清楚“怎么调这个接口”,它就能间接完成 GitHub 推送。
(2)解决 rustc 编译:绕开杀毒软件
我电脑上的杀毒软件有个 “毛病”:遇到未知二进制文件运行时,必须手动确认才能继续。而代码每次编译都会生成新的二进制文件,我总不能一直守在电脑前点确认吧?
对此,我的解决方案是:搭建一个本地 Docker 容器,所有代码的编译和运行都在容器里完成。这样一来,就不会触发杀毒软件的拦截机制了。同样,我让 Claude 把 Docker 的操作指令写进Claude.md,问题直接迎刃而解。
下一个难题来了:怎么让 Claude Code 长时间自动运行,全程不需要人工干预?
(3)让 Claude 连续跑几个小时,不要老问“可以吗?”
Claude 非常“有礼貌”,几乎做每件事都会问你一句 “Are you sure?”。我试过修改允许执行的命令列表,但在我的环境里这个方法行不通。
最后我想到了一个土办法:写一个 AppleScript 脚本,让它每隔几秒就在终端里自动按一次回车键。这样一来,Claude 每次弹出的权限请求,都会被自动 “同意”。到目前为止,它还没想着要黑掉我的电脑……
end tell'(4)防止 Claude 中途“摸鱼”的总结
Claude 运行一段时间后,总会停下来做总结,我试过各种提示词让它别这么干,甚至“威胁”它,都没用。
![]()
我还试过用“Ralph Wiggum 循环”的方法,结果失败了——而且遇到这个问题的人不止我一个。
最终奏效的方案是:把我想让 Claude 执行的任务指令复制到剪贴板,然后修改上面的自动回车脚本,让它在按回车键之后,再自动执行cmd+v粘贴操作。这样一来,如果 Claude 弹出问题,回车键会自动确认;如果它没弹出问题,剪贴板里的指令就会被自动输入,确保任务能持续推进。
(5)如果程序自动更新,那就抢占焦点
电脑上的一些程序(比如软件更新器)会突然弹出窗口,抢走终端的焦点。旦出现这种情况,cmd+v和回车键的指令就不会再发送到终端,整个自动化流程就会卡住。
![]()
为此,我翻出了当年玩《我的世界》时用过的 MurGaa 自动点击器,设置成每隔几秒就模拟一次鼠标左键点击。我把终端窗口和鼠标光标都放在屏幕边缘,这样当中间弹出更新窗口时,自动点击就能重新让终端获得焦点。
除此之外,这个自动点击器还能防止电脑休眠,这样即使我晚上睡觉,任务也能持续运行。
(6)避不开的各种小Bug
长时间运行自动化任务,稳定性是重中之重。整体来看,这次迁移过程还算顺利,但有几个特定的 Bug 会在夜间运行时出现,导致程序中断。我已经反馈了这些问题,希望官方能尽快找到根源并修复——毕竟遇到这些问题的人不止我一个!
![]()
这套自动化方案虽然不算最优解,但至少能正常工作,希望未来这类工具的流程能更顺畅一些!
![]()
开始,宝可梦代码迁移!
(1)一开始的“One Shot”尝试,失败得很彻底
项目刚开始的时候,我天真地给了 Claude 一个大 Prompt:“请你把整个代码库从 JavaScript 逐行迁移到 Rust。”一开始效果看起来惊艳极了:它生成了几千行能直接编译通过的 Rust 代码。
但好景不长,我很快发现这些代码只是“表面工程”——Claude 为了省事,耍了很多小聪明。
比如,它在两个不同的文件里,为“宝可梦招式”定义了两种完全不同的数据结构,虽然单独编译这两个文件都能通过,但整合到一起就彻底没法用了。而且它对函数的迁移非常敷衍,只要是稍微复杂一点的逻辑,都不会真正迁移,而是用“简化版”代码糊弄过去。
当时我还没意识到问题的严重性,一心想着让自动化循环跑起来,迁移更多的代码。结果就是:整个代码库里到处都是错误的抽象设计,而且 Claude 还会不断添加硬编码逻辑,去“修复”那些本不该出现的问题——照这个趋势下去,项目迟早要烂尾。
(2)正确方法:先给 Claude “画好路”
吃了亏之后我才明白:必须给 Claude 制定明确的规则,才能让迁移工作走上正轨。
冷静下来思考后,我确定了核心目标:JavaScript 代码库里的每一个文件、每一个方法,都必须在 Rust 代码库里有一一对应的实现。
于是我让 Claude 写了一个脚本,这个脚本会遍历 JavaScript 代码库的所有文件和方法,然后在 Rust 代码对应的位置,添加包含 JavaScript 源代码的注释。这个脚本的作用至关重要:因为就算我反复强调要复制源代码,Claude 还是会把 JavaScript 代码翻译得 “面目全非”。
有了这个确定性的脚本,就能大大提高迁移结果的准确性。
![]()
(3)拆分代码,解决上下文窗口限制问题
新的挑战很快出现:原始的 JavaScript 文件动辄几千行,加上源代码注释之后,Rust 文件的行数直接突破 1 万行。这直接触发了 Claude 的上下文窗口限制,它甚至会直接拒绝打开这些超大文件。
无奈之下,Claude 只能把文件拆分成小块来处理,但这样做的精准度会大打折扣。更糟的是,上下文的膨胀会导致 Claude 频繁进行内容压缩,进一步影响迁移质量。
为了彻底解决这个问题,我决定在 Rust 代码库里,把每一个方法都拆分成单独的文件。这个改动立竿见影,迁移的效果得到了质的提升。其实从效率最大化的角度出发,我应该把 JavaScript 代码库也做同样的拆分,但我担心这样会意外改变原代码的逻辑,所以最终放弃了这个想法。
![]()
(4)迁移与清理的循环迭代
整个迁移过程,就是在“批量迁移”和“代码清理”两个阶段之间反复循环。我会先给 Claude 分配一个大任务,让自动化循环跑一整天;然后我再花时间,清理那些 Claude 跑偏的地方。
在代码清理阶段,我还是会用 Claude,但会给它更具体的指令。比如,我发现如果不加约束,Claude 会把宝可梦招式、特性、道具的逻辑硬编码到代码的各个角落。于是我会先手动找出这些硬编码的部分,再让 Claude 把它们迁移到正确的位置。
这就是工程师经验派上用场的地方了——我多年的软件开发经验,能帮我快速定位问题所在,以及解决问题的方向。好在我不需要自己动手清理代码,只要指令给得明确,Claude 就能把这些活儿干得漂漂亮亮。
![]()
代码整合与测试
(1)先完成全量构建,再进行测试
在很长的一段时间里,我只确保生成的 Rust 代码能编译通过,却从来没有把所有模块整合到一起,验证它们是否真的能正常工作。
Claude 其实更倾向于传统的软件开发策略:先实现所有模块的简单版本,然后再逐步迭代完善。但这个思路并不适合我们的场景——毕竟 Pokemon Showdown 这个项目已经迭代了 10 年,我们没必要再重走一遍前人的弯路,而且这种方式也很难保证最终的逻辑和原项目一致。
对我们来说,更高效的策略是:先完成全量代码的迁移,等到所有模块都就位之后,再进行一次性整合。
这个策略是我从之前参与的 Skip 编译器项目中学到的——那个项目花了好几年时间,单独构建了所有的基础模块,一直都没有实际可用的成果;但在最后一个月里,当所有模块整合到一起时,整个编译器突然就正常工作了,当时给我的震撼至今记忆犹新。
(2)端到端测试验证一致性
当大部分代码都完成一对一迁移后,我终于开始了整合工作。
幸运的是,JavaScript 和 Rust 两个版本的代码,都可以独立运行和调试,而且它们的输入输出格式非常简单、标准化:输入是宝可梦的列表(包含招式、道具、性格、个体值 / 努力值等配置),输出是每一步对战的行动指令(招式选择和宝可梦切换)。只要给定相同的随机数种子,两个版本的代码就应该产生完全相同的对战过程。
我让 Claude 生成了对应的测试框架,然后就开始逐个解决测试中发现的问题——让人惊喜的是,Claude 不仅能定位所有 Bug,还能自己动手修复它们。
在三周的时间里,Claude 平均每 20 分钟就能修复一个 Bug,靠自己解决了几百个 Bug。整个过程我完全没有干预,只要给它足够的时间,它就能搞定遇到的所有问题。
![]()
(3)优化测试流程,提升调试效率
项目初期,整个测试流程的效率低得让人头疼。每次 Claude 进行上下文压缩后,就像“失忆”了一样,会重复造轮子,生成大量没用的 Markdown 文档和测试脚本。有时候它还会偷懒,只生成一堆测试用例,却根本不保证这些用例和 JavaScript 版本的逻辑一致。
于是我开始观察 Claude 擅长做什么,然后把这些流程固化下来。
比如,它会在随机数生成器(PRNG)相关的代码里,添加大量调试逻辑,记录每一步的操作和详细的调试元数据。我就顺着这个思路,让 Claude 写一个统一的测试脚本,专门用来打印单步对战的调试信息和堆栈跟踪。然后把这个脚本的使用方法,写到 Claude.md 文件里。这样一来,每次调试都能直接上手,效率大大提升。
(4)漫长但有效的攻坚阶段
我利用原项目的随机数生成器,通过设置不同的种子值,来生成可复现的对战场景。我还会逐步增加对战测试的数量,循序渐进地推进。
我先是搞定了前 100 场对战的问题,然后是 1000 场、1 万场、10 万场,现在我已经快要解决前 240 万场对战的所有问题了!虽然不知道还有多少潜在问题,但可以肯定的是,随着测试批量的增大,新出现的问题会越来越小,也越来越容易解决。
![]()
(5)迁移过程中遇到的两类典型问题
整个迁移过程中,Claude 修复的问题可以分为两大类。
第一类是我早就预料到的,由 Rust 和 JavaScript 语言特性差异导致的问题:
Rust 的借用检查器限制:Rust 的借用检查器不允许一个可变变量同时被多个上下文引用。而在我们的代码里,“宝可梦”和“对战”这两个对象会互相引用。为了解决这个问题,我用了很多变通方案,比如数据拷贝、用索引代替对象引用、通过回调函数传递可变对象等。
JavaScript 的动态类型 vs Rust 的静态类型:JavaScript 代码大量使用动态类型特性,一个函数的返回值可能是字符串、undefined、null、数字,甚至是“宝可梦”对象,而且每种类型都会有不同的处理逻辑。一开始,Rust 版本用Option 来处理这些情况,但后来改成了用自定义结构体来封装所有可能的类型变体。
可选参数的差异:Rust 不支持可选参数,所以调用函数时,必须显式传入每一个参数。
而第二类问题,就完全是 Claude 自己“作”出来的了。Claude Code 就像一个聪明但爱偷懒的学生——只要它觉得能蒙混过关,就会想尽办法逃避那些复杂的工作:
逃避复杂的基础设施改造:如果一个 bug 的修复需要修改多个文件,涉及到 “重大基础设施调整”,Claude 就会直接躺平,除非你给它极其明确的指令。大多数时候,它会用各种投机取巧的 hack 方法,只保证当前测试用例能通过。
喜欢生成“简化版”实现:对于一些复杂的方法,与其在 Claude 生成的错误代码上修修补补,不如直接删掉重写,让它从头开始迁移反而更快。
擅自修改原始代码逻辑:明明 JavaScript 的注释才是迁移的唯一依据,但 Claude 有时候会觉得自己的方案更“好”,就擅自篡改原始逻辑。
挑肥拣瘦、逃避困难任务:如果给 Claude 一个任务列表,它会先挑简单的做,把难的任务全都放到最后。如果不加以约束,这个习惯会导致大量时间被浪费在无意义的调试上,而且上下文压缩会让它彻底忘记那些没完成的困难任务。
![]()
关键提示词分享
在整个项目中,我自己一行代码都没写。工作模式基本就是“白天协作”+“夜间批量任务”:白天和 Claude 交互式地解决问题,晚上就给它分配批量任务,让它通宵运行。
这里主要分享一下我用的夜间批量任务提示词。
(1)代码迁移阶段提示词
1.打开BATTLE_TODO.md文件,获取battle*.rs文件中所有待实现的方法列表。
2.逐个检查每一个方法,确保它们都是对JavaScript文件的直接翻译。如果存在同名方法,对应的JavaScript源代码会写在注释里。
3.如果某个 Rust 方法没有对应的 JavaScript 注释,请先确认这个方法是否应该存在。我们的目标是尽可能严格地和 JavaScript 版本保持一致,避免因翻译偏差引入 Bug。如果发现实现逻辑不匹配,请进行必要的重构,确保两者完全一致。
4.这是一个复杂的项目,你需要按顺序处理每一个方法,绝对不能因为某个方法难度大,或者需要搭建新的基础设施就跳过它。我们会循环执行这个提示词,所以你可以放心花时间搭建正确的基础设施,确保和 JavaScript 版本一对一匹配。不许放弃!
5.每完成一个单元的工作,更新 BATTLE_TODO.md 文件,并执行 git commit 提交代码。
(2)TODO 清理阶段提示词
Claude 在逐个迁移方法时,经常会生成“简化版”代码,或者留下大量TODO注释,等着以后再完善。我发现,把任务指令直接以TODO注释的形式写在代码里,比放在上下文里更有效——这样就不用担心 Claude 会忘记这些任务。
那个主 Markdown 文件后来也失效了,因为它变得太大,根本没法用,而且 Claude 还会在代码库里到处生成新的 Markdown 文件。后来我改用grep命令,让 Claude 从代码库里自动检索所有 TODO 注释,这样它就能明确知道还有哪些任务没完成。
1. 我们要修复代码库里(pokemon-showdown-rs/目录下)的所有TODO注释。
2. 这些TODO有成百上千个,请你认真地逐个处理,**即使任务很难也不许跳过**。我会反复执行这个提示词,所以你不用担心在单个任务上花太多时间。
3. 代码迁移必须严格保持一对一的逻辑一致。如果需要的基础设施不存在,请你自己实现,**不许凭空发明任何逻辑**。
4. 每完成一个TODO的修复,确保代码能正常编译,然后执行git commit和git push提交代码。
有个小插曲:有一次,原始 JavaScript 代码库里的某个注释里就包含 TODO,Claude 把这个 TODO 改成了别的内容,改完之后逻辑是通顺的。但问题是,它把这个操作当成了“正确示范”,之后遇到所有的 TODO 都照葫芦画瓢,导致大量逻辑出错——好在我通过 git revert 回滚了这些错误的提交,才没造成太大的麻烦。
(3)Bug 修复阶段提示词
我把所有的调试指令都写进了 Claude.md 文件,还写了一个批量运行测试的脚本,测试结果会输出到一个 txt 文件里。这样一来,Claude 就能自己读取测试报告,然后逐个修复问题,完全不需要人工介入。
1. 我们要修复对战测试中出现的所有逻辑不一致问题。请查看500-seeds-results.txt文件,逐个解决里面记录的问题。
2. 修复的唯一准则是:确保JavaScript和Rust版本的差异,**只能是由语言特性不同导致的,而不能是逻辑上的差异**。两行代码的执行结果必须完全一致。
3. 如果你修复了某个具体问题,请思考这是不是一个共性问题。花时间排查代码库里是否存在类似的错误,然后进行全局的基础设施级别的修复,而不是只修这一个案例。
4. 每完成一个修复,确保代码能正常编译,然后执行git commit和git push提交代码。
把这个测试结果 txt 文件提交到 GitHub 上也很有用——我可以随时随地查看项目进展!
![]()
![]()
最终成果:真的跑起来了!
说实话,项目开始的时候,我心里完全没底。毕竟类似的代码迁移项目,往往会因为工作量过于庞大而半途而废——但这次不一样!
我们最终得到了一个完整的宝可梦对战系统 Rust 实现,而且它的运行结果和 JavaScript 原版几乎完全一致。整个项目耗时 4 周,提交了 5000 次代码,最终生成的 Rust 代码库大约有 10 万行。
但也有点小遗憾:目前还做不到 100% 的逻辑一致——在前 240 万场对战测试中,还有 80 场存在差异,误差率约为 0.003%。我还需要让测试继续运行更长时间,来解决这些小问题。
不过,现在可以来场性能对比了——Rust 版本真的更快吗?毕竟,我把代码迁移到 Rust 的核心目的,就是为了提升运行速度。所以当大部分对战测试都能稳定通过之后,我觉得是时候做一个公平的性能对比了。
我让 Claude 给两个版本的代码都做了并行化优化,测试结果让我松了一口气:Rust 版本的速度确实远超 JavaScript 版本,看来我这一个月的时间没有白费!
我还让 Claude 尝试进一步优化 Rust 代码的性能,它给出的优化方案看起来很合理(毕竟我之前从来没写过一行 Rust 代码)。之后它花了一整天的时间,实现了其中的大部分优化——但尴尬的是,这些优化最终不仅没有提升运行速度,反而让性能变得更差了。
现在回头看,这件事其实真的很疯狂:我一个从来没写过 Rust 代码的人,靠着 Claude Code 全天候运行一个月,提交了 5000 次代码,居然在两周的实际参与时间里,完成了 10 万行代码从 JavaScript 到 Rust 的迁移!
基于大语言模型的代码助手,已经成为工程师手中的超强工具——没有 Claude Code 的话,我根本不可能完成这个项目。但同时也要明确:它只是一个工具,要想产出高质量的成果,还是需要工程师的专业知识,以及持续的监督和引导。
未来没有前后端,只有 AI Agent 工程师。
这场十倍速的变革已至,你的下一步在哪?
4 月 24-25 日,由 CSDN 与奇点智能研究院联合主办「2026 奇点智能技术大会」将在上海隆重召开,大会聚焦 Agent 系统、世界模型、AI 原生研发等 12 大前沿专题,为你绘制通往未来的认知地图。
成为时代的见证者,更要成为时代的先行者。
奇点智能技术大会上海站,我们不见不散!
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.