一个宅邸命案的证词里,管家说案发的晚上十点他一直在酒窖清点酒瓶。三小时后玩家翻回账本,发现十点酒窖钥匙明明在厨娘手里。玩家会立刻分成两种反应:一种是“找到破绽了”,另一种是“系统是不是写错了”。这两种反应是推理游戏最重要的分界线,而AI生成恰恰最容易把前者悄悄变成后者。
无限生成不是难点,可推理才是
语言模型很擅长生成看起来合理的文本,但“看起来合理”和“逻辑上成立”是两回事。直接让模型一口气写完整个案件,常见的问题有几类:时间对不上,人物知道了不该知道的事,证词彼此矛盾却不是有意的谎言,线索指向的结论与真相不符,或者关键证据根本没被放进玩家能到达的地方。
更麻烦的是,这些错误在单次阅读时几乎看不出来,只有当玩家把证词逐条对照时才暴露。玩家花了三个小时推理,最后发现案件本身有漏洞,这种挫败感几乎无法弥补。因此问题的重心应该从“怎样生成更多案件”转向“怎样保证每个生成的案件都能被推出来”。
四层结构:谁负责保存什么
比较稳妥的做法是把案件拆成四层,每层只管一类信息,层与层之间靠明确的引用连接。
| 层 | 保存内容 | 谁可以读 | 典型错误 |
|---|---|---|---|
| 真相层 | 时间线、地点、动机、手段、机会 | 仅系统与校验器 | 时间冲突、动机缺失 |
| 人物知识层 | 每人知道、不知道、隐瞒、会说的谎 | 对应角色的对话生成 | 知道了不该知道的事 |
| 证据层 | 物证与文件、位置、获取条件 | 玩家探索时触发 | 线索不可达、指向错误 |
| 玩家信息层 | 玩家已见证词、已获证据、已做笔记 | 提示系统与验证器 | 提前泄底、遗漏关键项 |
这里的关键分工是:只有真相层是“事实”,其他三层都是真相的投影。人物知识层是真相经过“这个人所能看到的范围”过滤后的版本,证据层是真相在物理世界里留下的痕迹,玩家信息层是前两者被玩家实际接触到的那一部分。任何一层出现无法从真相层推出的内容,就是错误的候选。
真相层与人物知识层
真相层需要先写完,再去生成其他内容,这也是先建立“真实发生了什么”的原因。它不是一段故事文字,而是一份带时间戳的事件账本:谁在什么时间、什么地点,做了什么,用了什么手段,留下了什么东西。动机、机会与手段是三个必须都能被填上的字段,缺任何一个,案件就没有凶手。
人物知识层在此之上,为每名角色单独建一份“他所知道的世界”:他亲眼看到什么、听说了什么、以为自己知道什么、故意隐瞒什么。谎言在这里被显式登记:说什么、为什么说、与真相相差在哪里、什么证据能戳破。这样“嫌疑人说谎”与“系统自己前后矛盾”就有了区别,前者是登记过的、有目的的偏差,后者是没有登记的偏差,具体区分可以参考嫌疑人说谎和AI自相矛盾的区别。
证据层与玩家信息层
证据层要回答两个问题:这份证据证明了什么,玩家怎样才能拿到它。“怎样拿到”会形成一张可达性图:房间、上锁的抽屉、需要先对话才出现的物品,都是图上的节点与条件。关键线索的放置尤其要检查,具体方法在关键线索不会因随机生成而无法找到一文里展开。
玩家信息层则像一份持续更新的“玩家笔记”:玩家听到了哪些证词,拿到了哪些证据,做出了哪些标记。它有两个用途:一是防止系统把玩家尚未获得的信息在对话里提前说出来,二是让可解性验证有一个明确的输入,只从这一层出发,看能否推出真凶。长期状态的保存方式,与桌游主持人的长期记忆有不少共通之处。
一致性校验:案件发布前的几道关卡
- 时间线冲突检测:把所有事件按时间排序,检查同一个人是否同时出现在两个地点,移动耗时是否合理,物品是否在被拿走之前就出现在别处。
- 不在场证明校验:对每个嫌疑人的不在场说法,用真相层核对;说法为真的要有支持证据,为假的要留有可被戳破的证据。
- 证词与真相的差分:逐条比较证词与真相,把差异分成“无意的错误”“有意的谎言”“系统错误”。系统错误必须为零,谎言必须能被至少一条证据戳破。
- 关键线索可达性检查:从玩家起点出发,模拟探索,确认每个关键推断至少有两条独立的证据链可达,避免单点失败。
- 可解性验证:只给求解器或另一个AI玩家信息层,不给真相层,让它反推凶手,检验结论是否唯一并与真相一致。
这五步里,最后一步最有价值,也最难做。它需要一个“不知道答案”的推理者,因此必须与生成案件的模型隔离,否则会因为共享上下文而得出虚假的“可解”。
一个宅邸案例:一次校验失败与修复(示例)
下面是一个完全虚构的小案例:某宅邸晚宴当夜,主人林先生死于书房。五名嫌疑人是管家、女仆、厨娘、侄子和医生。真相层里,凶手是侄子,动机是遗嘱,手段是下药,机会窗口在晚上九点五十到十点二十之间。
truth.events:
- t: 21:50 who: 侄子 where: 书房 do: 在酒杯中加入药物
- t: 22:00 who: 管家 where: 酒窖 do: 清点酒瓶
- t: 22:20 who: 林先生 where: 书房 do: 饮酒后倒下
knowledge.管家:
knows: [22:00 自己在酒窖]
hides: [曾与林先生争吵]
lies: [{claim: "整晚未离开酒窖", breaks_by: evidence.酒窖登记簿}]
evidence.酒窖登记簿:
location: 酒窖 · 抽屉 requires: 钥匙(厨娘持有)
第一次校验时,时间线检测发现:管家的证词是“十点整晚都在酒窖”,而真相层里,酒窖钥匙十点前后一直在厨娘手里,管家根本进不去。这不是谎言,而是系统错误,因为没有任何证据可以戳破它。系统的处理是回到真相层,判断哪一边应该修改。这里选择改真相:让管家在九点五十五分向厨娘借了钥匙,并把这次借用写进厨娘的知识层,厨娘就成为一个能证明管家说法的证人。
修复之后,可达性检查又发现一个新问题:唯一能证明侄子加药的证据是酒杯上的指纹,它被放在了上锁的书房里,而书房钥匙只有主人持有。系统于是增加了一条独立线索:女仆在九点四十五看到侄子从书房方向走来,并把这份目击写进她的知识层,同时让她在“被追问时间”后才愿意说出来。最后,用另一个AI从玩家信息层反推,得到的结论是“侄子”,唯一且与真相一致,这份案件才能发布。
目前仍然没有好办法的地方
有几件事目前没有特别理想的解法。一是“可解性”与“难度”是两个问题:验证器只能说“能推出来”,不能说“推起来有意思”。二是台词生成仍然会让语言模型在细节里泄漏没登记过的信息,需要在输出后再做一次知识边界过滤。三是玩家的自由提问会不断产生新状态,玩家信息层必须持续更新,否则验证过的案件也会在游戏中途被玩家的提问撕开口子。
PA真人游戏世界智能研究组的思路是:先承认语言模型擅长表达而不擅长记账,把账本交给结构化数据,让模型在账本约束下发挥。想继续看这类内容,可以浏览PA真人AI推理游戏栏目。