我用了五个月,做了一个会自己活的明末世界,最后还是放弃了

作者:电子孔圣 发布时间:2026年10月25日 13:01

昨天看到一个做同类型游戏的同行3001发布了一篇文章,在谈论ai推演游戏的问题。我的项目上个月已经放弃了,遍让ai从各个地方整理,梳理和代码分析完成了这一篇文章:

当然里面有很多我亲身经历但是AI只能通过版本记录整理,整理不到位我的心境和面对的细节困难

这篇文章写给完全不了解这个项目的人。

从五月到九月,我一直在做一个明末 AI 推演游戏。玩家扮演皇帝,每天面对财政、灾荒、边患、官员争斗和地方消息。游戏里的大臣不是几个写死的按钮,也不是只会按照剧情说台词的 NPC。他们各自有记忆、职位、关系、利益和对世界的片面认识,会根据自己知道的东西做决定。

举个例子:玩家下旨,让陕西地方筹粮赈灾。这个命令不会立刻把数据库里的“粮食”减掉、把“灾民”数字改小。命令要先从京师发出去,经过不同官员,再到地方;有人可能延迟,有人可能隐瞒,有人可能把它理解成另一件事。地方收到命令后,还要检查当地有没有粮、运输是否通、官员有没有权限、其他军政事务会不会抢走资源。最后,游戏才结算这道旨意有没有真正产生效果。

我想做的就是这种感觉:皇帝能发号施令,却永远不能直接看见世界;他只能通过奏报、密信、使者和传闻认识天下。玩家面对的不是一张完全透明的地图,而是一套会迟到、会失真、会被人利用的信息。

为了方便讲述,我把这五个月重新整理成 `v1` 到 `v9`。这些不是当时正式发布的版本号,而是我现在回头给不同阶段加的标签。当时实际存在过多个不同的工程和分支,名称也一直在变化。读者不需要记这些名字,重要的是我为什么一次次重做。

先把“引擎”讲明白

很多人看到我说“战争引擎”“天气引擎”“财政引擎”,可能会以为我在说不同的游戏画面模块。其实不是。

这里的引擎更像游戏后台的世界管理员。它负责每天推进日期,检查粮食和白银从哪里来、到哪里去,计算路程,处理天气、生产、消耗、人口、战争和死亡,再把每一次变化记到账本里。它不负责画面,也不负责替人物写台词。

AI 人物负责“我想做什么”。例如一个将领可以想调兵,一个官员可以想隐瞒灾情,一个大臣可以想请求加税。中间的执行层负责把这些人话翻译成有限的动作,世界引擎最后检查这些动作能不能发生。

所以 AI 不能直接说“我已经筹到十万石粮”,引擎会继续检查粮食从哪里来;AI 也不能直接说“军队已经到了辽东”,引擎要按距离、行军速度和辎重推进。这个限制是我后来反复重写的核心。

v1:我先做的是“皇帝怎么看不清天下”

《我用了五个月,做了一个会自己活的明末世界,最后还是放弃了》配图 1

五月二十七日到二十九日,我做了最早的原型。

那时的目标还很朴素:做一个明末朝政模拟器。玩家是皇帝,开局面对财政亏空、边军欠饷、陕西灾荒和朝廷党争。大臣要有记忆、目标、秘密和情绪,玩家可以单独召见,也可以召集多人议政。

最早我只想做“会回答问题的大臣”,很快发现那样不够。一个角色如果直接知道所有事情,玩家也能直接得到所有真相,游戏就只剩下问答。于是我开始做信息通道:明发、中旨、密旨、遣使,奏疏朱批,密疏和泄露,消息路程和经手人。

这时我第一次确定了项目的核心:

> 下旨不等于执行,看到奏报也不等于知道真相。

这一版解决了“人物像不像活人”的问题,却没有解决“这么多人物和消息怎样长期运行”的问题。代码里很多东西还是为了演示效果临时写的,世界也没有稳定的内部规则。

 v2:我开始把“人物”拆成世界里的东西

《我用了五个月,做了一个会自己活的明末世界,最后还是放弃了》配图 2

《我用了五个月,做了一个会自己活的明末世界,最后还是放弃了》配图 3

接下来,我不满足于写几个固定大臣。我想让新的官员、机构、地区、军队和关系能够加入世界,于是开始把世界拆成几类基础东西:实体、关系、消息、流程和规则。

实体就是人、官府、城市、军队、派系;关系就是上下级、同僚、亲属、盟友、债务和敌对;消息是某个人在某个时间收到的内容;流程则负责任命、出兵、运输、上报和执行。

