构建沉浸世界的智能 NPC:Context is All You Need

AI 对话系统的核心工作 = 为每次对话组装最合适的上下文。本文以幽灵公主艾琳娜为线索,展示从传统预设对话到完整 AI 对话系统的八个演进阶段。

为 Unity 游戏构建了一套完整的 AI NPC 对话系统,让 NPC 能够根据世界观、角色人设、游戏状态进行智能对话。本文以一个具体案例为线索,展示系统从”传统预设对话”到”完整 AI 对话系统”的演进过程,最后揭示所有模块如何拼装成一个完整的上下文。


案例导入:玩家与幽灵的对话

全文将以这个案例为线索,展示系统从”传统预设对话”到”完整 AI 对话系统”的演进过程。

场景设定:


体验演进:从传统对话树到 AI 对话系统

阶段一:传统预设对话

传统的做法是写一棵对话树——每个问题对应一个固定的回答,玩家只能从预设选项中选。当玩家问”你知道关于黑龙战争的事吗?“,NPC 只能回答”抱歉,我不明白你在说什么”,因为策划没有预设这个问题的答案。

传统对话树的三大痛点:

阶段二:引入 AI 大模型

接入大语言模型后,NPC 可以回应开放问题了:

玩家:你知道关于黑龙战争的事吗?
AI:「黑龙战争?那是一场可怕的战争,发生在很久以前…」

但新问题出现了——AI 太自由,会胡编乱造:“黑龙战争死了一百万人,国王亲自出征”——这些全是 AI 编的,游戏里不是这样设定的。

关键洞察:AI 太自由了,我们需要约束 AI 只说应该说的内容——这就是世界书要做的事。

阶段三:世界书——约束知识边界

解决方案:创建一个”知识库”,当玩家提到某个话题时,把相关知识注入给 AI。

// 世界书条目示例
{
  "title": "黑龙战争",
  "keywords": ["黑龙战争", "黑龙", "尼德霍格"],
  "content": "黑龙战争发生在280年前,持续三年。黑龙'尼德霍格'袭击王国北境。
              最终被银月骑士团击退,但王国北部十城化为废墟。
              艾琳娜的兄长阿尔贝特王子在此战中阵亡。"
}

**触发机制:**玩家说”你知道黑龙战争吗?” → 关键词匹配 → 注入对应知识到 Prompt

效果:「黑龙战争发生在 280 年前,我的兄长阿尔贝特就是在那场战争中阵亡的…那头叫尼德霍格的黑龙,我至今还记得。」——知识准确了,与游戏设定一致。

但表达方式还是很机械——像在念百科全书,没有情感。

关键洞察:世界书解决了”说什么”的问题,但没解决”怎么说”的问题。我们需要给 NPC 注入性格和灵魂。

阶段四:角色卡——激活性格

为每个 NPC 写一张角色卡,定义它的性格、语气和情感表达:

你是艾琳娜,300年前因被诬陷通敌而被囚禁于此的公主幽灵。

## 性格特点
- 高贵但不傲慢,对善意的人友好
- 带着深深的悲伤和执念
- 对"背叛"这个词极其敏感
- 渴望被理解和帮助

## 说话风格
- 使用古典优雅的措辞
- 常用"......"表示沉默或回忆
- 提到过去时会变得忧伤

效果:

玩家提问有角色卡的回答
你是怎么死的?「…我被关在这里三年,最后病死在这冰冷的牢房里。那一天,是我 22 岁生日…时间太久了,我有时会忘记…」
你恨陷害你的人吗?「恨?…也许曾经恨过。但 300 年的时间,足够让恨意消散。现在我只想…证明我的清白,然后安息。」

世界书和角色卡的分工:

模块解决的问题内容类型共享性
世界书说什么(知识)事件、地点、物品、历史所有 NPC 共享
角色卡怎么说(性格)语气、措辞、情感、态度每个 NPC 独有

为什么要分开?黑龙战争是世界的客观事实,艾琳娜和酒馆老板都可能知道。但艾琳娜提到战争时会悲伤(因为兄长阵亡),酒馆老板则可能只是感慨。分开后可以复用:新增 NPC 只需写角色卡,关联现有世界书即可。

阶段五:认知限制——NPC 不该全知全能

通过角色卡中的关联字段,指定每个 NPC 能够访问哪些世界书条目:

{
  "npcName": "艾琳娜",
  "worldBooks": [
    "wb_dragon_war",         // 公共知识:黑龙战争
    "wb_ghost_castle",       // 公共知识:古堡历史
    "wb_elina_secret_letter" // 私有知识:只有艾琳娜知道信件位置
  ]
}
角色问”信件藏在哪”
艾琳娜(有私有知识)「…信件就藏在东塔的密室里。那是我临死前托侍女莉莉丝藏起来的…」
酒馆老板(无此知识)「信件?什么信件?你说的是那个古堡里的幽灵公主吗?我只听说过那个传说…」

