记忆图
记忆图(Memory Graph)解决长跑 RP 里最常见的一个痛点:角色失忆。
LLM 的上下文窗口是有限的。聊到几百轮以后,早期的重要信息——人物关系、关键事件、世界规则——会被截断丢掉。角色就「忘了」之前发生的事。记忆图把对话里的关键信息自动抽成结构化的知识节点,需要时再召回注入回 prompt——让角色能像你一样,记住 500 轮前发生的事情。
它不是简单的关键词搜索或纯向量检索。记忆图用图结构和多层算法,让召回既语义相关又覆盖全面——不会出现「只把最相似的五条拉出来,其他都丢了」的情况。
它怎么工作
记忆图后台跑三件事:自动提取、智能召回、分层压缩。
自动提取
每次 AI 回复后,记忆图分析对话内容,把值得记住的东西提取出来,产出结构化的知识节点。提取可以走两条通道:
内置提取 —— 当记忆面板里的 自动抽取 开关打开时,记忆图在每次 AI 回复后自己跑一次 LLM 调用,把 schema 里的结构化字段填出来。这是默认方式,不依赖任何其他扩展。
编排器驱动的提取 —— 当编排器扩展已安装,且导演模式使用默认配置时,主 agent 在每次起草回复后会调度一个 memory_curator 子 agent。memory_curator 跑多轮"观察—执行"循环,先用记忆图的只读工具确认现状,再写入。对像角色这类稳定事实节点,质量通常更高 —— agent 会先查是否已有同名角色,而不是直接新建出重复节点。
两条通道可以同时开,它们彼此并不协调,等于用额外的 LLM 成本换取一层兜底。多数用户只会留一条。
只走编排器驱动的提取:
- 打开记忆面板,把 自动抽取 关掉。
- 在编排器配置编辑器里确认
memory_curator已启用,并且由主 agent 调度(新装默认就是这样)。
节点分两层。默认 schema 自带下面这三种类型,但 schema 是完全可定制的。你可以新增节点类型(奇幻题材加 magic_system,政治题材加 faction,生存题材加 inventory_item,看你的卡需要什么),也可以移除任何默认类型。下面字段也是默认值,每种类型的字段可以在 Schema 编辑器里改(下面会讲到)。
语义层节点(持久化结构化知识,合并和更新):
| 类型 | 说明 | 例子 |
|---|---|---|
character_sheet | 角色的姓名、身份、性格、目标、随身物品 | 「Eileen 是治愈师,认下了对主角的一份恩情」 |
location_state | 地点的名称、控制者、危险度、资源 | 「黑暗森林由精灵控制,危险度高」 |
事件层节点(情节记录,每次提取新建,从不合并):
| 类型 | 说明 | 例子 |
|---|---|---|
event | 发生过的重要事件 | 「主角在森林中遭遇伏击」 |
事件节点不一样
事件节点和其他类型有本质区别:
- 每次提取都新建节点。 标题自动递增。事件是时间轴上独立的点,不像角色状态那样合并到现有节点
- 最高层时间线总是注入。 事件节点是核心剧情上下文——最高层级的总结永远在 prompt 里,确保 AI 始终把握剧情走向
- 被压缩的低层事件隐藏。 事件累积太多时,旧事件向上压缩成更高层的总结。低层事件依然在图里,需要时召回机制能再发现它们,但默认不持久注入
简单说:AI 始终能看到「大事」(最高层总结),具体细节只在对话需要时召回补充。
可以通过 提取间隔 控制提取频率——比如设为 2 表示每 2 次 AI 回复才触发一次提取,LLM 调用成本减半。
智能召回
你发新消息触发 AI 生成时,记忆图根据当前对话上下文,从累积的记忆中召回最相关的节点,注入 prompt 供 AI 参考。
| 召回方式 | 说明 |
|---|---|
| LLM 召回 | 让 LLM 直接从记忆库里挑相关节点,支持多轮深度探索 |
| Hybrid 召回 | 结合向量检索、图扩散、词法匹配等多维信号综合打分 |
| Hybrid + Reranking | 在 Hybrid 基础上用重排模型进一步优化 |
| Hybrid + LLM | 在 Hybrid 候选基础上让 LLM 二次过滤 |
选哪个?
LLM 召回是默认的,因为最容易配 —— 你的主对话已经有 LLM API,这就够用了。
Hybrid 召回更快、更贴近生产级检索系统的玩法(向量检索 + 图扩散),但需要先在 Vector Storage 扩展里配好嵌入(embedding)模型。想要更好的效果,可以叠一个重排模型(Hybrid+Rerank),或者再叠一道 LLM 过滤(Hybrid+LLM)。
经验法则:刚开始用就 LLM 召回,等碰到成本或延迟瓶颈、或者想让召回结果在换模型后保持稳定时,再切到 Hybrid。
分层压缩
随着对话推进,事件记忆持续累积。记忆图自动对老事件做向上压缩——多个相关事件合并为更高层的总结节点,既保留核心信息又控制总记忆体积。
压缩是递归的。某层的总结节点也超阈值时,继续向上压缩,直到节点数降到阈值以下。例如多个战斗事件先压成「森林战役」,多场战役再压成「北征之战」。压缩后的总结节点仍可展开看原始子事件。
和提取类似,压缩也有两条通道:
内置压缩 —— 当记忆面板里的 自动压缩 开关打开时,叶子层事件累积到阈值后,记忆图跑一次性的 LLM 总结调用。
编排器驱动的压缩 —— memory_curator 在提取之后会评估 memory_compaction_candidates,然后用 KEEP/FOLD/DROP 风格的总结调 memory_compact_nodes。多轮 agent 可以一个 rollup 一个 rollup 反复迭代,而内置路径是一次性的。
它实际长什么样
读到这儿大多数读者都想知道一个具体问题:节点到底长什么样?来个真实例子。
假设你和 Eileen(一个治愈师 NPC)有这样三轮对话:
You: 我把找到的伤药递给 Eileen。
Eileen: ...谢谢。但你确定要给我?这种东西在外面很值钱。
You: 你伤得比我重。再说,我们是朋友吧。
Eileen: ...嗯。是朋友。这个恩情我会记着的。
这一轮后,记忆图在后台跑一次提取,产生这样的结构化节点:
{
"id": "n_eileen",
"type": "character_sheet",
"level": "semantic",
"title": "Eileen",
"fields": {
"aliases": "",
"traits": "话不多,字斟句酌,即使道谢也很克制",
"identity": "在北境遇到的旅行治愈师",
"goal": "还这份恩情;伤好到能自己走路",
"inventory": "伤药(刚收下)、轻便行囊",
"language_sample": "...谢谢。但你确定要给我?",
"addressing_user": "称呼用名字,中间常有停顿"
},
"floor": 12
}{
"id": "evt_20260505_001",
"type": "event",
"level": "semantic",
"title": "Summary 1",
"fields": {
"summary": "时间:Day 12, late afternoon; 用户把找到的伤药递给受伤的 Eileen,Eileen 接受并明确认下了朋友关系和这份恩情。"
},
"floor": 12
}这就是默认 schema 的字段
上面例子里的字段(character_sheet 用的 aliases / traits / identity / goal / inventory / language_sample / addressing_user,event 用的 summary)就是默认表的真实列。Schema 编辑器里可以改名、删除,或者干脆加新类型。
记忆图的面板里你能看到所有节点,可以是图,也可以是表格:


点任意节点看完整字段:

50 轮后,你说「对了 Eileen,你之前说欠我一个人情......」。记忆图召回机制把这两个节点(以及其他相关的)挑出来,在主模型生成回复之前注入 prompt 的 SYSTEM 部分:

这就是记忆图在做的事——它不让 AI 忘掉那种「50 轮前的小事到 50 轮后突然变成关键」。
5 分钟跑起来
Step 1 — 启用
打开 扩展 抽屉 → 记忆 → 把 启用 开关打开。

Step 2 — 给提取和召回选模型
记忆图的提取和召回都要 LLM 调用,但不必和主对话用同一个模型。在同一面板设:
| 设置 | 说明 |
|---|---|
| 召回 API 预设 | 召回的 API 连接 |
| 召回提示词预设 | 召回的 Chat Completion 预设 |
| 生成图 API 预设 | 提取的 API 连接 |
| 生成图提示词预设 | 提取的 Chat Completion 预设 |
常见配法:主对话走 Claude Opus,记忆图走 Haiku 或 Gemini Flash。提取做的是结构化字段填充,不是写文,小模型能处理,而且确实省钱。
Step 3 — 正常聊天
记忆图自动运行。聊几轮,内容里包含一些值得记住的角色 / 事件 / 地点。
Step 4 — 看效果
3-5 轮后打开 Memory 面板:
- Graph 视图——节点关系图
- Nodes 表格——按类型展示节点结构化字段
- Recall 视图——最近一次注入到 prompt 里的内容
如果什么都没看到,在聊天里多带几个角色或事件——提取需要具体的东西可抓。
我想要……
常见问题,从「普遍」到「小众」:
我想让我的奇幻卡记住魔法体系 / 派系
记忆图的节点类型可以自定义。在 Memory 面板点 打开 Schema 编辑器 加新类型:

例如加一个 magic_system 类型(字段:name / source / restrictions),或一个 faction 类型(字段:name / leader / goals)。自定义类型保存在角色卡里,导出时随卡走——你的奇幻世界词汇随卡传递。
每种类型还带两个提取控制字段:
- 提取指令 —— 一段自由文本,仅当本类型本轮启用时才会附加到提取系统提示词。类型专属规则(如"每批次最多一个 event"、"角色一定填 aliases")写在这里,而不是塞进 base prompt。留空 = 无类型专属附加段。
- 每 N 层提取一次 —— 节奏控制。
1(默认)表示每次提取都包含该类型。设为2/3/5等,仅当currentSeq % N == 0时启用,适合location_state这种慢变化表,降低提取频率、省 LLM 调用。某类型本轮未启用时,其 create/edit/delete 工具不会暴露给模型,指令也不会附加 —— 模型这轮根本无法产出该表。
我想让某些记忆 始终 在 prompt 里(不等召回)
那是 持久注入。把某些节点类型设为持久注入——它们无论召回触发与否都出现在 prompt 里。常见用法:如果你加一个 rule_constraint 或 world_law 类型来表达不可违反的世界规则,把它标为持久——主模型就永远不会忘掉这些规则。
持久注入和召回是互斥的(节点级)
持久注入的节点会从召回池里完全排除——它已经每回合都在 prompt 里了,运行时直接 bypass 掉它的召回。
我编辑 / 删除消息——记忆会怎么变?
记忆图有完整的变更回滚机制。你编辑、删除消息或 swipe 时,记忆自动回滚到受影响消息之前的状态,保持记忆和聊天历史一致。
我想换电脑用 / 分享给别人
JSON 导入导出。
| 模式 | 作用 |
|---|---|
| Restore 还原 | 保留导出时的楼层号——同一聊天恢复数据用 |
| 绑定到最新楼层 | 所有导入节点绑到当前最新 AI 回复楼层。 实用技巧:开一个全新的聊天,把过去某段长跑的记忆导进来,从 0 楼重新开始。等于「开新档,但之前长跑里积累的世界观、角色、故事全在你脑子里」——你可以续写、换主线、换设定再玩一遍。 |
| 绑定到指定楼层 | 你手动输入目标楼层 |
记忆怎么进 prompt
两条通道,节点级互斥。
持久注入——某些节点类型总在 prompt 里。适合基线信息:世界规则、人设核心设定、那种永远不该忘的东西。在 Schema 编辑器里按类型配置(alwaysInject 标志)。持久节点会被从召回池里排除——它每回合都在,不需要再被「召回」一遍。
召回注入——其他节点类型由召回机制动态注入,只有和当前对话相关的记忆才进 prompt,不浪费上下文空间。
底层实现:世界书投射
这两条通道实际上都是把节点投射成世界书条目的方式工作的。持久注入写持久世界书条目;召回注入写临时条目(生成完自动清理)。这意味着记忆条目会遵守世界书的关键词扫描、深度排序等机制。这不是配置项,而是工作方式。
召回注入有自己的位置设置:
| 设置 | 默认 | 说明 |
|---|---|---|
| 召回注入位置 | atDepth | 注入位置 |
| 召回注入深度 | 9999 | 注入深度 |
| 召回注入角色 | SYSTEM | SYSTEM / USER / ASSISTANT |
结果复用
同一楼层 swipe 或重生成时,记忆图会复用上次召回结果而不是重跑。省 LLM 成本,保证同一回合记忆上下文一致。
配置参考
完整配置列表
基础配置
| 设置 | 默认 | 说明 |
|---|---|---|
| 启用记忆图 | false | 总开关 |
| 提取间隔 | 1 | 每 N 次 AI 回复触发一次提取 |
| 最大处理轮数 | 900 | 处理轮数硬上限 |
向量与扩散
| 设置 | 默认 | 说明 |
|---|---|---|
| 嵌入档案 | (空) | Connection Manager 里的 embed-profile,记录嵌入 Provider/模型/Endpoint/Key。可在记忆图设置或向量存储里创建,多插件共享。 |
| 向量 Top-K | 20 | 向量检索 Top-K |
| 图扩散步数 | 2 | 扩散步数 |
| 图扩散衰减 | 0.6 | 衰减系数 |
| 图扩散 Top-K | 100 | 扩散后 Top-K |
| 图扩散传送概率 | 0.0 | 传送概率 |
重排
| 设置 | 默认 | 说明 |
|---|---|---|
| 启用重排 | false | 是否重排 |
| 重排档案 | (空) | Connection Manager 里的 rerank-profile,定义重排 Provider/模型/Endpoint/Key。与向量存储共享。 |
其他
| 设置 | 默认 | 说明 |
|---|---|---|
| RPM 限制 | 0 | 每分钟请求数(0 = 不限) |
| LLM 可见最近消息数 | 5 | 召回 LLM 能看到的最近消息数 |
| 与预设一起包含世界书 | true | 用预设时是否包含世界书 |
| 覆写世界书名称 | (空) | 覆写投射的世界书名 |
| 世界书条目排序基数 | 9800 | 投射条目的基础排序值 |
| 工具调用最大重试 | 2 | 工具调用失败重试次数 |
| 排除最近 N 轮的节点 | 0 | 召回时排除最近 N 轮的节点(0 = 不排除) |
技术深入
给好奇的读者和贡献者
多阶段混合召回管道
Hybrid 模式下,记忆图跑一个 8 阶段管道:
- 向量预筛——从向量库取最相似的 Top-K 节点
- 实体锚定——在查询里匹配已知实体名和别名
- 建种子——合并向量命中和实体锚作为扩散起点
- 建邻接表——构造图的双层邻接表
- PEDSA 图扩散——从种子节点出发,通过图结构传播能量,发现间接相关记忆
- 混合打分——融合向量分、扩散能量、词法匹配、锚分、新近度加成等多维信号
- 认知层(NMF / FISTA / DPP)——三种算法保证召回既全面又多样
- 可选重排——外部重排器最终排序
认知层算法
- NMF 主题再平衡 —— 用非负矩阵分解识别欠覆盖的主题方向,提升代表性节点的得分
- FISTA 残差发现 —— 用快速迭代收缩阈值算法发现查询中候选集未覆盖的语义方向,补充检索
- DPP 多样性采样 —— 用行列式点过程从候选中选出高质量且互相多样的子集,避免召回过于集中
PEDSA 图扩散
PEDSA(Personalized Efficient Diffusion with Sparse Approximation)让记忆图能发现那些和查询没有直接语义关联,但通过图结构间接相关的重要记忆。能量从种子节点沿边传播多轮,支持传送概率(类似 PageRank)和稀疏近似控制。
向量索引
记忆图用增量更新策略管理向量嵌入——通过哈希比对检测节点内容变化,只有内容真的变了才重新生成嵌入向量。Hybrid 召回里使用记忆图设置中选定的嵌入档案作为单一事实源,Provider/模型/Endpoint/Secret 全部从档案读取。向量存储插件从同一份 Connection-Manager 档案库读取,两个插件可以共用一份档案,也可以各自挑不同的档案,不再依赖对方的私有 extension_settings。
插入向量时,记忆图把 nodeId 放在 metadata 字段里。后端原样存 metadata。其他插件也可以用 metadata 字段存自定义数据,查询结果会一并返回。这种设计让 hash → nodeId 映射可以绕开前端索引缓存——即使缓存丢了,也能从查询结果直接匹配节点。
如需手动控制,记忆图设置面板提供重算向量索引按钮。点击后弹出对话框,提供两种模式:增量补全仅对向量缺失或失效(如节点编辑后)的节点重新生成 embedding;全部重算清空集合并对所有可索引节点重新生成 embedding(更换嵌入模型或档案后用此项)。如果嵌入配置已变更,增量补全会自动升级为全部重算,因为旧向量与新空间不兼容。失败的节点记录到控制台,不阻断整体流程。
自动 schema 迁移
加载聊天时,记忆图运行迁移管道,把旧的持久化形态(v5 raw,v8 opLog)转换为当前的 v2 楼层状态布局(graph payload + __floor_log 提交日志 + __meta 状态)。管道幂等,只在输入形态不是 v2 时运行,任何步骤失败时绝不修改 chat-state。
更多实现细节请看源码。
相关页面
- Function Call Runtime — 记忆图的 LLM 交互依赖此框架
- 世界书基础 — 世界书投射涉及的基础概念