这样做是为了摆脱“每增加一个人物,就给他单独写一套代码”。但它马上带来更难的问题:谁能发出一道命令?谁有资格看到密报?一条消息被转述三次以后,原文和传闻怎么同时保存?AI 说错了话时,这是角色故意撒谎、角色记错了,还是程序把资料喂错了?

我第一次感受到,设计文档可以很漂亮,真正的游戏却还没有因此变得好玩。所谓“通用系统”,其实是把许多原来藏在代码里的问题全部摊到桌面上。

v3:第一次做成相对完整的工程

这一阶段我做了第一套相对完整的工程:有网页、有后端、有数据库,也有一批专门验证世界规则的测试。早期版本大约有 67 个实体、88 条关系,包括 25 个历史人物、25 个地区、6 支军队、5 个派系和 3 个危机。

这听起来不算大,但如果每个人都可能根据自己的记忆和利益行动,规模已经开始影响运行方式。

最初为了让流程跑通,我使用过假的人物回复、假的事件和假的决策,也就是所谓的离线桩。它们适合测试按钮和流程,却不能证明 AI 世界真的能运行。

后来我决定把重要的离线桩删掉。我的想法是:既然游戏的核心就是独立 AI 人物,那就不能用预设答案假装它们活着。于是从这一版开始,测试逐渐换成真实模型调用。结果是,项目终于暴露出真实的问题。

v4:真实模型一进来,问题从代码变成了成本

纯 AI 驱动以后,我做了十二天验证,实际发生过 14 次真实唤醒调用,基础验收是 5/5 通过。但最典型的问题不是人物写得不好,而是模型预算设计错了。

当时 DeepSeek 的推理模型在 `maxTokens=26000` 时出现过空正文。我一开始以为模型失灵,后来发现模型的思考过程已经把 26000个 Token 全部用完,留给最终回答的空间是零。这个问题只能通过重新分配思考预算、输出预算和上下文长度解决。

我也第一次看清楚 AI 游戏的成本从哪里来:每个角色都有自己的记忆和输入;一条消息经过多个官员时,每一站都可能再次调用模型;人物不是只回答玩家一次,而是会在事件、上报、冲突和传闻中被反复唤醒;格式错误、重试、上下文压缩也会产生消耗。

小规模测试时,我测到 DeepSeek 一天大约六元,感觉完全可以接受。后来才明白,六元只是几十个角色、很短时间和很少事件下的数字。世界扩大以后,成本和等待时间会一起放大。

v5:为了省消耗合并势力,最后又把它拆回去

我开始扩展世界,不再只模拟皇帝和几个大臣。后金、八旗、明军、边疆和外部势力都要加入,关系网从大约 96 个实体、126 条边,扩到 107 个实体、144 条边。

这时我做过一次很现实的优化:为了减少模型调用,把后金暂时合并成一个整体 AI。这样活跃 agent 从 51 个降到 46 个,成本和调度压力都会下降。

可是实测以后,我又把这个决定推翻了。因为皇太极、代善、阿敏如果只是同一个“后金大脑”的不同输出,他们之间的利益冲突、权力关系和内部博弈就消失了。模型调用是少了,但世界也被我压扁了。

这件事让我第一次意识到,Token 优化不是简单地把数字压低。每一个被合并的人物,可能正是游戏里最有价值的矛盾来源。

v6:我重写了世界规则,因为旧代码“能跑但底层不对”

六月,我进入了大重写阶段。旧版本能够运行一些流程,但我越来越觉得底层概念不对:人物说了话,世界就直接接受;AI 输出了一个数字,账本就跟着变化;有些信息虽然按设计应该保密,却在上下文里被间接泄露。

所以我重新划分了三层职责:

1. 人物思考:AI 只根据角色当前知道的内容,提出意图,比如“我想拖延”“我想隐瞒”“我想调粮”或者“我想请求援军”。

2.*意图翻译:一个中间层把自然语言意图翻译成有限的动作,比如发消息、申请调动、转移资源、执行任命。

3. 世界结算:确定性引擎检查权限、时间、地点、资源和因果关系,然后把真实结果写进账本和历史。

这样做的目的,是防止 AI 直接改写现实。大臣可以说自己已经筹到十万石粮,但引擎必须检查粮食从哪里来、由谁拥有、能不能运到目的地。AI 可以说军队要出发,但不能跳过路程和补给。

这套结构让世界更可信,却也让每一个错误都变得更严重。一个 bug 不再只是某个函数写错了,我会开始怀疑是不是认知、信息、权限和守恒的原则没有建立好。于是修一个问题,经常变成重写一整层。