阶段六:记忆系统——维持连贯性

对话历史会越来越长,超出 AI 的上下文窗口后就会被裁剪。三级记忆架构解决这个问题:

场景NPC 回答
第 20 轮:“你还记得我叫什么吗?”「艾德里安…当然记得。你是唯一一个说要帮我的人。」
跨会话(第二天登录):“我回来了。”「艾德里安!你真的回来了…我还以为你会像其他人一样,离开后就忘记我。」

阶段七:作者注释——运行时引导

作者注释是一种运行时动态注入的引导信息,告诉 AI”当前应该注意什么”。它像一个隐形的导演在幕后提词:

{
  "authorNoteContent": "当前情境:玩家刚获得东塔钥匙。你应该:
    1.表现出惊喜和希望 2.主动提到信件的事 3.引导玩家前往东塔"
}
无作者注释有作者注释
「你想聊什么?」「艾德里安!你手里拿的是…东塔的钥匙?!300 年了,终于有人能打开那扇门了…」

常见应用场景:玩家首次见面时引导自我介绍、任务完成后表现感激、玩家长时间未行动时委婉提醒、剧情高潮点时加强情绪。

阶段八:动态权重——聚焦话题

当系统注入了大量上下文,AI 可能会被不相关的信息干扰——玩家问”东塔钥匙在哪”,AI 却开始讲黑龙战争。解决方案是匹配权重加成

最终权重 = 基础优先级 × 匹配权重 × 新鲜度权重

效果(玩家问"东塔钥匙在哪"):
├── 东塔钥匙:50 × 1.5 = 75  ← 精确匹配,权重最高
├── 黑龙战争:70 × 0.8 = 56  ← 无匹配,降权
└── 古堡历史:60 × 0.8 = 48  ← 无匹配,降权

另外还有新鲜度衰减防复读——刚使用的信息降到 0.2x,让 NPC 不会反复说同样的话。

至此,八个阶段的演进完成。 能回应开放问题(AI 大模型)、知识准确不胡编(世界书)、有独特性格(角色卡)、认知有边界(私有记忆)、能记住对话(记忆系统)、能引导玩法(作者注释)、回答聚焦不跑题(动态权重)。但这一切的背后,本质上是在做一件事——拼装上下文。


全景:上下文的完整拼图

前面八个阶段,每个阶段解决一个具体问题,引入一个新模块。但读完之后你可能会问:这些模块最终是怎么组合在一起的?

答案很简单——它们全部被拼装成一段文本(Prompt),在每次对话时发送给 AI。AI 只是一个”补全器”,你给它什么上下文,它就基于什么来回答。给它一句”你是艾琳娜,一个幽灵”,回答冷冰冰的;给它完整的角色卡 + 世界知识 + 记忆 + 场景引导,回答就有血有肉。

所以,AI 对话系统的核心工作 = 为每次对话组装最合适的上下文。 这就是标题说的 Context is All You Need。

构建 AI 世界需要哪些材料

把前面八个阶段引入的所有模块整理成一张清单——这就是构建一个可控的 AI 世界所需要的完整材料:

材料解决什么内容举例共享性
世界书世界的客观事实黑龙战争的历史、古堡的地理、王国的政治所有 NPC 共享
角色卡NPC 的性格和说话方式艾琳娜的性格特点、说话风格、情感倾向每个 NPC 独有
认知关联NPC 知道什么、不知道什么艾琳娜知道密信位置,酒馆老板不知道每个 NPC 独有
记忆NPC 记住了什么对话摘要 + 长期记忆(跨会话)每个 NPC 独有
作者注释当前场景应该怎么表现“玩家刚获得钥匙,表现惊喜”按场景动态生成
游戏状态当前世界的实时状态时间、地点、天气、任务进度全局共享

这六种材料对应了现实世界中”人”对话时依赖的六种信息:

现实世界系统设计
世界客观存在的事实世界书
每个人独特的性格角色卡
每个人知道的不一样认知关联
每个人有自己的记忆记忆系统
对话时会根据情境调整作者注释
注意力集中在关键话题动态权重

这些材料是怎么拼装的

每次玩家发送一条消息,系统按以下流程把这些材料拼装成一个完整的 Prompt:

展开完整代码 · 27 行
玩家发送消息

  ▼ ① 加载角色卡
  │  PersonaManager 获取当前 NPC 的人设

  ▼ ② 匹配世界书
  │  根据玩家消息中的关键词,从世界书中查找相关条目
  │  同时根据认知关联过滤——只加载这个 NPC 有权访问的条目

  ▼ ③ 检索记忆
  │  查找对话摘要 + 长期记忆

  ▼ ④ 注入作者注释
  │  检查当前场景是否有运行时引导

  ▼ ⑤ 读取游戏状态
  │  时间、地点、天气、任务进度

  ▼ ⑥ 上下文编排
  │  收集以上所有片段,按动态权重排序
  │  在 Token 预算内裁剪(低权重的优先丢弃)

  ▼ ⑦ 组装 Prompt
  │  拼装为 SystemPrompt + Messages

  ▼ ⑧ 发送给 AI
     流式返回,打字机效果展示

关键在第 ⑥ 步:不是把所有材料都塞进去,而是按权重排序后在预算内裁剪。 和当前话题相关的信息权重高、排在前面;不相关的信息权重低,预算不够时优先丢弃。这就是为什么需要动态权重——它决定了有限的 Token 预算分配给哪些信息。

一个真实的 Prompt 长什么样

当玩家问”你知道黑龙战争吗?“时,系统最终拼装出的 Prompt:

展开完整代码 · 31 行
# SystemPrompt(实际发送给 AI 的内容)

## 角色设定
你是艾琳娜,300年前因被诬陷通敌而被囚禁于此的公主幽灵。
性格特点:高贵但不傲慢,带着深深的悲伤和执念......
[来自角色卡,~500 tokens]

## 作者注释
当前场景氛围:神秘、悲伤。引导玩家探索古堡秘密。
[来自作者注释,~50 tokens]

## 世界知识
[黑龙战争]
黑龙战争发生在280年前,持续三年......艾琳娜的兄长阵亡。
[来自世界书,关键词"黑龙战争"命中,~200 tokens]

[王子阿尔贝特]
艾尔文王国王子,艾琳娜的兄长。在黑龙战争中英勇战死......
[来自世界书,由"黑龙战争"条目递归触发,~150 tokens]

## 对话摘要
玩家自称艾德里安,是冒险者,表示愿意帮助艾琳娜证明清白。
[来自记忆系统,~100 tokens]

## 当前状态
- 游戏时间:夜晚
- 地点:古堡地下室
[来自游戏状态,~30 tokens]

---
总计:~1030 tokens(预算 1500 内)

这就是”上下文工程”的全貌——六种材料,按权重排序,在 Token 预算内裁剪,拼装成一段 Prompt 发给 AI。AI 收到什么就基于什么回答,所以 Prompt 拼得好不好,直接决定了 NPC 的回答质量。


性能优化

上下文编排不是没有成本的。如果每次对话都遍历所有世界书条目做关键词匹配,性能会成为瓶颈。几个关键的优化策略:

策略实现方式效果
上下文编排只注入相关片段,不是全部Token 减少 50-70%
倒排索引关键词 → 条目的映射表,O(1) 查找查询性能 250x-1000x 提升
正则缓存预编译正则表达式匹配性能 1000x 提升
Token 熔断硬性 maxTokens 限制防止超限
对话摘要早期对话压缩为摘要5-10x 压缩

优化后的实际数据:单次对话 Token 从 ~12,500 降到 ~1,500(节省 88%);本地处理耗时(世界书查询 ~0.2ms + 上下文编排 ~8ms)几乎无感知,用户感知的等待时间主要是 API 请求本身(~1 秒)。

内容创作方面,策划只需要写剧本(场景描述、角色设定、对话示例),后续由工具链自动拆分为角色卡和世界书条目,一键导入游戏。策划专注创意,工程交给工具。


总结

从传统对话树到完整 AI 对话系统,本质上是在解决一个问题:怎么在有限的 Token 预算内,给 AI 组装最合适的上下文。

八个阶段,每个阶段引入一种新的”材料”:

  1. AI 大模型 — 能回应开放问题,但会胡编
  2. 世界书 — 约束知识边界,让回答准确
  3. 角色卡 — 注入性格,让回答有灵魂
  4. 认知限制 — 每个 NPC 只知道该知道的
  5. 记忆系统 — 跨轮次、跨会话的连贯性
  6. 作者注释 — 运行时动态引导
  7. 动态权重 — 确保回答聚焦当前话题

这些材料最终被拼装成一段 Prompt——世界书提供事实、角色卡提供性格、认知关联控制边界、记忆维持连贯、作者注释引导方向、动态权重聚焦话题。AI 收到这段精心编排的上下文,输出的就是一个知道世界观、有自己性格、记得和你说过什么的 NPC。

Context is all you need.