在设计 World Agent 时,我希望它更接近开放世界游戏,而不是把所有世界设定一次性塞给模型。
prpg.fun 玩家与角色进行地点转换的工具调用
开放世界游戏通常只加载玩家当前区域的地图、角色和物件,远处内容则暂时卸载。受到这个思路启发,我设计了地点和角色动态载入系统,希望让 AI RPG 也拥有类似 LOD 的上下文管理能力。
为什么没有完全采用世界书
我考察过主流角色扮演工具中的 World Info / Lorebook 方案。它们通常扫描最近几轮对话,根据关键词、正则或语义相似度,动态召回地点和角色的详细设定。SillyTavern World Info
这种方式适合补充背景资料,但不适合单独承担当前场景管理。
玩家可能连续几轮都在同一个地点行动,却没有再次提到地点名称。此时相关世界书条目可能不再触发,模型只能依赖有限的历史信息自行补全,场景规则和角色设定就可能逐渐漂移。
主流工具确实提供了常驻条目、sticky、角色绑定和聊天绑定等补救机制,但它们本质上仍然是在控制 Lorebook 条目的触发和保留时间。群聊中的角色 Lorebook 通常也是被合并后参与扫描,而不是根据运行时位置自动判断谁在场。SillyTavern World Info 机制
因此,我没有把当前场景完全交给世界书触发,而是设计了独立的 World Runtime。
当前场景持续保留
我的核心思路是区分三种内容:
- 当前正在发生的场景;
- 暂时不在场的地点和角色;
- 可能被提及的外围世界资料。
只要玩家仍处于某个地点,系统就持续把这个地点和在场角色的关键设定保留在主 LLM 的提示词中。即使最近几轮没有再次提到地点名称,模型仍然知道当前在哪里、有哪些角色在场,以及这个场景有什么规则。
当玩家切换地点,或者角色离开场景时,系统才卸载详细设定,只保留必要的运行状态、摘要和关系记忆。
对我来说,世界书更像知识检索,而地点动态载入更像运行时场景管理:
世界书:
提到这个地点时,需要补充哪些背景?
World Runtime:
玩家现在在哪里,谁正在场?
从静态地点到运行态
开发过程中,我逐渐把世界内容和当前剧情运行态分开。
World Agent 保存相对稳定的内容:
- 世界规则;
- 地点模板;
- 角色设定;
- 地点和角色的基础关系。
World 会话则保存当前剧情中的运行态:
- 玩家所在地点;
- 当前场景中的角色;
- 角色之间的位置变化;
- 剧情中临时生成的地点;
- 与当前场景有关的状态和记忆。
地点模板描述“这个地方是什么”,运行态描述“玩家当前正在经历什么”。
让主 LLM 管理地点注册表
地点切换并不完全依赖服务端识别玩家文本。剧情中可能出现玩家主动前往、角色离场、角色被带走,或者临时生成新地点等情况,单纯依靠关键词很难覆盖。
因此,我让主 LLM 使用 edit_location_registry 工具管理地点注册表。
模型可以根据剧情移动玩家和角色,也可以创建临时地点。工具会先校验本次变化,并返回更新后的地点列表、当前在场角色以及需要加载的新角色资料。
模型拿到结果后继续生成剧情。只有 assistant 消息成功保存,地点和角色变化才会正式提交到运行态。
类似 LOD 的上下文加载
这套机制可以理解为一种适用于 AI RPG 的上下文 LOD:
当前地点
-> 加载完整场景设定和在场角色
刚刚离场的角色
-> 保留摘要、状态和必要记忆
远处地点与未登场角色
-> 暂不加载详细设定
角色重新进入场景时,再恢复相关设定。这样既能保持当前场景的稳定性,也不会让整个世界长期占用上下文。
玩家仍然可以手动切换地点
虽然主 LLM 可以根据剧情调用地点工具,但我没有取消玩家主动切换地点的能力。
玩家可以通过界面选择前往其他地点,模型也可以根据剧情推动角色移动。两种方式最终都进入同一个运行态更新流程,避免模型状态和界面状态出现分歧。
最终效果
现在,World Agent 的地点处理流程大致是:
World 配置初始化运行态
-> 主 LLM 读取当前地点和在场角色
-> 根据剧情调用地点注册表工具
-> 预演地点和角色变化
-> 继续生成剧情
-> 消息保存后提交运行态
-> 更新下一轮需要加载的上下文
当前场景的关键设定会持续留在提示词中,不会因为几轮对话没有再次出现关键词就被移除;不在场的角色和地点则不会长期占用详细上下文。
这套方案不是要取代世界书。世界书仍然适合保存远处地点、历史资料和偶然提及的背景。只是对于 AI RPG 来说,当前地点和在场角色不应该被当成普通知识条目,而应该被当成持续存在的游戏运行状态。
这正是我设计地点动态载入系统的初衷:让模型只重点关注玩家正在经历的场景,同时让这个场景始终保持稳定、具体,并能够随着剧情自然变化。