当 LLM 进入游戏玩法:从收权到放权
面向正在或打算把 LLM 接进游戏玩法的工程师。不聊模型训练,不聊 prompt 技巧,只聊工程权衡:权力给多少、能力从哪来、延迟怎么消化。
文章初衷:最近做一个 AI-native 的游戏服务器框架,有兴趣的可以看看(github.com/lamyinia/Be…) 本文多数判断来自这条路上的思考和探索,但全文基本不谈那个框架本身,只在需要举例时出现。想谈的是一个更普遍的问题:
LLM 进入玩法层之后,它和游戏主循环之间是什么权力关系?
约定的概念模型
后文所有论证建立在四条约定上。它们是简化,但不是过度简化——每一条都对应真实游戏架构中的不变量。
- 游戏是一个逻辑上单线程的主循环。 物理上当然可以多线程(渲染线程、IO 线程、worker 池),但玩法状态的变更只发生在明确定义的推进点上——tick 边界,或事件处理的临界区。锁、命令队列、帧同步,全是为守住这条不变量而存在的机制。
- LLM 是异步的外部协作者。 它不在你的线程里,没有帧的概念,不持有状态变更权。一次推理耗时几百毫秒到十几秒,且输出不确定。
- 两者之间只有两条通道:观察与影响。 观察,是把游戏状态的切片交给模型;影响,是模型的输出必须转化为主循环中的合法事件或动作才能生效。它经"影响"通道能走多远——这是全文的主题。
- 延迟与失败是常态,不是异常。 超时、限流、幻觉、格式漂移,按"一定会发生"来设计。
0、LLM 之前:被信任的不可预测
游戏 AI 不是新事物,它已经存在了三十年。把 LLM 之前的谱系摆出来,不是为了上历史课,而是因为每个坑位都被占过——知道坑位在哪,才知道 LLM 进来时到底替换了什么、又什么都没替换。
| 技术 | 坑位 | 现状 |
|---|---|---|
| —— 决策与行为 —— | ||
| 有限状态机 | 行为选择的骨架 | 还在,只是藏进了更大的结构里 |
| 行为树 | 反射层:tick 级快速反应 | 还在,且和 LLM 分层共存 |
| 效用系统 | "这么多事先做哪件"的排序 | 还在,是天然的降级兜底 |
| GOAP(目标导向行动规划) | 中期规划:手段到目的的动作串联 | 被工具循环部分接管 |
| MCTS(蒙特卡洛树搜索) | 封闭动作集上的权威决策器 | 被 LLM 部分接管 |
| —— 内容生成 —— | ||
| 噪声算法 | 世界的质感与随机性 | 没人想替换它 |
| 波函数坍缩(WFC) | 硬约束的内容生成 | 还在,与 LLM 生成互补 |
MCTS 值得多看一眼,它是 LLM 决策的直系前身。 围棋 AI、棋牌 bot 的结构是:枚举当前局面所有合法动作 → 前向模拟 → 选期望最高的那个。LLM 选择(后文会展开)的结构是:枚举当前局面所有合法动作 → 交给模型选一个。变的只是"搜索"换成了"直觉"。坑位没动。
GOAP 占的是"规划"的坑位,值得和 MCTS 对照着看。 F.E.A.R.(2005)发扬的这套结构:每个动作声明成"前置条件 + 效果",规划器从目标反向搜索出一条动作序列。它的现代继承者正是第一章的工具循环——多步、自主决定下一步的那种形态。一个耐人寻味的细节:GOAP 的动作声明(前置 + 效果)与 function calling 的工具声明(参数 schema + 副作用描述)结构同构——相隔二十年,"怎么描述一个可执行的动作",游戏 AI 和 agent 生态给出了同一个答案。
效用系统(Utility AI)大概是表里最陌生的一项,但例子一说就懂。《模拟人生》的 Sim "饿了吃饭、困了睡觉",背后就是效用打分:每个候选动作按当前需求算一个分数(有多饿、床有多远),选分最高的执行。行为树回答"刺激来了怎么反应",效用系统回答"这么多想做的事先做哪件"。后文它还会反复出现:第三章的降级终点,就是退回这套打分。
噪声算法则藏着全文最重要的一个对比。 Perlin 噪声生成地形、随机种子决定掉落——游戏的"不可预测"无处不在,玩家也确实感受不到下一次掷骰子的结果。但没人担心噪声算法的信任问题。为什么?
游戏随机是"被信任的不可预测":结果不可预测,但生成结果的代码是自己写的、确定性的、可审查的。 LLM 是"不被信任的不可预测":结果来自一个外部智能,输出即待验。
状态机的转移条件是 if 语句;行为树的优先级是自己排的;MCTS 的模拟是自己跑的。这些系统确实"智能",但它们的不可预测性全部产自引擎自己的代码。LLM 不同:它不是你的代码,也不是你的玩家,你却要把它的输出当真。信任问题从这时才出现。
内容生成这条线上还站着一位新成员:波函数坍缩(WFC)。 按邻接规则逐格坍缩拼图块,生成局部规则绝不违反的地图——近年独立游戏关卡生成的心头好。它和噪声同属"被信任的不可预测":规则是自己写的、可审查的。但它把内容生成的坑位分得更细:WFC 是硬约束生成,规则保证不破,但不懂语义;LLM 是软语义生成,语义连贯,但不保证任何硬规则。第一章"生成"形态的信任边界(引擎只验形式),正是为这个缺口设的:语义交给模型,硬规则留在引擎。
业界主流的 agent 框架——编排器、工具循环、多智能体框架——都默认一个前提:agent 拥有主循环,工具是被暴露给它的资源,任务跑多久由任务自己说了算。游戏恰好相反:主循环是主权者,一切 AI 都是嵌进循环的组件,必须服从帧预算和玩法节奏。两边都叫 agent,分歧只有一个问题——
主循环在谁手里?
一、权力谱系:收权与放权
先给词汇表,再给分界线。模型与引擎之间的交互形态,常见的有三种;但收权与放权的分界线不在形态上,而在另一件事——编排权。先看形态。
1.1 三种输出形态:生成、选择、工具调用(不是权力档位)
先钉一个容易被表格诱导出的误读:这三种是输出空间的形态,并列、不递进——生成和选择都默认是收权用法,工具调用骑墙。真正的权力分界线不在形态,在 1.2 的编排权;把三者误读成"放权程度递增",后面的判据就会全部对不上。用四个问题去照每一种形态——输出空间谁定义?信任边界在哪?延迟什么结构?失败怎么办?
| 生成 | 选择 | 工具调用 | |
|---|---|---|---|
| 输出空间 | schema 约束的自由数据 | 封闭合法集 | 开放函数签名 |
| 信任边界 | 只验形式,语义靠场景容错 | 快照验权 | 轮数预算 + 工具沙箱 |
| 延迟结构 | 一次往返 | 一次往返 | N 轮(有上限) |
| 失败形态 | 失败也回投(计数闭环) | 丢弃 + 日志(越权或过期) | 轮数耗尽 / 沙箱拒绝 / 部分写入,需补偿 |
注:信任边界与失败形态两行,是各形态在默认用法下的常见防线;工具调用骑墙——收权用法下它的防线是"验证每一步",见 1.2。
生成:模型产数据,引擎只验形式。 这是 LLM 应用最基础的形态(generation / structured output)。最小例子:玩家问路边的 NPC"这地方发生过什么",模型生成一段符合世界观的回答。注意模型返回的是一段文本(数据),不是任何游戏指令——它说得再离谱,引擎顶多做敏感词过滤和长度截断,最坏结果是这句话不通顺,游戏状态不会脏。
把这档的信任边界说精确:引擎验得了形式,验不了语义。 schema 合不合法、长度超没超、有没有敏感词——这些是形式,机器可查;这句话合不合世界观、人设对不对——这些是语义,引擎没有能力判断。所以生成档真正的信任边界不在引擎,在场景容错:这个场景语义错了也不致命,才走得通。叙事、建议、UGC 天然满足;反过来,任务结算文案、经济数值、排行榜判定理由——任何错了会写脏状态或引发纠纷的东西,哪怕看起来也是"文本",也不能走这档。工程上值得加一道"结果回投":失败不抛异常也不静默丢弃,而是作为错误结果走和成功同一条投递路径——发起 N 个请求最终一定收到 N 份结果,玩法侧用一个计数器就能确认无泄漏、无悬挂。这个"计数闭环"在第三章验证一节还会回来。
选择:封闭合法集 + 请求瞬间快照验权。 当模型的输出是权威动作、直接改游戏状态时——比如棋牌 bot 出牌,它必须从手牌里选一张,不能发明一张牌——最容易做错的事是把合法动作写进 prompt 然后相信模型不越界。它会的。这个思想在强化学习里有标准名字:合法动作掩码(legal action masking),策略输出前把非法动作屏蔽,只许在合法集里选。RL 的策略是自己写的,可以事前掩码;LLM 是黑盒解码器,管不了它吐什么——掩码于是翻转成事后验权,正确做法只有一句话:
请求发起的瞬间对合法动作集做快照;模型返回时对照快照验权——不对照模型的自述。
这个设计有三个容易做错的地方:
- 用编号,别用语义:别让模型抄写"打出三万"这样的语义字符串,把合法动作编号成 "0""1""2" 让它选编号。抄错编号的概率比抄错语义低一个量级,且天然规避字段格式自由发挥。局面描述里携带语义,模型做的是"选择",不是"复述"。
- 为什么是请求瞬间的快照:推理的几秒里局面可能已经变了。若拿"完成时的合法集"验权,会出现模型在它看到的局面下合法、在当前局面下非法的竞态。对照请求瞬间快照,语义才确定:它选的时候那步是合法的,就认。
- 输出契约与分发同源:哪种动作 JSON 解析到哪个处理函数、输出 schema 长什么样,都从同一份声明派生。手写 prompt 里的输出示例和手写的解析代码,迟早各改各的。
三个易错点落到代码上,就这么长:
// 请求发起的瞬间
struct ActionSnapshot {
uint64_t version; // 局面版本号
std::vector<ActionId> legal; // 合法动作编号
};
// 模型返回时(now = 当前局面版本号)
std::optional<Action> validate(const ActionSnapshot& snap, ActionId id, uint64_t now) {
if (std::find(snap.legal.begin(), snap.legal.end(), id) == snap.legal.end()) {
log_reject(id, snap.version); // 越权
return std::nullopt; // 丢弃:不重试、不猜、不进状态机
}
if (snap.version != now) {
log_stale(snap.version, now); // 世界已推进
return std::nullopt; // 作废:不重映射,转降级
}
return resolve(snap.version, id); // 编号映射回真实动作
}
但"认"不等于"直接执行"。快照解决的是模型有没有越权,还有一个独立的问题:我等它的时候,世界动没动。 模型按 V 版本选出的动作,回来时要面对的可能是 V′ 版本的世界——直接执行,就可能把 V 合法、V′ 非法的动作写进状态,越权方从模型换成了时间。两条路,按玩法选一条写死:
- 局面冻结(回合制、决策门):等待期间本就没有别的推进点会改这个局面,
snap.version == current_version恒成立,快照验权即充分——"选择"形态默认就活在这类场景里,3.4 的决策门正是它。 - 局面推进(实时玩法):返回时先比版本,不等则整次决策作废,转降级(3.6)。不要试图把 V 版本选出的动作重新映射到 V′ 上——那等于让引擎替模型做第二次猜测。
两次校验语义完全不同,别合并:快照验"模型有没有越权",版本验"这步现在还算不算数"。
工具调用:开放动作空间,用预算换自由。 这是 agent 生态的标准能力(function calling / tool use)。任务一次往返装不下时("查对局历史、总结打法、生成出场白"),需要工具循环:模型决定调哪个工具、读结果、走下一步,循环直到给出最终输出。防线有两道:轮数预算(防循环失控)和工具沙箱(工具的执行体在引擎侧,模型只能经"调用"间接触达状态——你注册了什么工具,它就有什么能力)。
三种形态之间也有中间地带:比如只让模型在传统决策器给出的候选集里做带理由的排序——第三章会回到它。
无论哪种形态,输出都要先变成机器可读的 JSON——这是三种形态共同的一层脏活。 schema 约束只是软约束:模型会用 markdown 代码块包裹 JSON、在前后加"好的,我来帮你"之类的自然语言,思考型模型甚至会吐出截断的前缀文本。容错解析(从一段自由文本里捞出第一个完整可解析的 JSON 对象)是每种形态都要写的第一道防御;新近的结构化输出 API 能缓解,但不能免除。这层没什么高明设计,就是得认。
生成与选择默认单次往返、无状态;工具调用的多轮循环自带上下文——那本账(连同会话记忆)挪到 2.1 末尾一起算。
形态不决定权力——那形态决定什么?爆炸半径的默认上限。 生成档的输出本身不碰状态机,它是否变成状态,取决于引擎拿这份数据去干什么——生成的任务文案被存进玩家日志,就已经是写状态了。所以最终上限仍由"引擎拿它做什么"决定,形态只是压低了默认档位:生成的默认上限天然比选择、工具调用低一档。这也是 1.3 的伏笔:叙事类 agent 放得起权,不是因为叙事天然无害,是因为这一档的默认半径就小。
1.2 权力的分界线:编排权在谁手里
三种形态本身不决定权力。收权与放权的分界线只有一条:流程的下一步由谁决定——编排权在引擎手里,还是模型手里。 这条分界在 agent 工程界已有通行词对——Anthropic 在 Building Effective Agents 一文里称为 workflows 与 agents:前者由代码预定义路径编排模型,后者由模型自主决定流程和工具使用。
- 收权:引擎编排。 生成和选择都是典型——引擎决定何时发起、发起什么,模型只是被问到时作答,输出全部经引擎验证才生效。工具调用也可以是收权用法:引擎按固定流程驱动工具循环,每步调什么、调几轮都是代码写死的。防线是验证每一次输出。
- 放权:模型编排。 "下一步调什么、要不要继续"交给模型自己决定,编排权从系统手里交出去。防线换了一整套:不再是验证每次输出,而是轮数预算、工具沙箱和兜底。
编排权还带走一样容易被忽略的东西:失败语义。收权的失败是"这次没做成"——引擎知道自己在第几步,状态干净,天然可回滚。放权的失败是"做了一半,且不知道做到哪了"——模型自主走过的路径,引擎没有账本,已发生的写操作不会自动回滚,只能靠工具的事务化、日志和补偿收拾残局。这条差异在 3.6 还会回来。
第0章结尾问"主循环在谁手里",答案在这里落地:编排权就是主循环的运营权。
放权端有一个已上线的实例:NVIDIA 的 ACE Game Agent SDK 与 KRAFTON 用它构建的 PUBG Ally(AI 队友 Ella)。它的 agent 循环是事件驱动的——玩家说话或游戏事件触发;工具横跨观测(自身状态、队友、战况)、知识查询、记忆更新;每周期工具循环 3–5 轮。动作不直接执行:System 1 行为树以 tick 率处理反射动作,System 2 语言模型管深思熟虑的意图理解与协作。
有意思的是 KRAFTON 自己的演进史。GDC 2026 上展示的还是 workflow 版:系统按预定义顺序调用各组件,语言模型只负责给定 prompt 的文本生成——编排权在系统手里,一个标准的收权设计。之后公开的架构已转向自主 agent 版,他们的原话:"它开始自己选择调用哪个工具、读结果、自己决定下一步。不再是系统给它指令——模型成为了决策者。"
驱动这次放权的是三个能力需求:主动性(没人问也开口)、记忆(跨局记住玩家偏好)、战略建议。而组件拆分的理由极其朴素,没有任何多智能体理论:
"拆分最实际的理由是 prompt 空间和延迟。单个 prompt 处理一切很快撞上下文上限。拆开的组件意味着各自独立的 token 预算和调用频率,可以独立优化。"
Action Agent 每轮必跑、Memory Agent 间歇执行、Strategic Agent 独立节奏、Proactive Agent 事件触发——四个 agent 不是一个"团队",是四份不同节奏的预算账本。
1.3 判据:一次幻觉,最坏能写到谁的状态里
那么收权还是放权,由什么决定?不是技术品味,不是模型能力,是一个能落到代码上的问句:一次幻觉,最坏能写到谁的状态里?
- 本地体验:错误输出只影响一个玩家自己的观感,行为树和降级链在下面接着——可以放权。
- 小队 / 房间共享状态:错误会写进几个玩家共同可见的状态——中间档,可以放权,但工具集必须按角色裁剪:能写的状态越少,越放得开。
- 全服权威状态:经济、账号、跨房间匹配——必须收权,快照验权不可谈判。
拿这个问句去验 PUBG Ally:它是多人游戏,却放了权——因为 Ella 跑在玩家自己的显卡上,炸的最多是这台机器的体验;工具集限定在"队友"角色内(观测、知识查询、记忆更新),碰不到经济与账号。放权不是因为 KRAFTON 胆大,是这两道裁剪把幻觉半径压回了中间档以下。反过来,同一个 Ella 若跑在服务端权威进程里、工具集不裁剪,判据立刻翻成"必须收权"。
同一家公司在同一个产品上从谱系的一端滑到另一端,说明收权与放权不是阵营之争:判据不是"单机还是网游",是幻觉能污染的状态范围——而范围靠两把刀裁:运行位置和工具集。
二、供给侧
权力定了,接下来是能力。agent 的三个外部依赖正好归成三条轴:能调什么(行动)、知道什么(知识)、算力从哪来(部署)。
2.1 行动轴:Agent Loop 是本体,MCP 是部署形态
工具循环(agent loop)的本体是一个朴素的结构:
提交消息(观察切片 + 可用工具的声明)
循环:
模型返回结果
若不是工具调用 → 循环结束,这就是最终输出
若是工具调用 →
校验:工具名在注册表里?参数过 schema?
生成工具执行事件,投回主循环
引擎在推进点执行 handler,结果回填为新消息
下一轮
一个值得圈出来的细节:工具的执行不在 loop 里,在主循环里。 handler 触达的是引擎状态,按概念模型第一条,状态变更只该发生在主循环的推进点——loop 负责"问",主循环负责"做"。这条分界漏掉的话,工具就会在循环外的线程上直接改游戏状态,单线程不变量悄悄破掉。
MCP(Model Context Protocol)就是这个 loop 的解耦形态:把 handler 搬到进程之外,顺手标准化了工具的发现、描述与调用约定。primitive 是 loop,MCP 只是行动能力的一种部署拓扑。
由此能推出一个反直觉的判断:游戏是少数"进程内执行才是常态"的领域。企业级 agent 生态默认工具在远处——数据库、SaaS、内部服务,跨进程是常态,所以 MCP 应运而生。而游戏的工具是引擎内存里的活数据:查牌河、查 NPC 状态、播一段动画,handler 就地执行零序列化。把这些搬出进程是自找的。所以游戏语境下 MCP 的正确角色是对接外部世界的桥(查百科、查运营配置、查第三方服务),而不是游戏内工具的组织方式。
loop 的隐性代价是上下文膨胀。 每一轮的工具调用与结果都追加进消息历史,大头是工具结果——一次对局历史查询就是几千 token。循环越长,窗口越胖,延迟与成本同步上涨;KRAFTON 把 Ally 拆成四个 agent 的头号理由(prompt 空间和延迟)就是它。配套的管理手法三层:一次性指令用完即弃,下一轮不再出现在 prompt 里;大型工具结果在循环结束后折叠成一行摘要;稳定内容(人设、规则、世界观)做成永生前缀,窗口超限时做摘要压缩——何时摘、摘到多短是玩法的决定,框架只提供机制。
这里其实是两本账。一本是上面的窗口预算:单次循环内的上下文膨胀与压缩。另一本是会话记忆:多轮对话的上下文、跨局记住的玩家偏好、随存档走的 NPC 记忆——这本账的设计问题是对话历史谁持有:引擎每次自己拼好完整上下文(玩法全权,但每处调用都要重写拼装逻辑),或者由一个有状态的 Agent 对象持有、可序列化可恢复(框架代劳,但状态的生命周期要跟实体与存档对齐)。没有免费的一边。
2.2 知识轴:按知识寿命,固化方式三档
模型需要知道游戏世界的知识。按固化发生在多早,从早到晚三档:
- 蒸馏进权重(版本级固化):规格交给 teacher 模型,蒸馏给 student。运行时零开销零延迟,但一次蒸馏一次成本,且知识随版本衰减——Ella 的官方文档写着她的知识截止于 41.1,之后上线的道具她不认识。适合封版周期长的稳定世界。
- 注入 prompt(发版级固化):规格写进 system prompt,随发布更新,成本最低;代价是每次请求都耗 token,大规格塞不进窗口。PUBG Ally 的配套做法值得借鉴:先约束世界(单地图、单模式)、物品三档分类(可用 / 可识别但不可用 / 不存在),"先决定不处理什么",再谈注入。
- 运行时检索 / RAG(不固化):知识活在查询里,内容打补丁立刻可见;代价是每次查询的延迟与检索质量。
判断式一句话:内容频繁打补丁的世界,任何固化都会腐烂,必须给模型留"现场查"的能力。
这一档位选择和 3.3 的生成时机谱系是同构的——"知识什么时候固化"与"内容什么时候生成",是同一个决策的两个投影:都在问"这件事该在离玩家多远的地方完成"。读第三章时可以用同一把尺自查。
2.3 算力轴:租与自有
"接 LLM 逃不开 HTTP"——多数时候成立,但成立的原因是商业现实而非技术必然:推理算力外置在别人的机房里,跨机器的默认选择就是 HTTP。通道其实一直在:官方 SDK(HTTP 藏在库后面)、同机独立进程(Unix 域套接字/共享内存)、进程内推理(直接链推理库)、离线烘焙(严格说它不是通道,是没有通道——运行时根本没有模型)。所以"用不用 HTTP"实质是"算力归谁管"的选型:
- 租(云 API):弹性、零运维;代价是延迟不可控、不可预算,限流和 5xx 都不受你控制。
- 自有(进程内或同机推理):延迟可预算、失败语义变成进程内错误;代价是容量自己扛——GPU 选型、批处理调度、显存预算都得自己做。
KRAFTON 给过一组实战数据:他们测过云 LLM 方案,"网络延迟加推理延迟让实时小队沟通感觉太慢",最终用 2B 量化模型塞进玩家显卡剩余的显存里。注意他们否决云方案的理由不是成本,是延迟不可预测——这直接验证了算力轴的定价逻辑。
进程内也不等于终点形态。直接链推理库意味着 continuous batching、请求队列、显存调度全要自己长——等于自建推理调度器。务实的两步走:先用独立推理进程跑通全部玩法(隔离崩溃、白送批处理),等部署规模值得省那一跳再换进程内。这里有一条好用的分层自检:
接口里看得见 status code、SSE chunk 的影子,就是分层漏了。
而无论租还是自有、换不换传输,真正不变的是两个边界:慢速非确定算力与硬实时循环之间的异步边界,输出不可信的信任边界——"逃不开"名单上仅有的两项。
三、玩法启发式:LLM 加入工具箱
游戏 AI 的传统本质就是启发式的组合:状态机加行为树加效用加噪声,叠了三十年。LLM 不是取代这个工具箱,是加入它。下面这些技法没有先后之分,按"什么时候用"组织——每一条都对应一个你已经遇到(或即将遇到)的问题。
3.1 启发式重排:让传统系统出题,LLM 只答卷
效用系统(或任何传统决策器)产出候选动作集,LLM 只做重排、加理由、选风格。这是收权思想在行为层的投影:模型碰不到动作空间本身,只在给定集合内做偏好排序。预算最小、风险最低,是实时玩法里最安全的一档。
3.2 AI-LOD:预算分配是第一性问题
把模型预算当渲染 LOD 分:主角队的 NPC 上完整推理,路人 NPC 跑传统启发式。KRAFTON 系里有一组现成对照——模拟人生类的 inZOI 用 0.5B 模型做单次推理(选动作、日常反思,无工具循环),PUBG Ally 用 2B 做带工具的迭代多步推理。同一家公司、同一模型家族,按品类分配算力档位。先问"谁值得上模型",再问"模型多聪明"。
3.3 生成时机谱系:把"等"变成"提前等"
LLM 输出不一定要在需要的那一刻生成。谱系从早到晚:离线烘焙(build 期生成对话树/背景故事,运行时零成本)→ 加载时(进关卡时按需生成局部内容)→ 运行时(真交互)→ 推测预生成(玩家还没问,就按上下文先生成好备着)。延迟问题的最优解常常不是优化推理,而是把生成挪到没有人在等的时刻。这根谱系正是 2.2 知识三档的镜像——那边问"知识什么时候固化",这边问"内容什么时候生成",同一个决策的两个投影。
3.4 agent 时钟:门与 deadline,冻谁的钟
模拟品类(模拟人生、RimWorld 类)有个独特资源:虚拟时间。三种时钟并存,以不同速率推进——真实时间不可暂停,世界时间可暂停可加速(模拟品类的变速档),agent 时间可冻结——每个 Sim 自带行动队列,"当前动作演完、队列空了、决策下一步"这个时刻就是天然的等待门。
一个有趣的思想实验:把主循环直接停住等 LLM 行不行?这个直觉的内核是对的——门是真的,deadline 是真的,超时不推这个 agent 的帧也是真的——但被卡住的只能是 agent 自己的钟,永远不能是世界的钟。 玩家对冻结画面的容忍是几百毫秒,而推理 p95 是好几秒;把世界停了,等待就成了 bug。正确实现是 pending 状态:角色发着呆、东张西望、播"思考中"动画,世界照常转,别的角色照常生活。到 deadline 还没结果?降级(见 3.6)。
这个模式有个被验证过的祖先:RTwP(实时暂停)——博德之门系列二十五年前就在做"需要决策就自动暂停"。被等的那个"慢速决策者"当时是人类玩家,超时降级是"AI 接管默认行为"。从"等玩家"到"等 LLM",结构一个字没改。
3.5 延迟掩盖:等待本来就是玩法语言
对手思考十秒是合法游戏状态——卡牌游戏甚至给 AI 人为加延迟装作思考。所以掩盖延迟的素材全是玩法母语:思考气泡、idle 动画、倾听姿态、话轮中的 backchannel(点头、"嗯")。加载界面是这个思路的极端形态:资产没到不能进关卡是最正当的"游戏在等",但没人靠冻结帧等资产。一旦想让等待看起来不卡,你就已经不能阻塞了——这个约束本身就逼出了正确实现。
3.6 降级链:从"有性格"退到"正常但平庸"
LLM 超时或验权失败之后去哪?模拟品类给了全品类里降级代价最低的答案:退回效用打分(饿了吃、困了睡)。Sim 的传统决策器本来就在,LLM 只是替换它——降级不是额外发明,是把增强撤掉。失败的表现不是"没动作",是"动作没那么聪明"。注意降级链是收权侧的失败语义——撤掉的是"增强",底下的效用系统本来就是完整系统。放权侧没有"把增强撤掉"这个动作可撤(1.2 说过:它做了一半,你不知道做到哪了),对应的失败语义是预算封顶、沙箱圈界和事后补偿,两边不通用。降级策略只有玩法自己能定义:快节奏玩法宁可降级不重试,慢节奏叙事重试三次都无所谓。把降级当框架的义务,是 LLM 接入里最贵的一种误判。
3.7 验证:找不变量,不找对答案
非确定系统的测试不能对答案,要找不变量。三个层级:协议层(模型是否遵守交互协议、正确使用工具——机器可查);闭环层(发起 N 个请求收 N 份结果,计数闭环查泄漏与悬挂);体验层(A/B 与真人 playtest)。KRAFTON 的验证栈就是这个三层:自动化协议检查 → playtest A/B → 千人规模玩家反馈。非确定输出的质量门槛是"不变量全部成立 + 体验抽样可信",它注定比确定性代码的验证松,所以爆炸半径的定价(第一章)才必须保守。
结语
回到开头的概念模型:LLM 是一个异步的、不确定的、不持有状态变更权的外部协作者。全文讨论的其实只有一件事——它经"影响"通道能走多远。三章是一条完整的选型链:第一章定权力边界——能不能动状态;第二章定能力来源——凭什么会做;第三章定时间预算——什么时候做、做不完怎么办。 能不能、凭什么、什么时候——问完这三个,接入方案就定了。有人会补第四问——花多少。但成本不是独立的第四轴,是行动与算力的共同产物:轮数 × 单次 token × 并发;前三问答完,这一问自己就有答案了。
- 收权端说:可以说,不能动;要动,先过快照。
- 放权端说:你来决策,预算封顶,行为树在下面接着。
- 判据从来不是哪个更先进,是你的爆炸半径装得下多大的失败。
而第0章的小伙伴们一个都没走:行为树还在 LLM 身边以 tick 率跑着(System 1),效用系统还在降级链的末端兜底,噪声算法还在生成没人想替换的世界质感。MCTS 和 GOAP 腾出的两个坑位——封闭动作集上的权威决策、多步规划——LLM 刚刚坐进去。
游戏 AI 三十年的传统不是被替换的对象,是 LLM 落地的地基。不是把游戏接进 agent,是把 agent 关进游戏。 如果你也在把 LLM 往玩法里接,先问权力,再谈智能。