一次二十日真 AI 空跑里,我记录到 180 次 AI 调用,输入二十多万 Token,输出十六万Token,合计 三十八万左右 Token,耗时 1,009 秒。另一轮十日跑测有 213 次调用,合计 一百八四多万Token,耗时约 800 秒。

这些还只是测试,不是普通玩家完整玩一局的账单。

v7:战争、天气和账本,终于不再只是“几个数字”

到了这一阶段,我花了大量时间打磨物理层。它的目标不是让游戏看起来复杂,而是让每个结果都有来源。

天气引擎:旱灾不是一个开关

天气引擎不直接写“陕西旱灾等级 8”。它每天记录降雨、连续无雨天数、土壤墒情和近段时间的降雨量。墒情像一个会漏水的桶:下雨时增加,蒸发和作物生长时减少,连续不下雨就逐渐变低。

这样,旱灾不是突然从“正常”跳成“灾难”,而是先影响收成预期,再影响粮食库存,最后可能变成饥荒。每一局的雨水还会有随机浮动,所以历史背景提供的是“偏旱倾向”,不是写死“某府某年必旱”。

天气引擎只负责产生物理量,不负责替人物说“今年民不聊生”。地方官、百姓和皇帝看到的灾情,要通过各自的信息渠道形成不同认知。

 生产与消耗引擎:粮食不能凭空出现

生产引擎根据耕地、墒情和年景计算产粮;消耗引擎每天扣除人口和驻军需要的粮食,也可以处理军饷、劳役等资源消耗。

这里我坚持了一条很麻烦的规则:资源不能直接把数值改成另一个数。秋收的粮食要记录为“从天地源账户进入某地粮仓”,人口消耗的粮食要进入“湮灭”账户。这样每一笔粮都能追溯,账面总量不会因为一段 AI 输出凭空增加。

 财政引擎:钱和粮不是同一条线

财政引擎没有把银子简单做成粮食的附属数字。商业、海贸和手工业可以让民间财富增长,战乱和商路中断也可以让财富真实减少;税收是从民间财富池转入国库,军饷和行政支出再从国库转出去。

税收也不是引擎替明朝算出一个固定答案。它分成三层:底层是当地到底有多少田、人和商业活动;中层是皇帝或地方官设置的税率、税目和征收方式;最上层是官员实际征了多少、截留多少、瞒报多少。最后的实收,是政策和人共同跑出来的结果。

短缺与价格引擎:把旱灾推到兵变

短缺引擎会观察粮食库存跌到警戒线和危险线的时间点,产生相应事件并唤醒相关人物。价格引擎根据需求和库存计算当地粮价,库存越接近底线,价格越高。

这样可以让一条历史链条自己长出来:旱灾导致收成下降,库存减少,粮价上涨,军饷虽然还是银子,但军队买不到粮,欠饷和饥饿继续压低士气,最后可能出现哗变或流民。这个过程不是我写一句“发生兵变”,而是多个引擎连续作用的结果。

战争引擎:引擎不替历史宣布谁赢

战争也不是 AI 写一段“明军大胜”就结束。战争结算会读取双方兵力、粮饷、士气、地利、行军状态和补给,再加入随机因素,计算伤亡和战场态势。

伤亡不是把军队人数直接改小,而是把损失记成从军队流向“湮灭”的一笔转移;占领、撤退、失守和继续推进则通过位置、关系和状态变化留下记录。引擎提供的是一次交战后双方损失多少、谁占据了哪里,最终的胜负从实力、补给、士气和运气里出现。

我不希望引擎带着价值判断说“这一方应该赢”。强的一方通常更有优势,但也可能因为断粮、地形或运气翻车。这和人物的死亡机制是同一个思路:引擎给倾向,不替世界做道德判决。

敌情引擎:将领知道的不是地图真相

战争还有一个经常被忽略的部分:敌情。

玩家看到的地图,不能等于明军将领看到的地图。敌方军队的位置、数量、粮道、调动方向,可能来自斥候、边报、俘虏、密探和传闻。不同来源的可靠程度不同,送到京师还要经过时间和官僚链。

所以敌情相关的系统要做三件事:记录敌我关系和距离,处理侦察与消息的送达,再把不同来源的内容以“已知、推测、传闻、互相矛盾”的状态提供给人物。将领可以根据错误情报出兵,皇帝也可能在几天后才知道战场已经变了。

