6 天,15 万行:一个人用 AI 写 游戏 ,怎么让它不失控
6 天,15 万行:一个人用 AI 写 游戏 ,怎么让它不失控
作者分享了单人用AI开发游戏时维持代码可维护性的具体工程规范与验收流程。
先摆数字。一个 LLM 驱动 NPC 的武侠游戏项目,我一个人,加一个 AI:
- 6 天(首次提交到现在)
- 437 次提交
- 15 万行代码
- 快 80 条编号决策,每条带理由、带日期
听起来像是来吹牛的。但这篇恰恰不打算聊"AI 写代码有多快"——快是最无聊的部分,今天谁开个 AI 都能快。我想聊反过来的事:怎么让这 15 万行,在第 7 天、第 30 天、第 90 天之后,还敢改。
因为 AI 写代码的项目,最典型的死法是这样的:前三天激情产出五万行,第七天发现没人看得懂——包括三天前的自己,第十天含泪推倒重来,发帖控诉"AI 生成的代码根本没法维护"。
代码挺冤的。错的不是它,是流程。
下面是我们这六天里立起来、并且真的救过命的几条规矩,全部真实踩坑记录,无虚构。
先交代在做的是什么
首先是名字,我暂时先定下的:《人间众生录》,因为最开始的脑洞确实就是希望做一个AI驱动运行一整个游戏世界。
《人间众生录》:开放世界武侠 RPG,每个有名字的 NPC 都有一份"人生履历"——属性从履历推导,经历可以被传授、抢走、弄丢;重要 NPC 接大模型,有记忆,会记得你撒过的谎,并且三个月后用这条谎对付你(设计上是这么希望的)。
底层一句话:模型是外挂大脑,不是操作系统。 LLM 想说什么随便它,但它说的任何话想变成游戏里的实际动作,都必须先过一层裁决。规则脑兜底,没网没 key 照样能玩。
细节后面每篇展开,今天只聊流程。
真正的瓶颈,早就不是"写代码"了
AI 把"把想法变成代码"的成本打到接近零之后,事情就变得很微妙了。
你想要的越模糊,它给你得越快。一句"帮我做个技能系统",十秒钟后你收获五百行看起来很对的代码——然后你花一下午发现它对的部分你用不上,用得上的部分它没写。
所以现在的瓶颈其实挪了位置:
- 说清楚你要什么(规格)
- 知道它做没做对(验收)
这两头没有工程手段兜着,AI 就是把垃圾生产得更快而已。我们全程在跟这两件事搏斗,下面是几条真的立住的规矩。
一、文档写得比代码还狠,但代码说了算
这个项目有 96 份文档。所有代码开工前先有规格,所有文档打架时有一张总纲当裁判。
但真正救命的是反过来的那条:文档跟代码对不上时,代码是老大,然后回头把文档改了。
文档不是宪法,是地图。地图画错了改地图,不是把河填了。这句话写进了维护约定,还配了个链接检查脚本——文档搬家必须全量过一遍相对链接,退出码不是 0 谁也别想合。
没有这条,第六天的你会拥有 96 份互相矛盾的文档,和一个再也不敢相信任何文档的自己。
二、拍板的事,全部编号
项目里有个一直追加的决策清单,快 80 条了。听起来像官僚主义?确实是。但属于救命的那种官僚主义。
举两个真事。
一个公式的较劲。 设计文档写 NPC 记忆衰减是 exp(-Δt / halfLife)。实现的时候发现不对——这是时间常数的语义,不是半衰期。参数叫 halfLife,就该真的半衰,于是实现改成了 exp(-Δt · ln2 / halfLife),然后回文档里写清楚为什么和原稿不一样。
这事要是不登记会怎样?三周后某个会话读到代码,觉得"这跟文档不一样啊",热心地"修正"回去——一个安安静静的语义 bug 就诞生了,还没有任何人知道该怪谁。
一次口径变更。 决策 76:修炼速率不做"调低数值"这种一次性手术,改成速率数据化——以后调平衡只改 JSON,不碰代码。理由、日期、影响面,全部记录在案。
编号的意义不是仪式感,是让"当初为什么这么干"变成一次查询而不是一次考古。AI 时代这条更狠:三个月后你换个 AI 会话来改代码,它没有你的记忆,但它读得懂决策清单。
三、批次切小,三件套一起交
最近做完的建筑与粮仓系统,切成了 B1 到 B6 六批,14 次提交。B1 只做"建筑是一种单位,有耐久",B5 才做到"箱子碎了就打不开",B6 建筑才真正进世界。
每一批交三样东西:过测试的代码、更新过的文档、一份自审记录。
B3 的自审标题就很诚实:"删掉没人读的 ProducingStructures"——上一批的我给这一批的我埋了个没人用的类,自审的时候当场拆掉。
批次多大合适?判断标准就一条:这批里犯的错,下一批开始前能不能被自审抓出来。 能,尺寸就对了;不能,说明切太大了。
四、验收这事,别相信人,相信机器
CI 里跑的不只是编译加测试:
- 编译警告即错误——警告这东西,忍第一条就会忍第一百条
- 测试覆盖率门槛 80%
lwcheck:全部 JSON 内容(技能、物品、委托)全量校验,写错了明确告诉你错在第几行,不跟你玩"哪里错了自己想"- 无头服务端自检,必须恰好拒掉 1 条越权指令
最后这条值得多说一句。为什么是"恰好一条",不是"至少一条"?
因为"至少拒一条"挡不住另一个极端:安全机制写嗨了,把所有指令全拒了,NPC 集体闭麦,游戏变成行为艺术。"恰好一条"同时抓住两种死法——该拦的没拦,和不该拦的全拦。
对 AI 写的代码,机器验收不是什么最佳实践,是唯一稳定的验收方。人会累、会想当然、会看漏,CI 不会,而且它不计较你凌晨三点提交了什么。
五、神秘行为不过夜
三个我们亲手抓出来的怪事。
修为永远不涨。 修炼系统里修为按整数累计,每帧取整——增量不足 1 的部分全部蒸发。玩家打坐一晚上,境界纹丝不动,非常禅。修法是改成小数累计。这个 bug 最阴的地方是它不报错、不崩溃,只是安静地躺在那里违背设计意图,像个卧底。
52 条测试从没跑过。 LLM 网关是 Node/TS 写的,52 条测试从写出来那天起就没进过 CI——CI 只跑 C#。后来盘点才发现:它们手工跑是绿的,过得很好,只是没有任何人保证它们一直过得很好。当天补进 CI。
文档说一个数,代码说另一个数。 逐步排查登记成缺陷票,逐条拍板该信谁,信完回写文档。
规矩就一句话:任何"看起来不对但说不清为什么"的东西,要么当场解释并记录,要么立票带证据(文件行号都得给)。"先这样,回头再说"不允许活过当晚。 因为在 AI 产量下,"回头再说"的意思是"永远不会再说了"。
我们也欠着债
诚实时间。这套流程跑出来的不是净土,是个债写得明明白白的工地:
- 单文件 300 行上限,5 个生产文件已经超了(立了票)
- 有几组同层循环依赖,排进重构批次了
- 最要命的:真实大模型到现在还没接通过,全链路是用打桩的脚本客户端测的
最后一条是故意的。先把"上下文 → 提示词 → 解析 → 裁决 → 应用 → 记忆"整条管道用确定性桩件跑透,先确认咱家水管不漏,再研究水质。桩件的好处是"模型说什么"变成可控变量,测试不再靠玄学。
但风险也明明白白:真模型一接进来,上面所有确定性假设都得重新对账。那是后面批次的事,也是这个系列接下来几篇的主题。
可以抄走的清单
- 文档即规格,代码是唯一事实——冲突时信代码,然后回写文档
- 拍板全部编号——"当初为什么这么干"必须可查询,不能靠回忆
- 批次切小——代码、文档、自审三件套一起交
- 机器守验收线——警告即错误、覆盖率门槛、数据全量校验,外加"恰好拒绝一次"这种活性断言
- 神秘行为不过夜——要么解释,要么立票
- 桩件先行——外部依赖先打桩测透管道,再接真水
这个系列还会写什么
这篇只是开胃菜,流程是骨架,真正有意思的肉还在后面。
后面大致会聊三块:怎么拦着大模型别对游戏世界指手画脚;没有 API Key、甚至断网的时候,这些 NPC 怎么照常过日子;以及一个更现实的问题——每次玩家开口都在烧钱,这笔账怎么算才不会把项目烧死。
有些内容我还欠着实现,边做边写,节奏大概是双周一篇。想看的可以关注一下,更新了就能刷到。
最后
《人间众生录》还在垂直切片阶段。骨架立住了,但离"好玩"还差大量内容——而内容恰恰是这套流程里最不"AI"的部分:写一个属性推导器只要一批,给 NPC 写一段可信的人生,慢得多。
如果你对这个方向好奇——技术侧的,或者单纯想看看一个"NPC 记得你撒过的谎"的世界长什么样——评论区聊,或私信。
顺手一提:本项目里有一套数据驱动的"技能 JSON"的内核,我把它单独摘出来开源了——skill-dsl。方法表、沙箱表达式、注册期校验,24 个测试,去掉了所有项目私货,任何项目都能直接拿走。想找个参考实现,或者打算自己搭一套类似的,可以拿去用。
来源:知乎 · AI 游戏文章 · zhuanlan.zhihu.com