Skip to content

知识库与条目

条目是你喂给 AI 的"记忆碎片"——把角色设定、世界观、剧情线索、写作风格拆成独立的小卡片,引擎会根据情况自动挑选、组装,拼成最终发给 AI 的提示词。


简单版

条目到底是什么?

你可以把条目想象成一本百科全书里的"页"。AI 的记忆是有限的(上下文窗口),你不可能把整个世界观一股脑塞进去。知识库系统的思路是:把信息拆碎,按需投喂。

比如你的世界里有一座"暗影森林",但玩家可能一百条消息都不会提到它。那这段描述就不需要每次都占用宝贵的 token。你可以把它做成一个带关键词的条目——只有玩家聊到"森林"、"暗影"、"树林"的时候,引擎才会把这段描述塞进提示词里。

编辑器里怎么操作

在编辑器里,条目有两个关键设置:

  • 发送方式(Send as):决定 AI 怎么看待这段内容
    • Instruction — AI 当成系统规则遵守(最常用)
    • User — AI 以为是玩家说的话
    • AI — AI 以为是自己说过的话
  • 标签(Tags):用来分类管理——Characters、Plot、Style、Example、Preset 等

条目放在哪个分组决定了它的行为:

  • 预设 — 始终发送
  • 示例 — 示例对话
  • 聊天历史 — 关键词触发
  • 后置 — 后置兜底指令

引擎内部的 Role 字段

引擎底层每个条目还有一个 role 字段(characterloreplotstyleexamplegreetingsystemcustom 等),用于内部分类。在编辑器里,这个字段通过 Tags 自动映射——比如加 Characters 标签对应 role: character。你不需要手动管 role,知道有这么回事就行。

关键词触发

给条目添加关键词(keywords),引擎会扫描玩家最近的消息。只要消息里出现了关键词,这个条目就会被激活,内容被注入提示词。

比如一个条目的关键词是 ["森林", "树林", "暗影"],那玩家说"我走进了那片树林"时,这个条目就会被触发。

alwaysSend:永远生效

如果你希望一个条目不管玩家说什么都会被发送给 AI——比如角色的核心描述、世界的基本规则——把 alwaysSend 设为 true 就行了。这类条目不受关键词限制,每次对话都会包含在提示词里。

最简单的角色条目

json
{
  "name": "艾莉丝",
  "content": "艾莉丝是一位年轻的精灵法师,银色长发,翠绿色的眼睛。她说话温柔但偶尔毒舌,喜欢用植物做比喻。",
  "role": "character",
  "section": "system-presets",
  "alwaysSend": true,
  "keywords": [],
  "enabled": true
}

就这么简单。这个条目会在每次对话中都被发送给 AI,因为 alwaysSendtrue


详细版

条目字段 — 编辑器里你会看到什么

在编辑器里点击 + 添加条目,你会看到以下字段。下面是每个字段的位置和作用。

基础字段

编辑器字段在哪里找到它是干什么的
名称条目面板顶部条目的标题,显示在侧边栏列表中。也用于示例对话中解析角色名
内容主文本区域AI 读到的正文内容。支持宏替换,比如 {{char}}{{user}}
标签名称下方分类管理用的标签(Characters、Plot、Style、Example、Preset 等)。标签会自动映射到内部 role 字段——比如加 Characters 标签对应 role: character
启用 开关右上角关闭后,这个条目完全不参与匹配和注入

投送控制

编辑器字段在哪里找到它是干什么的
分组条目面板中的下拉菜单条目投送到提示词的哪个区域:预设、示例、聊天历史、后置。详见下方"四大区域"
位置分组旁边的数字输入框同一分组内的排序优先级。数字越小越靠前。支持小数——用 2.5 可以插在 23 之间
始终发送 开关条目面板中打开后,不管关键词是否匹配,每次都包含在提示词里
深度数字输入框(只在分组为"聊天历史"时显示)从聊天记录末尾往回数第几条消息的位置插入。比如深度 4 就是插在倒数第 4 条消息前面
发送方式条目面板中的下拉菜单AI 怎么看待这段内容:Instruction(系统规则)、User(AI 以为是玩家说的)、AI(AI 以为是自己说过的——可以用来"预填充"回复开头)

关键词匹配