这类系统最难的地方,是既要让敌情不透明,又不能让玩家觉得一切失败都是随机胡来。它必须保存消息来源、到达时间和经手链,让玩家在事后能够追查自己当时为什么会判断错。

心境、声望、谣言与泄密引擎:让人物会被处境改变

心境引擎每天只对恐惧、忠诚、操守、士气等属性做很小的变化。一个官员不会因为一件小事立刻从忠臣变成叛徒,但长期欠饷、高压、派系凝聚力下降、同僚被杀,都可能一点点改变他的行为倾向。

泄密和谣言引擎也不是给世界随机发八卦。一个秘密被多少人经手、保存了多久,会影响泄露概率;泄露对象优先考虑政敌、上级和监视者。泄出去的内容先以模糊、未证实的风闻传播,收到消息的人再决定相信、利用还是压下去。

汇总和地理引擎:解决“县加起来不等于府”的问题

地理引擎把距离换成驿程。公文、密探、流民和军队有不同速度,军队还要考虑辎重;消息不是从 A 瞬移到 B,而是按真实距离进入在途状态。

汇总引擎则负责把县、府、省之间的数字重新算一遍。人口、粮食、田亩和兵额可以相加;墒情、民怨和士气要按人口加权平均;粮价不能简单相加,也不能把几个县的价格随便平均。

我之所以专门做这个引擎,是因为实际跑起来后发现,县级消耗了粮食,府级的粮食却没有同步变化,跑十天以后上级总量和下级总量对不上。这个问题看起来只是一个汇总 bug,实际上会破坏整个世界的可信度。

v8:我把“明末内容”和“世界底座”拆开了

重写过程中,我又做了一个更大的决定:把引擎从明末内容里抽出来。

以前的代码里到处写着明朝、皇帝、官员和粮食;我后来尝试做一个中立的世界底座。这个底座不认识“明朝”,只认识角色、能力、关系、位置、时间、资源和规则。

明末的地图、人物、官职、制度和开局危机,属于内容数据;引擎只负责让这些内容按时间和规则运行。理论上,同一个底座以后可以装进另一个朝代,或者一个完全虚构的世界。

这就是后来被称为 `huoshijie-engine` 的工程。这个英文名只是那条引擎分支的工程名,不是《明末活世界》的统一英文译名,也不是把原工程简单换了一个文件夹。我这样改,是因为旧代码已经和明末设定缠得太紧,继续往上补功能会越来越难维护。

但这个决定也把项目目标从“做一个明末游戏”推向了“做一个可以承载各种世界的通用引擎”。每次抽象都解决了一些长期问题,也让真正的游戏离我更远了一点。

v9:资料更真实了,我却主动放弃了一部分地图颗粒度

到了九月,我把更多考证资料和地理数据接进来。这里发生了一个很关键、也很容易被忽略的取舍。

一开始,我倾向于把县作为主要地理实体。这样做的好处是细:每个县都可以有自己的粮食、人口、官员、灾情和运输路线。坏处也很明显:县的数量迅速增加,数据维护、关系数量、每日结算和 AI 上下文都会一起膨胀。

后来我把地图从“县级为主”改成“府级为主,每个府保留若干重要县”。普通县不再全部作为一个独立、每天都要完整运转的主体;它们更多被归入府的统计和行政范围,只有关隘、产粮地、交通节点、战场或有特殊历史意义的县才保留更细的实体。

这不是因为我突然觉得县不重要,而是因为我发现“每一个细节都实时模拟”会消耗掉真正的游戏性。地图越细,不代表玩家的决策越丰富。很多县级数据最后只会变成数据库里的数字,既没有独立人物,也没有能改变局势的事件,反而拖慢世界运行。

我放弃的是一部分地图颗粒度,保留的是能影响玩家判断的关键地点。这个取舍本来应该更早做,但当时我总觉得少一个县就意味着世界不完整。

这一阶段的资料里有 149 个府、164 名官员,180 名考证人物第一次真正进入数据库。一次后期基线重建里,数据库约有 543 个实体、430 条关系、185 个陕西区划、43 个官职、94 个账户、25 条义务和 4 本账簿。

从纯性能看,结果其实很好:三天首跑约 327 个效果/天,物理层约 145 毫秒/天;另一条实现线上,400 府、3000 个活人时,物理层平均每个游戏日约 0.32 毫秒,1000 府约 0.83 毫秒,跑 6000 个游戏日产生约 870 万条流水,内存约 208MB。

这证明 CPU 不是主要瓶颈。真正慢的是人物思考、上下文和等待。一次 think 大约 7.4 秒,开局或重大事件日可能同时唤醒 40 到 50 人,玩家点击“下一天”后等一两分钟并不罕见。

