AI驱动自涌现游戏原型:从NPC复读机到社会分工的架构实践

📅 发布时间:2026/10/14 6:26:17
AI驱动自涌现游戏原型:从NPC复读机到社会分工的架构实践
最近我搞了个大的——一个由 AI 驱动的自涌现游戏原型。标题里“大”不是指画面多好、地图多大而是指游戏里的行为复杂度没有预设剧情、没有脚本任务NPC 自己会说话、会模仿、会干活、会传播消息甚至能自己“长”出社会分工来。这篇文章就聊聊我踩过的坑、最终的架构以及对“涌现”这件事的理解。先说结论如果你以为“给每个 NPC 接一个大模型扔进沙盒世界就能自动涌现出文明”那大概率会失望。我第一次就是这么干的结果跑出来一群站桩复读机。真正的自涌现不是模型有多聪明而是交互结构有没有闭环。1. 先泼盆冷水给每个NPC塞个大模型只会得到一群站桩复读机1.1 我第一次的翻车现场第一版做得特别简单我给镇子上的每个 NPC 配了一段身份提示词比如“你是铁匠性格沉稳”“你是面包师性格热情”然后写了一个循环——每隔几十秒让每个 NPC 向大模型提问“你现在想做什么”把返回的文本直接当行为输出。刚启动那会儿还挺惊喜的确实有 NPC 会主动搭话见面会问“今天天气不错”。但最多跑二十分钟画风就开始诡异了所有 NPC 开始互相重复同一句话见面永远是“你好我叫XX”“很高兴认识你”有的 NPC 干脆站在广场中央发呆每轮都输出“我望着远方思考人生”更离谱的是我写的“性格”在对话里第三句就会碎掉沉稳的铁匠突然变成话痨热情的面包师开始复读机式地拒绝所有人。我一度以为是模型参数调得不对换了好几个模型重试结果都差不多。后来把日志拉出来看才发现问题根本不在单一模型上——每个 NPC 都活在“真空”里。它不知道周围有谁、不知道几小时前自己说过什么、不知道镇上正在发生什么事。它每次被唤醒都是从零开始重新“扮演”一个角色那当然只会产出碎片化的表演而不是连续的行为。1.2 问题出在哪大模型是无状态决策器想明白这个本质之后我才理解自涌现游戏的第一个前提大模型本身是无状态的决策器它每一次被调用都相当于一个失忆的人从梦里醒来只靠当前这段文字做判断。想让它产生有连续性的行为你必须把“状态”放在外部而不是指望它自己记住。我当时想起蚁群算法——蚁群里没有任何一只蚂蚁知道全局计划每只蚂蚁只对身边的信息素浓度做局部反应但整体上却能形成高效的觅食路径。所谓涌现就是大量简单局部决策叠加出来的高级秩序。AI 游戏也是同理你不需要给 NPC 一个“拯救世界”的宏大目标你要做的是给它足够的局部信息、一套反馈机制让它的一个个小决策在交互中汇聚成集体行为。想通这一点后我立刻把第一版推倒重来。2. 把世界和脑子分开这套系统最终长这样2.1 世界服务器 NPC大脑我的最终架构一句话总结世界归世界脑子归脑子。游戏世界里所有客观事实——谁在哪儿、仓库里有多少粮食、天气如何——统一由一个“世界状态服务”管理每个 NPC 的“脑子”则是一个决策模块通过感知接口拿到局部信息做出行动再由行动接口把结果写回世界。二者完全解耦。这个设计思路其实很像传统游戏服务器数据库维护世界客户端渲染画面逻辑层处理规则。只不过我这里把“逻辑层”里的硬编码规则换成了大模型的开放决策。数据流大概是这样的世界状态 → 感知模块按位置/关系筛选 → 记忆检索 → Prompt组装 → 大模型决策 → 结构化行动输出 → 行动执行器 → 更新世界状态 → 广播事件 → 其他NPC感知到 → 下一轮循环每一步之间通过消息队列连接而不是函数直接调用。这样好处是任何一环卡住不会拖垮整个镇子每个 NPC 的感知、决策、行动可以异步进行。2.2 为什么不能直接把世界状态全塞进Prompt早先我还犯过一个错误为了省事把整个镇子的状态表格几百行的 JSON直接拼进每个 NPC 的 Prompt心想“给它足够的信息它总该做出聪明的选择了吧”结果更糟——上下文一长模型反而失去了焦点NPC 开始纠结一些无关紧要的细节比如反复念叨某间房子的门是开的而完全忽略了自己已经饿了一天。后来我把感知模块加了“视野范围”概念跟真实世界的感官逻辑保持一致。每个 NPC 只能感知到自己所在位置附近的物体、当前在场的人、和它直接相关的事件。超出视野的一律不提供。这一步做完决策质量立刻上了一个台阶。我随手写了个很小的数据结构示例{ agent_id: sarah_001, location: [12, 38], energy: 80, hunger: 55, inventory: [wood], visible_entities: [ {type: person, id: tom_002, distance: 4}, {type: tree, id: tree_033, distance: 2} ], recent_events: [ {time: 12, text: 你看到隔壁的tom在砍树}, {time: 15, text: 仓库里的食物不多了} ] }这个结构看起来朴实但它解决了自涌现游戏最关键的问题每个 NPC 的世界是“主观”的不是“客观”的。不同 NPC 会因为位置和亲疏关系看到完全不同的信息行为自然就会产生差异而不是所有人同时对全局作出反应。3. 单个NPC是怎么“活”起来的从感知到行动的完整循环3.1 行为循环伪代码每个 NPC 的核心逻辑我最后收敛成了一个循环感知、回忆、做决定、行动、沉淀记忆。伪代码差不多是这样while running: # 1. 获取该NPC当前能看到的世界状态 perception sense_world(agent_id) # 2. 从记忆中检索相关的历史信息 memories retrieve_memories(agent_id, perception) # 3. 组装成Prompt交给大模型决策 prompt build_prompt(agent_profile, perception, memories) decision llm_call(prompt) # 4. 把决策解析成结构化行动写回世界 execute_action(agent_id, decision) # 5. 把这次决策和结果存回记忆库 store_memory(agent_id, perception, decision) sleep(tick_interval)很多人会忽略第 5 步——记忆沉淀但这个恰恰是整个循环的灵魂。没有记忆NPC 永远在“失忆重生”永远无法积累经验也就不可能产生涌现。我那版跑出一模一样的复读机根子就出在记忆缺失上。3.2 记忆怎么分层记忆不是把历史记录全部堆进 Prompt那样上下文会迅速被撑爆。我实际用下来分成三层最省心短期记忆保留最近 10~20 条事件记录按时间顺序放进 Prompt。它负责“此刻我正在做什么”。长期记忆把更早的信息向量化存入数据库每次按相关性检索 Top 5 出来。它负责“我过去经历过什么类似的事”。印象归档每隔一段时间比如模拟世界的一天让模型把短期记忆压缩成几行摘要再存入长期记忆。它负责“我是一个什么样的人”。印象归档这个点子帮我解决了一个大问题NPC 的“人格连续性”。我发现如果只靠短期记忆NPC 过半天就会忘光自己早期的经历变得前后矛盾但有了“每天存档总结”之后角色的行为会呈现一种缓慢演化。比如某个 NPC 连续几天被人骗它的归档摘要就会逐渐变成“这里的人不值得信任”然后它的行为模式真的会越来越警惕。3.3 决策输出要用结构化JSON一开始我把模型的输出直接当文本处理发现非常难接回世界状态它会说一大段“我想走向东边的树林然后砍一棵树”你要用正则去解析稍微复杂一点的句子就解析失败。我后来强制要求模型输出严格的 JSON只允许抛出三类行动指令{action: move_to, target: [12, 39], reason: 去河边看看} {action: interact, target: tom_002, kind: chat, content: 晚上要一起烤火吗} {action: pickup, target: wood_003, reason: 柴火不够了}这个改动看似微小但直接决定了系统能不能稳定跑起来。结构化输出让行动执行器可以像处理普通游戏指令一样去验证、执行、广播——比如移动要检查路径是否合法、拾取要检查物品是否还在。模型只负责“决定”规则交给系统两边各司其职。4. 涌现是怎么逼出来的事件传播、性格漂移、资源约束4.1 事件传播让NPC开始“八卦”这是我最得意的一个机制每个行动都会在世界上产生一条事件而事件是可以被其他 NPC 听到的。一开始我只把事件当作简单的广播——每个人的行为都会同步给全镇人结果跑出来一个灾难场面几十条互相矛盾的信息叠加NPC 集体精神分裂上一秒还在讨论打雷下一秒就开始转发仓库着火的谣传。后来我限制了事件的传播条件只有处于一定空间距离内、或者与该事件直接相关的人才会收到播报。这样一来信息不再均匀扩散而是像真实小镇一样沿着社交关系流动。举一个具体例子某天镇子东边的“玛拉”打碎了一个花瓶她的邻居“凯”看见了于是凯的记忆里有了这件事之后凯去广场找别人聊天才在对话中把这件事当作谈资说出来。最有意思的是这件事我没写过任何一条“NPC应该传播谣言”的规则它完全是从“看见事件 → 存入记忆 → 聊天时检索相关记忆”的链路里自然长出来的。这就是最典型的涌现——信息沿着局部交互网络传播形成所谓的“八卦链”而八卦又反过来影响 NPC 之间的亲密度说人坏话的次数多了被说的人会渐渐疏远对方。我后来专门把 NPC 之间的关系值单独存了一张表用来记录这种动态变化。4.2 性格漂移让角色会“变”另一个关键机制是性格漂移。最初我给每个 NPC 写死了一个性格标签比如“开朗”“阴郁”但跑久了发现角色很扁平——开朗的人永远开朗遇到悲剧也开朗这显然不符合真实感。我把性格从固定标签改成了动态评分每次行为都会影响几个维度的数值比如社交倾向、攻击倾向、好奇度、勤勉度。社交多一点社交分就涨成功做成一件事自信分就涨连续遭遇失败消极倾向就会上升。然后我在 Prompt 里的角色描述不再写死“你是一个开朗的人”而是写“你最近的行为显示你经常主动找人聊天成功率中等你对自己的判断是……”。模型会根据这个流动的描述逐渐调整自己的行为风格。效果非常明显。有个 NPC 起初是标准的温和派但因为连续几天自己的农田被踩每次去交涉都以失败告终它的冲突倾向评分慢慢走高。终于有一天它不再去理论而是直接做出了一个行动——“趁夜把对方田里的木栅栏拆了”。这一刀不是我写进代码里的而是它在一次次失败反馈中自己“学”出来的应对方式。这比任何写死的性格系统都更有生命力。4.3 资源约束逼出分工与合作如果没有资源压力NPC 的行为会倾向于“闲逛”——没有生存压力就没有动力去做复杂的事。我给世界加了最朴素的资源系统每人需要吃饭食物来自农田和采集工具会磨损需要铁匠修补冬天来临之前必须储存足够的柴火。这些约束写得很简单但组合起来社会行为就开始分化了。我看到的第一个真正称得上“涌现”的场景是这样的镇子的粮仓存量见底负责种地的那几个 NPC 开始疯狂加班但收成依然不够。其中一个 NPC 在路过河边时发现另一个 NPC 在钓鱼于是它的记忆里多了一条“原来可以钓鱼吃”没过多久它自己也开始尝试钓鱼再后来粮仓里出现了鱼制品关于“钓鱼好用还是种地靠谱”的讨论出现在好几个 NPC 的聊天里。另有一个 NPC 因为总钓不到鱼转而开始研究能不能用树枝做捕鱼陷阱结果它真的在河边制造了一个简易陷阱——这个新物品直接诞生于它的行动。注意这个捕鱼陷阱不是我事先做好的物品而是 NPC 根据自己的需求、工具材料和地点组合出了一个世界上本来不存在的新实体。系统只是提供了“材料可以组合”的底层规则NPC 自己完成了设计。看到日志里蹦出这条记录的时候我确实愣了好一会儿——这种“新事物从行为里长出来”的感觉正是我做这个项目最想追求的东西。5. 别把随机当涌现我自己用的三套测评方法5.1 事件新颖度曲线做自涌现系统最危险的事情是自我感动看到一个新鲜行为就觉得“哇涌现了”但其实那可能只是随机噪声。我用来给自己泼冷水的第一套工具是“事件新颖度曲线”。做法很简单把所有行动按“动作类型 对象类型”组合成事件类型比如“move_toriver”“chatfriend”“pickupwood”。然后按时间窗口统计每个窗口里新出现的事件类型占比。如果系统真的有涌现能力那么运行后期应该不断出现早期没有见过的新组合——某两个行为模式拼接出了之前从未发生的交互。如果这个曲线很快就平了说明所谓涌现不过是刚开始各种可能性的随机爆炸之后系统一直在走老路。我跑过一个对照组关闭记忆检索环节让 NPC 只依靠当前感知做决策。结果新颖度曲线在前二十分钟到顶之后就躺平成一条直线——所有 NPC 的行为都收敛到几种固定模式再也长不出新东西。这说明记忆不是锦上添花而是涌现的发动机。5.2 反事实测试第二个方法是从科学实验里借来的反事实推理找一个你觉得“涌现”出来的现象定位到疑似触发机制然后把它在系统里关掉看现象是否消失。如果消失了说明现象确实来自机制不是偶然。当时我发现 NPC 之间出现了“社会模仿”——一个 NPC 开始砍柴附近的 NPC 跟着也开始砍柴。我怀疑这是“观察者机制”导致的于是我做了一次反事实测试把“看到他人行动”这个感知输入临时屏蔽只保留资源短缺信号。结果呢砍柴行为依然存在因为资源短缺本身就能触发但“一群人集中砍柴”的聚集效应消失了大家各自分散在不同的时间点砍不再形成同步浪潮。由此我得出结论资源压力是第一动力“看见别人在做什么”带动的是同步与放大。一个自涌现系统里不同现象往往由不同机制驱动只有用反事实测试区分开你才真正理解这个系统的因果结构而不是笼统地说“它自己动起来了”。5.3 噪声与涌现的判断标准最后我给自己定了一套主观判断标准用来区分随机噪声和涌现行为可解释涌现出来的行为必须能向前追踪出一条因果链。比如“粮仓不足 → 某NPC尝试钓鱼 → 钓鱼经验写入记忆 → 下次看到河优先选择钓鱼”这就是涌现而“NPC突然开始跳舞原因未知”那不是涌现是故障。可重复相同初始条件下跑多次实验行为可以不完全相同但必须保持“同一类模式”。比如每次都会出现分工但分工的具体人选可能不同——这叫涌现的稳定性如果每次都出现完全不同的荒唐行为那叫混沌。可干预你能通过调整某个参数稳定地压制或放大这个行为。比如把资源压力调低分工就消失把观察距离调大模仿就扩散更快。能干预说明现象在系统控制范围之内而不是不可控的意外。满足这三点我才愿意称之为“涌现”而不是“随机”。6. 跑起来的真实代价并发、上下文和token账单6.1 并发50个NPC同时思考是伪并发把规模从 5 个 NPC 扩到 50 个时我踩了一坑模型调用是串行的一个 NPC 决策需要两三秒50 个下来一轮就要两分钟游戏节奏完全跑不动。我第一反应是“上多线程并行调用”结果更糟——50 个 NPC 同时决策同一件东西可能被 5 个人同时捡走状态写入互相覆盖日志里全是矛盾和回滚。后来我换成了 actor 模式每个 NPC 是一个独立执行单元内部串行处理自己的决策全局的任务分发器只负责为不同 NPC 分配并行的 worker保证“跨 NPC 并行、同 NPC 串行”。同时我在行动执行器里加了最基础的乐观锁任何东西被取走之后状态版本号 1其他 NPC 的动作如果基于旧版本就被拒绝并提示“目标已不在那里”。这一步做了之后资源类逻辑瞬间稳定了。6.2 上下文塞爆了怎么办并发解决了下一个杀手是 token 消耗。每个 NPC 每轮决策都要携带角色设定、视野状态、短期记忆和检索到的长期记忆很快就把上下文窗口顶满了。我算了一笔账一个 NPC 每小时决策 30 次每次输入 4000 token一个 NPC 一小时就是 12 万 token50 个 NPC 就是 600 万 token跑一天的数字非常恐怖。我的解法就是前面提到的三层记忆再配合一个规则短期记忆超过 20 条时最早的 5 条会被压缩成 1 条摘要移动到长期记忆区检索长期记忆时最多只取 Top 5每条不超过 200 字。这套策略能把单次决策的上下文稳定压在 3500 token 左右而不是随运行时间无限膨胀。6.3 成本估算与模型取舍说到钱我给想复刻的朋友一个实际参考。如果全用商用大模型 API50 个 NPC 跑一个模拟日约 2 小时真实时间大概要消耗 2000 万 token成本非常可观。我的做法是“混合模型策略”日常感知、移动、简单交互全部用本地开源小模型跑输出质量虽然糙一点但胜在便宜且快只有每天晚上的“归档反思”和重大事件决策才调商用大模型让它在信息充足的情况下做长程规划。两种模型跑出来的角色有个明显差异本地小模型做即时行动没问题但让它写角色回顾时内容比较干巴经常只有“今天做了 X、Y、Z”这种流水账商用大模型则能在摘要里加入“我因此觉得……”这种自我认知再回流到 Prompt 里角色深度就有了显著提升。所以我的建议是别把昂贵的模型用在每一轮行动上把它放在“对记忆做沉淀”的环节性价比最高。模型策略适合场景单次输入token量成本本地开源小模型移动、采集、简单对话、即时反应1000~3000极低商用大模型每日回顾、重大事件复盘、长程规划3000~5000高仅关键节点使用7. 下一步计划与给想动手的人的三条建议这个项目离“成品游戏”还很远我现在主要在补三块一是世界的地形生成让河流、森林、矿点的分布影响社会分工二是文化传播比如 NPC 开始给某些地点起名字并把故事一代一代传下去三是更复杂的团体行为让 NPC 不只是两两交互而是能形成小团体并产生团体间的竞争与合作。每一条都不能贪多一次只加一个机制然后跑大量实验去观察它是否真的带来行为深度的变化。如果你也想做类似的 AI 自涌现游戏我的三条建议是第一先跑一个只有 5 个 NPC 的小镇把决策日志完整打印出来像看监控录像一样反复看十个小时直到你能一眼看出哪条行为链断了第二先把单 NPC 调通确保它能连续完成“出门、找资源、带回来”这种闭环任务再扩大到多 NPC否则你会被交互 Bug 淹没第三别一上来就写复杂的“社会规则”先保证世界状态一致性和事件传播不出错最简单的基础设施稳定之后涌现自己就会出现。最后分享一点个人感受自涌现游戏最迷人的时刻不是你写了一堆规则跑出一个复杂世界而是某个深夜你盯着日志突然看到一个从未写进代码里的行为模式冒出来——那个行为是系统的产物也是你亲手搭建的机制结出的果实。你在里面看到了“开发者没设计过的东西”那是一种很难被复制的成就感。这个坑很深但非常值得跳。