编辑器字段在哪里找到它是干什么的
关键词关键词输入区域主关键词列表。任意一个命中就触发条目(OR 逻辑)
匹配完整单词关键词旁边的复选框勾选后,"for" 不会匹配 "forest"
模糊匹配关键词旁边的复选框允许容错匹配。5 个字符以下允许 1 个拼写错误,更长的允许 2 个。仅适用于拉丁字母,对中日韩文字无效
二级关键词主关键词下方在主关键词命中后做进一步筛选的额外关键词
二级逻辑二级关键词旁边的下拉菜单二级关键词的组合方式:AND_ANY、AND_ALL、NOT_ANY、NOT_ALL(详见下方"二级关键词逻辑")

条件与递归

编辑器字段在哪里找到它是干什么的
条件条目的条件区域基于游戏变量的触发条件。每个条件包含一个变量、一个运算符(等于、大于等)、一个目标值
条件逻辑条件区域的下拉菜单多个条件的组合方式:全部满足(AND)或 任一满足(OR)
阻止递归高级设置中的复选框本条目可以被触发,但它的内容不会去扫描和触发其他条目
排除递归高级设置中的复选框本条目完全不参与递归扫描——只有直接匹配玩家消息才能触发它

组织管理

编辑器字段在哪里找到它是干什么的
标签条目名称下方自定义标签,方便在侧边栏里分类和筛选
文件夹侧边栏拖拽或文件夹选择器条目所属的文件夹——纯粹是组织工具,不影响运行时行为

四大区域(section)详解

条目被投送到提示词的位置,由 section 字段决定。你可以把发给 AI 的完整提示词想象成一个三明治:

[system-presets]   <-- 最上面:核心设定,AI 最先看到
[examples]         <-- 示例对话:教 AI 怎么说话
[chat-history]     <-- 中间:玩家和 AI 的对话记录
  (depth 插入点)   <-- depth 条目在这里见缝插针
[post-history]     <-- 最下面:兜底指令,AI 最后看到

system-presets — 系统预设

这是提示词的"开头"部分。放在这里的内容 AI 一定会看到,而且会最先看到。适合放:

  • 角色核心描述(character)
  • 世界观总述(lore)
  • 写作风格要求(style)
  • 场景设定(scenario)

这个区域的条目通常设为 alwaysSend: true,因为它们是世界运转的基础。

examples — 示例对话

专门用来放示例对话的区域。role 为 example 的条目会被特殊解析——引擎会把它们转换成一组 user/assistant 消息对,让 AI "看到"几轮示范对话。

示例对话的格式:

<START>
{{user}}: 你好,艾莉丝。
{{char}}: *微微侧头,银发滑过肩膀* 哦?来访者吗。你看起来比上一棵枯萎的仙人掌还要迷茫。
<START>
{{user}}: 这里是什么地方?
{{char}}: *轻轻一笑* 你管这叫"什么地方",我管这叫家。翡翠森林,精灵的领地——至少在人类砍掉最后一棵树之前是这样。

关键点:

  • <START> 分隔不同的对话段落
  • {{user}} 代表玩家,{{char}} 代表角色
  • 也可以直接用角色名(比如 艾莉丝:)代替 {{char}}
  • 引擎会在每段前面自动插入 [Example Chat] 标记

chat-history — 聊天历史中的深度插入

这个区域的条目不会出现在提示词的开头或结尾,而是"插入"到聊天历史的特定位置。通过 depth 字段控制插入点。

这特别适合需要"提醒" AI 当前状态的内容——比如角色当前的情绪、场景的环境描述。放在聊天历史中间,比放在开头更容易被 AI "注意到"(因为 AI 对中间位置的注意力分配不同)。

post-history — 后历史/越狱指令

放在所有聊天消息之后、AI 开始生成回复之前的"最后一句话"。因为 AI 对最后看到的内容印象最深,这里适合放:

  • "记住,你是 XX,不要打破角色"
  • "用中文回复"
  • "回复长度控制在 500 字以内"
  • 任何你希望 AI "最后再强调一遍"的指令

深度插入(depth)

depthchat-history 区域的专属字段。它的意思是"从聊天记录末尾往回数第 N 条消息的位置"。

举个例子。假设聊天记录是:

[1] 用户: 你好
[2] AI:   你好呀
[3] 用户: 森林在哪?
[4] AI:   往北走
[5] 用户: 好的,出发

如果一个条目的 depth2,那它会被插在倒数第 2 条消息之前(也就是 [4] 前面),变成:

[1] 用户: 你好
[2] AI:   你好呀
[3] 用户: 森林在哪?
--- [条目内容插入在这里] ---
[4] AI:   往北走
[5] 用户: 好的,出发

depth: 0 意味着插在最末尾(和 post-history 效果类似)。数字越大,插入位置越靠前。


模糊匹配(useFuzzyMatch)

开启后,引擎会用 Levenshtein 编辑距离算法做容错匹配。简单说就是允许拼写错误:

  • 关键词 5 个字符以内:允许 1 个字符的差异("magic" 可以匹配 "magik"
  • 关键词 5 个字符以上:允许 2 个字符的差异("forest" 可以匹配 "forset"

限制:模糊匹配对中日韩文字(CJK)不生效。CJK 文字只用精确匹配或子串匹配。

另外,关键词还支持正则表达式。如果你的关键词写成 /pattern/flags 的格式(比如 /dark\s*forest/i),引擎会把它当正则来用。


二级关键词逻辑(secondaryKeywords)

主关键词是"门槛"——只要命中任意一个就算匹配。但有时候你需要更精细的控制,这就是二级关键词的用武之地。

工作流程: 先检查主关键词(至少一个命中),然后用二级关键词做进一步筛选。

四种组合逻辑:

逻辑含义例子
AND_ANY主关键词命中 二级关键词至少命中一个主词 ["森林"],二级 ["精灵", "树人"]:玩家说"森林里的精灵" -> 触发;说"森林真美" -> 不触发
AND_ALL主关键词命中 二级关键词全部命中主词 ["森林"],二级 ["夜晚", "危险"]:只有"夜晚的森林很危险"才触发
NOT_ANY主关键词命中 二级关键词一个都没命中主词 ["森林"],二级 ["安全", "美丽"]:只要玩家没提到"安全"或"美丽"就触发——这是一个"排除"逻辑
NOT_ALL主关键词命中 二级关键词没有全部命中主词 ["森林"],二级 ["A", "B"]:只要不是 A 和 B 同时出现就触发

递归触发(recursion)

递归是一个强大但需要小心使用的功能。它的意思是:条目 A 被触发后,A 的内容本身会被当作"新的文本"再扫描一遍,看看能不能触发条目 B。

例子: 条目 A 关键词是"森林",内容里提到了"精灵"。条目 B 的关键词是"精灵"。如果开启了递归(世界设置中 lorebookRecursionDepth > 0),那玩家只要提到"森林",就会连锁触发 A 和 B。

递归深度由世界设置的 lorebookRecursionDepth 控制,范围 0-10,默认 0(关闭)。

两个安全阀:

  • preventRecursion: true — 本条目被触发后,它的内容不会被拿去扫描别的条目。"我可以被触发,但我不会触发别人。"
  • excludeRecursion: true — 本条目完全不参与递归轮次。只有玩家消息的直接匹配才能触发它。"只有玩家亲口说的话才能叫醒我。"

条件触发(conditions)

除了关键词,条目还可以基于游戏变量的状态来决定是否生效。

每个条件包含三个要素:

  • variableId — 要检查哪个变量
  • operator — 比较运算符:eq(等于)、neq(不等于)、gt(大于)、gte(大于等于)、lt(小于)、lte(小于等于)、contains(字符串包含)
  • value — 比较的目标值

conditionLogic 控制多个条件之间的关系:

  • "all" — 所有条件都满足才触发(AND)
  • "any" — 任一条件满足即触发(OR)

条件和关键词是"双重门槛"——两者都要通过才会触发。如果一个条目同时有关键词和条件,那流程是:先看关键词是否命中,再看条件是否满足,两者都通过才注入。


文件夹组织

当你的世界有几十上百个条目时,列表会变得很混乱。文件夹(entryFolders)让你按逻辑分组管理。

每个文件夹有自己的 section(对应四大区域之一)和 order(排序),还可以折叠(collapsed)。条目通过 folderId 关联到文件夹。

这纯粹是编辑器里的组织工具,不影响运行时行为。


apiRole 覆盖

默认情况下,所有条目都以 system 身份发送。但有些场景你需要不同的身份:

  • apiRole: "user" — 以用户身份发送。某些模型对"用户说的话"比"系统指令"更重视。
  • apiRole: "assistant" — 以 AI 助手身份发送。这相当于"预填充"——告诉 AI "你之前说过这些话",可以用来引导回复风格。

用法:在 system-presets 或 post-history 区域的条目上设置 apiRole 即可。


position 排序

position 是一个浮点数,控制同一区域内条目的先后顺序。数字越小越靠前。

支持小数点,所以你可以用 2.5 把一个条目插在 position 为 23 的条目之间,而不需要重新编号所有条目。

当两个条目的 position 相同时,关键词匹配得分更高的优先。


示例对话格式

role 为 example 的条目需要遵循特定格式,引擎才能正确解析成 user/assistant 消息对:

<START>
{{user}}: 你能治好这个伤口吗?
{{char}}: *检查了一下伤口,皱眉* 这可不是普通的刀伤。里面有诅咒的残留。我需要月光花的花粉——不过现在是白天。
{{user}}: 那怎么办?
{{char}}: *耸肩* 要么等天黑,要么你忍着。我建议后者,毕竟痛苦是最好的老师。
  • <START> 分隔不同的对话示例
  • 引擎会把每段解析成真正的 user/assistant 消息,而不是一大段纯文本

关键词扫描范围

引擎不会扫描所有历史消息——那样太慢也太浪费。世界设置中的 lorebookScanDepth(默认 2)控制扫描最近几条消息。设为 4 就是扫描最近 4 条消息来匹配关键词。在编辑器的 知识库 区域点击展开 Entry Settings 即可修改。

另外还有 token 预算控制:lorebookBudgetPercent(默认 100%)和 lorebookBudgetCap(默认 0 = 不限)限制触发条目总共能占用多少 token。超出预算时,匹配得分更高的条目优先保留。


技术参考:JSON 字段映射

以下是编辑器字段与 worldEntrySchema 底层 JSON 字段的对照表(源码:packages/engine/src/world/schema.ts)。导出/导入世界文件或直接调用 API 时会用到。

基础字段

JSON 字段类型必填编辑器对应
idstring自动生成的唯一标识符
namestring (min 1)名称
contentstring内容
roleenum (system, character, personality, scenario, lore, plot, style, example, greeting, custom)通过 标签 自动映射
enabledboolean否(默认 true启用 开关

投送控制

JSON 字段类型默认值编辑器对应
sectionenum (system-presets, examples, chat-history, post-history)-- (必填)分组 下拉菜单
positionnumber0位置
alwaysSendbooleanfalse始终发送 开关
depthnumber (int)--深度(仅"聊天历史"分组)
apiRoleenum (system, user, assistant)--发送方式 下拉菜单

关键词匹配

JSON 字段类型默认值编辑器对应
keywordsstring[][]关键词
matchWholeWordsbooleanfalse匹配完整单词
useFuzzyMatchbooleanfalse模糊匹配
secondaryKeywordsstring[][]二级关键词
secondaryKeywordLogicenum (AND_ANY, AND_ALL, NOT_ANY, NOT_ALL)AND_ANY二级逻辑

条件与递归

JSON 字段类型默认值编辑器对应
conditionsCondition[](每个包含 variableIdoperatorvalue[]条件
conditionLogic"all" | "any""all"条件逻辑
preventRecursionbooleanfalse阻止递归
excludeRecursionbooleanfalse排除递归

组织管理

JSON 字段类型编辑器对应
tagsstring[]标签
folderIdstring文件夹
presetIdstring关联的预设 ID(内部使用)

实用例子

例子 1:一个完整的角色(三个条目配合)

角色描述条目:

json
{
  "id": "alice-desc",
  "name": "艾莉丝",
  "content": "{{char}}是翡翠森林的精灵法师,年龄约300岁(精灵中算年轻人)。银色齐腰长发,翠绿色眼睛,左耳戴着一枚橡果形状的耳环。身高165cm,纤细但不柔弱。总是穿着一件染着苔藓色的长袍,袍角绣着看不懂的精灵文字。",
  "role": "character",
  "section": "system-presets",
  "position": 0,
  "alwaysSend": true,
  "keywords": [],
  "conditions": [],
  "conditionLogic": "all",
  "enabled": true
}

性格条目:

json
{
  "id": "alice-personality",
  "name": "艾莉丝的性格",
  "content": "{{char}}的性格特征:\n- 说话温柔但藏着毒舌,喜欢用植物和自然做比喻来损人\n- 对人类充满好奇但嘴上不承认\n- 极其护短,一旦认定朋友会不顾一切保护\n- 怕虫子,尤其是蜈蚣——这是她最大的秘密\n- 喜欢在对话中夹带精灵语单词(用斜体标注)",
  "role": "personality",
  "section": "system-presets",
  "position": 1,
  "alwaysSend": true,
  "keywords": [],
  "conditions": [],
  "conditionLogic": "all",
  "enabled": true
}

开场白条目:

json
{
  "id": "alice-greeting",
  "name": "艾莉丝的问候",
  "content": "*一片银色的光芒在林间闪烁。当你走近时,一位精灵从古橡树后走出,翠绿的眼睛上下打量着你。*\n\n又一个迷路的人类。*她轻叹一声,银发随微风飘动* 你是从哪条路摸过来的?不——别告诉我,让我猜。\n\n*她凑近你,嗅了嗅* ……北边的沼泽路。你身上有腐草的味道。*Ithiliel*,你们人类真的对鼻子没有任何尊重。\n\n好吧,既然来了就别站着。我叫艾莉丝。跟我走,在这片森林里乱逛可比和我说话危险多了。",
  "role": "greeting",
  "section": "system-presets",
  "position": 0,
  "alwaysSend": false,
  "keywords": [],
  "conditions": [],
  "conditionLogic": "all",
  "enabled": true
}

三个条目分工明确:角色描述和性格永远发送(alwaysSend: true),开场白只在会话开始时使用一次。


例子 2:关键词触发的场景条目

这个条目只有在玩家提到森林相关的词时才会被注入:

json
{
  "id": "dark-forest-lore",
  "name": "暗影森林的秘密",
  "content": "[暗影森林]\n森林深处有一片被月光永远照不到的区域,精灵们称之为\"沉默之地\"。传说那里住着一只被封印的古龙,它的呼吸让周围的植物全部变成了黑色。任何人在沉默之地停留超过一个时辰,就会开始听到龙的低语——大部分听到的人都疯了。艾莉丝知道这个秘密,但她从不主动提起。",
  "role": "lore",
  "section": "chat-history",
  "depth": 4,
  "position": 10,
  "alwaysSend": false,
  "keywords": ["森林", "树林", "暗影", "沉默之地", "古龙"],
  "matchWholeWords": false,
  "useFuzzyMatch": false,
  "secondaryKeywords": [],
  "conditions": [],
  "conditionLogic": "all",
  "enabled": true
}

注意这里的设计选择:

  • sectionchat-historydepth4 —— 内容会插在聊天记录的倒数第 4 条消息处,而不是放在系统提示词的最前面。这让 AI 觉得"森林的信息是在对话进行中自然浮现的",而不是一开始就知道的。
  • 多个关键词用 OR 逻辑——玩家提到任何一个就触发。
  • alwaysSendfalse——不提到森林就不浪费 token。

例子 3:带条件的条目(变量驱动)

这个条目只在角色 HP 低于 20 时生效,用来让 AI 描写濒死状态:

json
{
  "id": "near-death-state",
  "name": "濒死状态描写指令",
  "content": "[当前状态:濒死]\n{{char}}此刻身受重伤,生命垂危。描写时必须体现:\n- 动作迟缓,每一步都很吃力\n- 说话断断续续,偶尔咳血\n- 视线模糊,可能会认错人\n- 但意志力惊人,拒绝倒下\n绝对不要写出{{char}}轻松战斗或正常行动的描述。",
  "role": "custom",
  "section": "post-history",
  "position": 5,
  "alwaysSend": true,
  "keywords": [],
  "conditions": [
    {
      "variableId": "hp",
      "operator": "lt",
      "value": 20
    }
  ],
  "conditionLogic": "all",
  "enabled": true
}

这里的巧思:

  • sectionpost-history——放在所有聊天消息之后,作为 AI 生成回复前的"最后指令"。这个位置的内容 AI 印象最深。
  • alwaysSendtrue 但有 conditions——意思是"每回合都检查这个条件,满足了就发送"。不需要关键词触发,纯靠变量状态驱动。
  • 条件:hp < 20。当游戏中 HP 变量降到 20 以下时,这段描写指令就会自动注入。HP 恢复到 20 以上后,它又会自动消失。

这比关键词触发更可靠——你不需要指望玩家提到"受伤",系统会根据实际的游戏状态自动判断。