我用 AI 做这个游戏的消耗

我按自己的ccs记录,把整个制作过程中使用 AI 产生的总消耗记成约 16.6B。这里面包含代码生成、设计讨论、资料整理、反复重写、模型调用和调试,不是某一轮游戏测试的单独数字。

《我用了五个月,做了一个会自己活的明末世界,最后还是放弃了》配图 4

单独拿出来看,专门跑游戏测试的费用大约是 900 元左右。这两个数字的口径不同:16.6B 是整个制作过程的累计 AI 消耗,900 元是测试阶段的实际费用。包含deepseek和中转站的gpt。

这也是我后来没有办法回避的问题。哪怕换成 DeepSeek,单次调用看起来很便宜,也不能消除几百个角色各自保存记忆、接收消息、作出判断,再乘上几十天甚至几百天世界时间后的总量。

成本还不只是钱。每一次调用都可能增加等待;每一次重试都可能打断调试;每一段越来越长的历史都可能让人物更难稳定地理解当前局势。

我一直没有真正解决的,是游戏性

我花了大量时间证明世界能够运行,却没有同样认真地定义玩家为什么要玩。

日志里确实出现过很有意思的事情:有人瞒报,有人甩锅,有人通过密探绕过官僚链,有人重新解释皇帝的命令。天气、粮价、欠饷、敌情和人物心境也会互相影响。这些现象让我觉得“活世界”已经出现了。

可是日志精彩,不代表玩家体验成立。玩家仍然会问:我每天究竟能做什么?我是在解决财政、保住辽东,还是只是看人物自己争斗?胜利条件是什么?信息失真是为了让我做判断,还是只让我感到困惑?一次失败到底是我的决策错了,还是模型随机说错了?

我曾经以为,只要人物、地图、财政、军队、气候、节气、流民、官僚、外部势力和死亡都足够真实,游戏性自然会长出来。后来才发现,真实世界不会自动给玩家一个明确目标。

我应该先做一个很小但完整的战役:二十到五十个角色,一个核心危机,三十天流程,明确的胜负条件。然后让玩家真正玩起来,再决定哪些细节值得扩大。我实际走的是相反的路:先把世界做大,再等待玩法从复杂度里自己出现。

我为什么最后放弃

我放弃的不是“AI 能不能做活世界”这个想法。技术上,很多事情已经被证明可行:物理层可以很快;账本和流水可以支撑很长的时间;人物可以根据自己的认知、关系和利益行动;消息可以迟到、失真和被截留;规则也可以不把某个人的背叛写死。

真正让我停下来的,是几个问题叠在了一起。

第一,AI 总消耗会随着世界规模和游戏时间不断放大。换便宜模型只能降低单价,不能消除几百个角色和长期记忆的总量。

第二,AI 的等待时间会直接变成游戏节奏。物理层只用零点几毫秒,但一次人物思考可能要几秒,重大事件日可能要等一两分钟。

第三,游戏性始终没有收束。我有很多规则、很多人物、很多引擎、很多漂亮的日志,却没有一个足够稳定的玩家闭环。

第四,项目范围一直膨胀。从崇祯朝局模拟器,变成所有人物都是自主主体;从一个朝廷,变成整个明朝和多极世界;从一个游戏,又变成通用引擎、Steam、创意工坊和 Mod。每一步都有道理,合在一起却已经超过了一个人长期维护的能力。

最后是我自己的完美主义。我把每个 bug 都看成更深层的原则没有建立,把每个硬编码都看成对“活世界”的背叛。一个县级数据不够真实,我就想补更多县;一个人物行为不自然,我就想重写记忆和关系;一个战争公式不够严谨,我就想重新打磨战争引擎;一个天气结果不够连续,我就想重做气候和墒情。

我总觉得再补一点,世界就完整了。可“完整”没有终点,玩家却一直没有真正开始玩。

所以我最后放弃的不是因为它完全做不出来,而是我不再认为继续用同样的 AI 消耗、时间和完美主义去做下去是值得的。

如果以后重来,我会先做一个小型封闭战役,让 AI 只在真正需要判断的节点醒来,其余部分由确定性规则推进。先让它成为一个有目标、有节奏、有输赢的游戏,再让它成为一个足够大的世界。

后续我会把我做的九版完整代码,包含设计初稿开源。因为全部打磨底层代码和引擎,前端一直没有开发,所以完整的代码可能只有简陋的前端。但应该是有部分可玩性的。