diff --git a/README.md b/README.md index f98e0a0..e64be7c 100644 --- a/README.md +++ b/README.md @@ -1,671 +1,1007 @@ -# 🧠 ST-BME — SillyTavern 仿生记忆生态 +# ST-BME — SillyTavern 仿生记忆生态 -> **让 AI 真正记住你们的故事。** -> -> ST-BME 把对话中散落的角色、事件、地点、关系自动提取为记忆图谱,在下一轮生成前精准召回,让长期 RP 的角色不再"失忆"。 +> 让 AI 真正记住你们的故事。 + +ST-BME(Bionic Memory Ecology)是一个 **SillyTavern 第三方前端扩展**。它会把长期聊天中出现的角色、事件、地点、规则、主线、反思和总结抽取成一张可视化记忆图谱,并在下一轮生成前自动召回最相关的记忆注入 prompt。 --- -## ✨ 核心能力 +## 目录 -- 🧩 **自动提取** — AI 回复后自动从上下文中抽取角色状态、事件、地点、规则、主线等结构化记忆 -- 🔍 **多层混合召回** — 向量语义搜索 + 图扩散 + 词法增强 + 认知边界过滤 + 可选 LLM 精排,精准注入 -- 🧠 **认知架构** — 主客观分层记忆、角色视角记忆、空间邻接感知、故事时间线,模拟真实认知 -- 🌐 **图谱可视化** — 内置力导向图谱面板,直观查看记忆节点之间的关系 -- 🎨 **4 套配色主题** — Crimson Synth / Neon Cyan / Amber Console / Violet Haze -- 📱 **手机端适配** — 底部 Tab Bar + 精简布局,手机也能用 -- 🔄 **历史安全** — 删楼、编辑、切 swipe 时自动回滚恢复,不留脏记忆 -- 🧹 **污染标签清理** — 默认清理 thinking/choice/UpdateVariable 等常见污染标签,可自定义正则 -- 📦 **不改酒馆本体** — 纯第三方扩展,即装即用 +- [核心能力](#核心能力) +- [工作原理](#工作原理) +- [安装](#安装) +- [快速上手](#快速上手) +- [面板导览](#面板导览) +- [主要配置](#主要配置) +- [记忆模型](#记忆模型) +- [长聊天与历史安全](#长聊天与历史安全) +- [常用操作速查](#常用操作速查) +- [数据存储与同步](#数据存储与同步) +- [排障指南](#排障指南) +- [开发者参考](#开发者参考) +- [已知限制](#已知限制) +- [License](#license) --- -## 🧭 工作原理 +## 核心能力 -整个插件可以拆成三件事:**写入**(把对话变成记忆)、**读取**(把记忆送回给 AI)、**安全**(出了问题能恢复)。 +- **自动记忆提取** + - AI 回复后自动读取对话上下文,提取结构化节点和关系。 + - 支持角色、事件、地点、规则、主线、反思、主观记忆等类型。 + - 默认排除 `think`、`analysis`、`reasoning` 等推理标签,避免污染记忆。 + +- **多层混合召回** + - 生成前自动召回相关记忆。 + - 检索链路包含向量预筛、图扩散、词法增强、上下文混合查询、多意图拆分、DPP 多样性采样和可选 LLM 精排。 + - 支持消息级持久召回卡片,可查看、编辑、删除、重新召回。 + +- **认知架构** + - 支持角色 POV 记忆、用户 POV 记忆、客观世界记忆。 + - 支持空间区域、邻接区域、全局区域权重。 + - 支持故事时间线、时间桶、时间跨度和软引导。 + +- **总结与维护** + - 支持小总结、总结折叠、反思、整合、自动压缩、主动遗忘。 + - 维护操作带日志和回滚能力,可撤销最近维护。 + +- **图谱可视化** + - 内置 Canvas 力导向图谱。 + - 支持实时图谱、认知视图、总结视图、移动端图谱视图。 + - 支持主题切换、节点详情、子图召回卡片。 + +- **任务预设系统** + - 提取、召回、压缩、小总结、总结折叠、反思、整合、规划都走统一 task profile。 + - 支持任务块排序、生成参数、全局正则、局部规则、世界书扫描和 EJS 渲染。 + +- **ENA Planner 集成** + - ENA 规划器已整合到 ST-BME 配置页和 `planner` 任务预设。 + - 规划链路可使用角色卡、世界书、最近聊天、BME 记忆、历史 plot 和当前玩家输入。 + +- **持久化与同步** + - 本地优先,主路径使用 IndexedDB。 + - 支持自动云端镜像和手动备份/恢复。 + - 支持导入、导出、重建、修复、压实和持久化探测。 + +- **历史安全** + - 检测删楼、编辑、切 swipe 等历史变动。 + - 自动回滚受影响批次并从变动点恢复。 + - 对“聊天区只渲染最近 N 条”的截断视图有保护,避免误把渲染切片当成历史删除而清空运行时图谱。 + +- **长聊天优化** + - 可隐藏旧楼层来控制上下文 token。 + - 可限制聊天区最多渲染最近 N 条,降低超长聊天前端卡顿。 + - 图布局、持久化 delta、快照 hydrate 支持 Native/Worker/WASM 灰度加速和 JS fail-open 回退。 + +--- + +## 工作原理 + +ST-BME 可以理解为三条链路:**写入**、**读取**、**安全**。 ```mermaid flowchart LR - subgraph 写入["✏️ 写入:对话 → 记忆"] - A["AI 回复了一条消息"] --> B["结构化消息预处理"] - B --> C["LLM 识别出角色/事件/地点等"] - C --> D["近邻对照 + 认知归属判定"] - D --> E["写入图谱 + 同步向量 + 故事时间线"] + subgraph Write["写入:对话 → 记忆"] + A["AI 回复"] --> B["结构化消息预处理"] + B --> C["LLM 提取节点/边"] + C --> D["近邻对照 + 认知归属"] + D --> E["写入图谱 + 向量同步 + 时间线"] + E --> F["整合 / 压缩 / 总结 / 反思"] end - subgraph 读取["🔍 读取:记忆 → 注入"] - F["用户准备发送下一条"] --> G["多意图拆分 + 上下文混合查询"] - G --> H["向量预筛 → 图扩散 → 词法增强"] - H --> I["认知边界过滤 + 混合评分"] - I --> J["[可选 LLM 精排] → 分桶注入"] + subgraph Read["读取:记忆 → 注入"] + G["用户准备生成"] --> H["多意图 + 上下文混合查询"] + H --> I["向量预筛 + 图扩散 + 词法增强"] + I --> J["认知边界过滤 + 混合评分"] + J --> K["可选 LLM 精排 + 分桶注入"] end - subgraph 安全["🛡️ 安全:历史变动 → 恢复"] - K["用户删楼/编辑/切 swipe"] --> L["检测到哪些楼层变了"] - L --> M["回滚受影响的记忆和向量"] - M --> N["从变动点重新提取"] + subgraph Safe["安全:历史变化 → 恢复"] + L["删楼 / 编辑 / Swipe"] --> M["消息 hash 检测"] + M --> N["定位受影响楼层"] + N --> O["回滚批次与向量"] + O --> P["从变动点重新提取"] end - E -.-> F - N -.-> E + F -.-> G + P -.-> E ``` -### 写入阶段(对话 → 记忆) +### 写入链路 -每次 AI 回复后,插件会把最近几轮对话打包发给 LLM(可以是你聊天用的同一个模型,也可以单独配一个),让它识别出"这段对话里出现了哪些角色、发生了什么事、在哪里、有什么新规则"等等。 +1. **结构化消息** + - 对话被规范为带楼层、角色、说话人、原文、来源类型的结构化消息。 -**提取管线预处理**: +2. **Assistant 边界过滤** + - 默认排除推理标签内容。 + - 可自定义提取标签、排除标签和正则规则。 -1. **结构化消息** — 对话被规范为带 `seq/role/speaker/name/rawContent/sourceType` 的结构化消息 -2. **Assistant 边界过滤** — 默认排除 `think/analysis/reasoning` 等推理标签内容,可自定义提取/排除规则 -3. **分层上下文** — 对话切片、图谱状态、总结快照、故事时间线、Schema 定义作为独立上下文字段传给 LLM -4. **世界书集成** — 提取时可选择是否解析世界书内容,复用酒馆原生世界书扫描逻辑 +3. **分层上下文** + - 提取 prompt 可以包含近期对话、图谱统计、活跃总结、故事时间、世界书和 Schema。 -识别出来的结果不是直接塞进去——插件会先跟已有记忆做对比(通过向量搜索找相似的),如果已经有了就更新,如果是真正的新内容才创建。同时会判定记忆的**认知归属**(角色视角/用户视角/客观)和**空间区域**。 +4. **LLM 提取** + - 输出结构化图操作。 + - 自动解析新增、更新、合并、关系建立和主客观归属。 -写入之后,还可能触发一些后续处理: +5. **后处理** + - 向量同步。 + - 相似记忆整合。 + - 自动压缩。 + - 小总结与总结折叠。 + - 反思与主动遗忘。 -- **整合** — 相似记忆合并(Mem0 精确对照 + A-MEM 进化) -- **压缩** — 太多类似的事件记忆会被层级合并 -- **层级总结** — 基于近期原文窗口生成小总结,并在前沿过厚时继续做总结折叠 -- **反思** — 长期模式总结,生成叙事指导原则 -- **遗忘** — 很久没被用到的记忆降低优先级 +### 读取链路 -### 读取阶段(记忆 → 注入) +1. **召回输入解析** + - 从当前用户输入、发送意图、生成生命周期或持久召回记录中解析召回目标。 -当你准备发送下一条消息时,插件会抢在 AI 生成之前做一轮"召回": +2. **候选召回** + - 向量预筛找语义相关节点。 + - 图扩散沿关系网络发现间接关联。 + - 词法增强补足实体名、地名、关键词匹配。 -1. **多意图拆分** — 自动识别用户消息中的多个意图,分别检索 -2. **上下文混合查询** — 融合当前用户输入 + 上一轮 AI 回复 + 前一条用户消息的加权查询 -3. **向量预筛** — 用 Embedding 找到语义最相关的候选 -4. **图扩散** — 沿关系网络向外扩散,发现间接关联 -5. **词法增强** — 关键词精确匹配加权,弥补纯语义搜索的盲区 -6. **认知边界过滤** — 按角色视角/用户视角/客观区域过滤和加权 -7. **混合评分** — 向量相似度 × 图扩散能量 × 节点重要性 × 时间新旧 × 认知权重 -8. **多样性采样** — DPP 采样避免召回内容过于同质 -9. **[可选] LLM 精排** — 让 LLM 从候选池中挑选最相关的记忆 -10. **格式化注入** — 选出最终入围的记忆,分类整理后注入到 prompt 里 +3. **排序与筛选** + - 融合向量分、图分、重要性、时间新旧、访问强化、认知区域权重。 + - 可选多意图拆分、上下文混合查询、DPP 多样性采样、LLM 精排。 -注入的内容分成两层: +4. **注入** + - 结果按当前状态、事件、反思锚点、规则约束等桶整理。 + - 注入到 SillyTavern prompt。 + - 同时可写入对应用户楼层的 `message.extra.bme_recall` 作为持久召回卡片。 -- **Core(常驻层)** — 规则、主线,以及在没有活跃总结前沿时兜底的旧式全局概要 -- **Recalled(动态层)** — 根据当前对话语境召回的 +### 安全链路 -每层内进一步按用途分桶:当前状态 / 情景事件 / 反思锚点 / 规则约束。 - -**召回 prompt 分段**:recall 的 LLM prompt 将 recentMessages 拆分为"上下文回顾"和"当前召回目标"两段 system message,帮助模型更好地区分参考信息和当前任务。 - -### 安全机制(历史变动 → 恢复) - -这是很多记忆插件忽略的问题:如果用户删了某条消息、编辑了内容、或者切了 swipe,已经基于那条消息提取的记忆就变成"脏"的了。 - -ST-BME 的处理方式是: - -1. 给每条已处理的消息计算 hash(指纹) -2. 发现 hash 变了 → 找到最早受影响的位置 -3. 把那之后产生的记忆和向量全部回滚 -4. 从变动点重新走一遍提取流程 - -如果恢复日志损坏了,会退化为全量重建——慢一点但保证正确。 - -**持久化稳态保障**: - -- IndexedDB 热路径走增量提交(`buildPersistDelta`),不再整图替换 -- `accepted/recoverable` 语义分层:只有 IndexedDB 和 chat-state 计入 accepted;shadow 与 metadata-full 仅为 recoverable 恢复锚点 -- Restore Lock 门禁:手动重建/导入/云恢复等操作期间,自动提取/召回/持久化重试自动暂停 +ST-BME 会为已处理消息记录 hash。发现历史被修改时,会找到最早受影响楼层,优先使用维护日志回滚并重放;无法安全回滚时才退化为全量重建。 --- -## 🚀 安装 +## 安装 ### 方法一:通过 SillyTavern 扩展安装 -1. 打开 SillyTavern → 扩展 → 安装扩展 -1. 输入仓库地址: +1. 打开 SillyTavern。 +2. 进入扩展管理。 +3. 选择安装第三方扩展。 +4. 输入仓库地址: ```text https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology ``` -注意:请粘贴仓库根地址,不要使用像 `/graphs/code-frequency` 这样的 GitHub 子页面地址。 +5. 安装完成后刷新页面。 -1. 刷新页面 +> 请粘贴仓库根地址,不要粘贴 GitHub 的子页面地址。 ### 方法二:手动安装 +进入 SillyTavern 的第三方扩展目录: + ```bash cd SillyTavern/data/default-user/extensions/third-party git clone https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology.git st-bme ``` -重启 SillyTavern 即可。 +然后重启或刷新 SillyTavern。 --- -## ⚡ 快速上手 +## 快速上手 -1. **打开面板** — 左上角 ≡ 菜单 →「🧠 记忆图谱」 -2. **启用插件** — 进入面板的「配置 → 功能开关」,打开 ST-BME 自动记忆 -3. **配置 Embedding** — 进入「配置 → API 配置」,选择向量模式并填好模型 -4. **开始聊天** — 正常跟角色对话,插件会自动在后台提取和召回 +1. **打开面板** + - 左上角菜单中点击“记忆图谱”。 + - 或使用 ST-BME 注入的面板入口。 -> **最少配置:** 只勾选"启用"就能跑起来。默认会复用你当前的聊天模型做提取。 +2. **启用插件** + - 进入“配置 → 功能开关”。 + - 确认 ST-BME 主开关已启用。 + +3. **配置模型** + - 记忆 LLM 留空时,会复用当前 SillyTavern 聊天模型。 + - 如果希望提取/总结/整合走独立模型,可在“API 配置”中填写 OpenAI-compatible 地址、Key 和模型名。 + +4. **配置 Embedding** + - 推荐使用“后端模式”,复用 SillyTavern 已配置的向量 provider。 + - 也可以使用直连模式,但需要自行处理浏览器 CORS。 + +5. **开始聊天** + - 正常对话即可。 + - AI 回复后自动提取,下一次生成前自动召回。 + +6. **查看结果** + - “总览”看运行状态。 + - “任务 → 记忆浏览”看节点。 + - 图谱区域看关系网络。 + - 用户消息下方可能出现召回卡片,可展开查看召回子图。 + +> 最小可用配置:启用插件,并保证当前聊天模型可用。Embedding 不可用时,召回质量会明显下降,建议尽早配置。 --- -## 📝 记忆类型 +## 面板导览 -插件会把对话拆解成以下几种记忆节点: +### 总览 -| 类型 | 说明 | 举例 | -| ------ | ------ | ------ | -| 🧑 角色 | 角色的当前状态、性格、外貌变化 | "小明因为淋雨感冒了" | -| ⚡ 事件 | 发生过的事 | "河边的告白" | -| 📍 地点 | 地点状态 | "废弃实验室,门被锁上了" | -| 📌 规则 | 世界观设定、约束 | "魔法会消耗生命力" | -| 🧵 主线 | 任务线/剧情线 | "寻找失踪的项链" | -| 📜 全局概要(旧) | 单条全局前情提要,现主要用于兼容 / 迁移兜底 | — | -| 💭 反思 | 长期规律总结 | "他们经常在夕阳下聊天" | -| 👁️ 主观记忆 | 角色视角下的记忆,含误解和情绪 | "她以为他离开了,其实他躲起来了" | +- **活跃节点、边连接、已归档、碎片率** +- **当前聊天 ID** +- **历史状态** +- **向量状态** +- **最近恢复** +- **最近提取** +- **最近持久化** +- **最近向量** +- **最近召回** +- **认知 / 空间状态** -这些节点之间还会建立关系(参与、发生在、推动、矛盾、更新、时序更新等),形成一张完整的记忆网络。 +### 任务 -### 认知架构 +任务页用于实时观察 ST-BME 的后台任务流。 -ST-BME 的记忆不是扁平的——它模拟了真实的认知分层: +- **管线总览** + - 提取、召回、持久化、向量等阶段状态。 -**主客观分层**: +- **任务流水** + - 最近任务的时间线和阶段结果。 -- **客观层** — 事件、地点、规则等事实性记忆,按空间区域组织 -- **主观层(POV)** — 角色视角记忆,包含信念、情绪、态度,甚至允许"误解"(`certainty: mistaken`) +- **记忆浏览** + - 浏览、筛选、查看节点详情。 -**空间感知**: +- **注入预览** + - 查看当前构造出的注入文本和 token 估算。 -- 记忆按空间区域归属(当前区域/邻接区域/全局)加权召回 -- 角色移动时,相关区域的记忆权重自动调整 +- **消息追踪** + - 追踪楼层、提取范围、召回来源和持久记录。 -**故事时间线**: +- **持久化** + - 查看 IndexedDB、同步、恢复、sidecar、native hydrate 等诊断信息。 -- 每条记忆带有故事时间标记(当前/近过去/远过去/闪回/未来) -- 时间线上下文可注入 prompt,帮助模型保持时间感知 -- 支持软引导(`storyTimeSoftDirecting`),不强制但提示模型注意时间流 +### 操作 -### 总结状态 +- **重新提取** + - `提取未处理`:只处理还没提取的助手楼层。 + - `重新提取范围`:按起止楼层重跑指定范围。 -当前主用的总结体系不是 `synopsis` 节点,而是 `summaryState` 中持续演化的「小总结 + 总结折叠」活跃前沿。 +- **手动压缩** + - 对冗余或相似记忆做压缩。 + +- **生成小总结** + - 基于近期原文窗口生成阶段性总结。 + +- **执行总结折叠** + - 将多条活跃总结折叠成更高层总结。 + +- **重建总结状态** + - 根据提取批次重建总结状态。 + +- **强制进化** + - 让新记忆主动影响旧记忆。 + +- **执行遗忘** + - 降低长期未使用节点的优先级或归档。 + +- **撤销最近维护** + - 回滚最近一次可撤销的维护动作。 + +- **重建向量 / 范围重建 / 直连重嵌** + - 重建节点向量,修复召回质量或切换向量模型后的不一致。 + +- **导出 / 导入 / 重建图谱** + - 图谱管理与危险操作。 + +- **持久化修复** + - 重试持久化、重新探测图谱、重建本地缓存、修复/压实主 sidecar。 + +### 配置 + +配置页包含以下工作区: + +- **API 配置** + - 记忆 LLM。 + - Embedding 后端模式/直连模式。 + +- **功能开关** + - 提取、召回、整合、总结、反思、压缩、遗忘、概率召回等主能力。 + - 云端存储模式。 + - 世界书过滤。 + - 隐藏旧楼层与聊天区渲染限制。 + +- **详细参数** + - 提取频率、上下文窗口、召回 Top-K、图扩散、认知权重、维护阈值等。 + +- **任务预设** + - 每个任务类型的 prompt blocks、生成参数、正则、世界书、EJS 模板。 + +- **ENA 规划器** + - ENA Planner 的 API、模型、规划配置和任务预设入口。 + +- **面板外观** + - 主题、通知样式、调试日志、Native 性能加速。 + +- **数据清理** + - 本地缓存、遗留数据、调试状态等清理入口。 + +### 图谱区域 + +桌面端会显示实时图谱区域。移动端提供子视图切换: + +- **实时图谱** +- **认知视图** +- **总结视图** --- -## 🔧 设置说明 +## 主要配置 ### 记忆 LLM -用来做提取、压缩、整合、小总结、总结折叠、反思等任务的模型。 +记忆 LLM 用于: -- **留空** → 复用当前 SillyTavern 的聊天模型(最简配置) -- **填写** → 你可以指定一个独立的 OpenAI-compatible 模型专门处理记忆 -- **自动检测** → 插件会自动检测是否配置了专用的记忆 LLM 提供商 +- 提取记忆。 +- 召回精排。 +- 整合。 +- 压缩。 +- 小总结。 +- 总结折叠。 +- 反思。 +- ENA Planner 规划。 -### Embedding(向量搜索) +配置方式: -向量搜索是"智能召回"的关键。支持两种模式: +- **留空** + - 复用当前 SillyTavern 聊天模型。 -#### 后端模式(推荐) +- **填写 OpenAI-compatible 配置** + - 使用独立模型处理记忆任务。 + - 适合把主聊天模型和后台维护模型分开。 -走 SillyTavern 后端的向量 API,最稳定: +安全建议: -- 支持 OpenAI / Cohere / Mistral / Ollama / LlamaCpp / vLLM 等 -- 在设置面板选择「后端向量源」,填好模型名即可 -- 不需要单独填 API Key,复用酒馆已有的 +- 不要把包含 API Key 的 `extension_settings` 或浏览器存储导出后公开。 +- 调试日志默认关闭,需要排障时再临时开启。 + +### Embedding + +Embedding 是智能召回的核心。 + +#### 后端模式 + +推荐优先使用后端模式: + +- 复用 SillyTavern 后端的 embedding provider。 +- 通常不需要浏览器直接持有 embedding API Key。 +- 可使用 SillyTavern 已支持的 OpenAI、Cohere、Mistral、Ollama、LlamaCpp、vLLM 等来源。 #### 直连模式 -如果你需要完全独立的 Embedding 服务(比如酒馆后端不支持的源): +直连模式由浏览器直接请求 embedding 服务: -- 填入 Embedding API 地址、Key、Model -- 插件直接请求你的 Embedding 服务 -- 注意浏览器跨域问题(CORS) +- 需要填写 API 地址、Key 和模型。 +- 可能遇到 CORS 限制。 +- 适合自建网关或独立 embedding 服务。 -> **切换向量模式/模型后,建议点一次"重建向量"。** +> 切换 embedding 模式或模型后,建议执行“重建向量”。 ### 提取设置 | 设置 | 默认 | 说明 | -| ------ | ------ | ------ | -| 每 N 条回复提取 | 1 | 每几条 AI 回复做一次提取 | -| 提取上下文轮数 | 2 | 提取时向前看几轮对话 | -| 提取模式 | pending | 手动提取面板默认模式(pending/rerun),跨会话记忆 | -| Assistant 排除标签 | think,analysis,reasoning | 默认排除的推理标签 | -| 提取消息上限 | 0(不限) | 限制传入 prompt 的最近消息数量 | -| 提取 Prompt 模式 | both | 对话传入方式:both/transcript/structured | -| 提取世界书模式 | active | 是否在提取时解析世界书 | -| 包含故事时间线 | 开 | 提取 prompt 中包含故事时间线上下文 | -| 包含总结快照 | 开 | 提取 prompt 中包含活跃总结快照 | +| --- | --- | --- | +| 每 N 条回复提取 | `1` | 每几条助手回复触发一次提取 | +| 提取上下文轮数 | `2` | 提取时向前看的对话轮数 | +| 自动延后最新助手 | `false` | 可让最新回复稳定后再提取 | +| Assistant 排除标签 | `think,analysis,reasoning` | 默认排除推理标签 | +| 提取消息上限 | `0` | `0` 表示不限 | +| 提取 Prompt 结构模式 | `both` | 同时提供 transcript 和 structured messages | +| 提取世界书模式 | `active` | 复用当前激活世界书上下文 | +| 包含故事时间 | `true` | 提取时提供故事时间线 | +| 包含总结快照 | `true` | 提取时提供活跃总结 | +| 手动提取模式 | `pending` | 面板中的提取模式默认值 | ### 召回设置 | 设置 | 默认 | 说明 | -| ------ | ------ | ------ | -| 向量预筛 Top-K | 20 | 向量预筛阶段最多保留多少个候选 | -| LLM 精排候选池 | 30 | 进入 LLM 精排阶段前的候选池大小 | -| LLM 最终选择上限 | 12 | LLM 精排后最多保留多少条记忆 | -| 图扩散 Top-K | 100 | 图扩散阶段最多保留多少个候选 | -| 注入深度 | 9999 | 当前走 IN_CHAT@Depth,数值越大越靠前插入 | -| 多意图拆分 | 开 | 自动识别用户消息中的多个意图 | -| 上下文混合查询 | 开 | 融合用户输入 + AI 回复 + 前一条用户消息 | -| 词法增强 | 开 | 关键词精确匹配加权 | -| 多样性采样 | 开 | DPP 采样避免召回内容过于同质 | -| 时序链接 | 开 | 相邻时间节点的关联增强 | -| 角色视角权重 | 1.25 | 当前角色视角记忆的召回加权 | -| 用户视角权重 | 1.05 | 用户视角记忆的召回加权 | -| 当前区域权重 | 1.15 | 当前空间区域记忆的召回加权 | -| 邻接区域权重 | 0.9 | 邻接空间区域记忆的召回加权 | -| 全局区域权重 | 0.75 | 全局空间区域记忆的召回加权 | +| --- | --- | --- | +| 启用召回 | `true` | 生成前自动检索记忆 | +| 向量预筛 | `true` | 先用 embedding 找候选 | +| 图扩散 | `true` | 沿图关系扩散相关节点 | +| LLM 精排 | `true` | 让 LLM 从候选中筛最终结果 | +| 召回 Top-K | `20` | 向量预筛数量 | +| 最终节点上限 | `12` | 注入前最多保留节点数 | +| 图扩散 Top-K | `100` | 图扩散候选数量 | +| LLM 候选池 | `30` | 进入精排的候选池大小 | +| 多意图拆分 | `true` | 一条输入拆成多个检索意图 | +| 上下文混合查询 | `true` | 融合当前输入、上一轮助手、前一条用户消息 | +| 词法增强 | `true` | 关键词精确匹配加权 | +| 时序链接 | `true` | 临近时间节点互相增强 | +| 多样性采样 | `true` | 避免召回结果过于同质 | + +### 认知与空间设置 + +| 设置 | 默认 | 说明 | +| --- | --- | --- | +| Scoped Memory | `true` | 启用作用域记忆 | +| POV Memory | `true` | 启用角色/用户视角记忆 | +| 区域目标 | `true` | 区分当前区域、邻接区域、全局 | +| 认知记忆 | `true` | 启用主客观认知归属 | +| 空间邻接 | `true` | 地区之间可建立邻接关系 | +| 故事时间线 | `true` | 启用故事时间标签 | +| 注入故事时间标签 | `true` | 在注入中提示当前故事时间 | +| 软时间引导 | `true` | 以提示方式引导,不强制改写 | ### 维护设置 | 设置 | 默认 | 说明 | -| ------ | ------ | ------ | -| 启用整合 | 开 | 相似记忆自动合并 | -| 整合阈值 | 0.85 | 向量相似度高于此值时触发合并 | -| 启用层级总结 | 开 | 启用「小总结 + 总结折叠」主路径(兼容旧 `enableSynopsis` 命名) | -| 小总结频率 | 3 次提取 | 每累计多少次提取生成一条新的小总结 | -| 折叠扇入 | 3 | 同层活跃总结达到多少条时触发一次折叠 | -| 启用反思 | 开 | 让 AI 总结长期模式 | -| 启用自动压缩 | 开 | 事件/主线节点过多时自动层级合并 | -| 启用主动遗忘 | 开 | 太久没被用到的记忆降低优先级 | -| 启用智能触发 | 关 | 仅在检测到关键内容时才提取 | -| 启用概率召回 | 关 | 以一定概率触发召回,减少 token 消耗 | +| --- | --- | --- | +| 启用整合 | `true` | 相似/冲突记忆分析与合并 | +| 整合阈值 | `0.85` | 相似度触发阈值 | +| 启用小总结 | `true` | 兼容旧 `synopsis` 名称 | +| 启用层级总结 | `true` | 使用小总结 + 折叠的总结体系 | +| 小总结频率 | `3` | 每几次提取生成小总结 | +| 总结折叠扇入 | `3` | 同层总结达到几条后折叠 | +| 启用智能触发 | `false` | 只在高信息量场景增强提取 | +| 启用主动遗忘 | `false` | 周期性降低低价值节点 | +| 启用概率召回 | `false` | 少量弱相关记忆按概率入围 | +| 启用反思 | `true` | 周期性总结长期趋势 | +| 启用自动压缩 | `true` | 按提取周期压缩同类记忆 | -### 污染标签清理 +### 任务预设与正则清理 -插件默认携带 5 条通用正则规则,自动清理 prompt 中的常见污染标签: +任务预设类型: -- `thinking/think/analysis/reasoning` — 推理/思维链标签 -- `choice` — 选择标签 -- `UpdateVariable` — MVU 变量更新标签 -- `status_current_variable` — MVU 状态变量标签 -- `StatusPlaceHolderImpl` — MVU 状态占位标签 +- **`extract`** + - 记忆提取。 -这些规则作为 `globalTaskRegex` 的默认预设,用户可以在「系统提示词」配置页自定义或清空。如果显式保存空规则,插件不会偷偷加回默认规则。 +- **`recall`** + - 召回精排。 + +- **`compress`** + - 记忆压缩。 + +- **`synopsis`** + - 小总结生成。 + +- **`summary_rollup`** + - 总结折叠。 + +- **`reflection`** + - 长期反思。 + +- **`consolidation`** + - 记忆整合。 + +- **`planner`** + - ENA Planner 规划。 + +正则清理用于减少污染标签进入提取、召回和注入: + +- `thinking` / `think` / `analysis` / `reasoning` +- `choice` +- `UpdateVariable` +- `status_current_variable` +- `StatusPlaceHolderImpl` + +用户可以在“任务预设”中调整全局正则和任务局部规则。显式保存为空规则时,插件不会自动把默认规则加回去。 + +### ENA Planner + +ENA Planner 现在通过 `planner` 任务预设接入。它可以使用: + +- 角色卡块。 +- 世界书块。 +- 最近聊天块。 +- BME 召回记忆块。 +- 历史 `` 块。 +- 当前玩家输入块。 + +建议: + +- 在“配置 → ENA 规划器”中配置基础 API 和启用状态。 +- 在“配置 → 任务预设 → planner”中调整规划 prompt 结构和生成参数。 + +### 隐藏旧楼层与渲染限制 + +这是两个不同功能: + +- **隐藏旧楼层** + - 用于控制上下文 token。 + - 不删除聊天内容。 + - 通过酒馆隐藏机制让较早楼层不再参与主回复和 ST-BME 读取。 + +- **限制聊天区渲染楼层** + - 用于减少超长聊天界面卡顿。 + - 同步到 SillyTavern 的 `chat_truncation`。 + - 只控制前端最多加载最近多少条。 + - 不等于上下文隐藏,也不等于删除消息。 + +重要提示: + +- 如果你要对很早的楼层做“重新提取范围”或完整历史恢复,建议临时关闭渲染限制或调大数量并刷新。 +- 当 ST-BME 检测到当前 `context.chat` 很可能只是最近 N 条渲染切片时,会暂停破坏性历史恢复,避免误清空运行时图谱。 + +### Native 性能加速 + +Native 加速目前是灰度能力,覆盖: + +- 图布局。 +- Persist Delta。 +- 快照 Hydrate。 + +默认策略: + +- 按节点、边、记录数、结构变化和序列化体积阈值自动命中。 +- `Fail-open` 默认开启,Native 不可用或失败时回退 JS。 +- 可以通过“全局强制关闭 Native”统一回退 JS。 --- -## 🖥️ 操控面板 +## 记忆模型 -从左上角 ≡ 菜单点「🧠 记忆图谱」打开面板。 +### 节点类型 -### 总览 Tab +| 类型 | 说明 | 示例 | +| --- | --- | --- | +| 角色 | 角色状态、性格、外貌、能力变化 | “艾琳左肩受伤,暂时无法举弓” | +| 事件 | 已发生的剧情事件 | “两人在钟楼顶层达成约定” | +| 地点 | 地点状态和环境信息 | “旧实验室的北门被封住” | +| 规则 | 世界观设定、系统规则、约束 | “血契会在月蚀时失效” | +| 主线 | 任务线、剧情线、目标 | “寻找失踪的王冠碎片” | +| 全局概要 | 兼容旧概要体系的兜底节点 | “此前剧情摘要” | +| 反思 | 长期模式、叙事建议、关系趋势 | “二人遇到压力时倾向于互相隐瞒” | +| 主观记忆 | 某角色/用户视角中的信念、误解、情绪 | “她误以为对方背叛了自己” | -- 统计数据(活跃节点、边、归档数、碎片率) -- 运行状态(聊天 ID、向量状态、持久化状态、历史状态) -- 最近提取 / 召回的记忆 +### 关系类型 -### 记忆 Tab +图谱会建立参与、发生在、推动、矛盾、更新、时序更新、引用、归属等关系,让召回不只依赖单点相似度,而能沿剧情网络扩散。 -- 搜索和筛选记忆节点 -- 点击节点查看详情 -- 支持按类型过滤 +### 主客观分层 -### 注入 Tab +- **客观层** + - 世界事实、事件、地点、规则、主线。 -- 预览当前注入内容 -- 查看 token 消耗 +- **角色 POV** + - 角色知道什么、误解什么、相信什么、在意什么。 -### 操作 Tab +- **用户 POV** + - 玩家/用户视角下需要保留的偏好、承诺、视角信息。 -- 手动提取 — 立即从当前对话提取(模式选择跨会话记忆) -- 手动压缩 — 合并重复/冗余的事件 -- 执行遗忘 — 降低长期未使用记忆的优先级 -- 生成小总结 — 基于近期原文窗口生成阶段性总结 -- 执行总结折叠 — 折叠当前活跃总结前沿 -- 重建总结状态 — 从提取批次重建小总结与折叠总结 -- 导出 / 导入图谱 -- 重建图谱 — 从当前聊天重新提取全部记忆 -- 重建向量 — 重建全部向量索引 -- 强制进化 — 让新记忆影响旧记忆 +### 故事时间线 -### 配置 Tab +每条记忆可带有: -配置页是一个完整的工作区,分成 5 个子页: +- 当前。 +- 近过去。 +- 远过去。 +- 闪回。 +- 未来预告。 +- 时间跨度。 -- **API 配置** — 记忆 LLM、Embedding 向量源 -- **功能开关** — 提取/召回/维护各项功能的启用开关 -- **详细参数** — 检索流水线、认知架构、维护阈值等细粒度参数 -- **系统提示词** — 任务预设模板编辑、全局正则规则管理 -- **面板外观** — 主题切换、通知模式 - -桌面端会显示左侧竖向子导航,右侧显示宽版配置表单;移动端则改成顶部横向子页切换。 - -### 图谱可视化 - -桌面端右侧大区域显示力导向图谱,节点可拖拽、缩放、点击查看详情。支持 4 套主题配色切换。 +这些信息会影响召回排序和注入提示。 --- -## 🔄 历史安全 +## 长聊天与历史安全 -这是最重要的功能之一。 +### 历史变动恢复 -当你在 SillyTavern 里做以下操作时: +当你执行以下操作时: -- 删除某条消息 -- 编辑某条消息 -- 切换 swipe +- 删除消息。 +- 编辑消息。 +- 切换 swipe。 +- 重跑某段提取。 -插件会自动检测到历史发生了变化,然后: +ST-BME 会: -1. **止损** — 停止当前推进,清空可能失效的注入 -2. **回滚** — 找到受影响的批次,删除相关记忆和向量 -3. **恢复** — 从变动点重新提取 +1. 对比已处理消息 hash。 +2. 找到最早受影响楼层。 +3. 清空可能失效的注入。 +4. 回滚受影响批次中的节点、边和向量。 +5. 从变动点重放提取。 +6. 更新持久化快照。 -这样你就不用担心"改了历史但记忆还留着错的内容"的问题。 +如果维护日志不足以安全回滚,会进入全量重建路径。全量重建较慢,但优先保证正确性。 + +### 渲染限制保护 + +长聊天中如果开启“限制聊天区渲染楼层”,SillyTavern 可能只把最近 N 条消息暴露给前端上下文。这样 `context.chat.length` 会短于真实聊天。 + +ST-BME 已加入保护: + +- 当图谱显示已处理到更高楼层,但当前可见 chat 只有最近 N 条时,不会立刻判断为“历史被删除”。 +- `inspectHistoryMutation()` 会跳过这类渲染切片误判。 +- `recoverHistoryIfNeeded()` 会暂停破坏性恢复,避免 full-rebuild 清空运行时图谱。 +- 面板会提示你关闭/调大渲染限制后再做完整提取或恢复。 + +### Restore Lock + +以下操作期间,ST-BME 会进入恢复锁: + +- 手动重建图谱。 +- 导入图谱。 +- 重建总结状态。 +- 云端恢复。 +- 回滚上次恢复。 + +恢复锁期间会暂停自动提取、历史恢复、持久化重试和部分召回失效处理,避免并发写入破坏数据一致性。 --- -## 📋 手动操作速查 +## 常用操作速查 -| 操作 | 说明 | -| ------ | ------ | -| 手动提取 | 不等自动触发,立刻提取当前对话 | -| 手动压缩 | 把重复/冗余的事件合并 | -| 执行遗忘 | 降低长期未使用记忆的优先级 | -| 生成小总结 | 基于近期原文窗口生成一条新的阶段性总结 | -| 执行总结折叠 | 将多条同层活跃总结折叠成更高层总结 | -| 重建总结状态 | 从提取批次重建小总结与折叠总结 | -| 导出图谱 | 下载当前图谱 JSON(不含向量) | -| 导入图谱 | 导入图谱文件(导入后需重建向量) | -| 重建图谱 | ⚠️ 清空现有图谱,从聊天记录重新提取 | -| 重建向量 | 重建全部节点的向量索引 | -| 范围重建向量 | 只重建指定楼层范围内的向量 | -| 强制进化 | 让新记忆深度影响旧记忆认知 | +| 操作 | 位置 | 说明 | +| --- | --- | --- | +| 重新提取 | 操作 → 记忆操作 | 提取未处理楼层或重跑指定范围 | +| 手动压缩 | 操作 → 记忆操作 | 合并冗余高层节点 | +| 生成小总结 | 操作 → 记忆操作 | 为近期原文窗口生成阶段性总结 | +| 执行总结折叠 | 操作 → 记忆操作 | 把多条活跃总结折叠成更高层总结 | +| 重建总结状态 | 操作 → 记忆操作 | 从提取批次重建 summaryState | +| 强制进化 | 操作 → 记忆操作 | 让新记忆主动影响旧记忆 | +| 执行遗忘 | 操作 → 记忆操作 | 归档或降权低价值节点 | +| 撤销最近维护 | 操作 → 记忆操作 | 回滚最近可撤销维护 | +| 重建向量 | 操作 → 向量操作 | 重建全部节点 embedding | +| 范围重建 | 操作 → 向量操作 | 只重建指定楼层范围相关节点 | +| 直连重嵌 | 操作 → 向量操作 | 使用直连 embedding 配置重嵌 | +| 导出图谱 | 操作 → 图谱管理 | 下载当前图谱 JSON | +| 导入图谱 | 操作 → 图谱管理 | 导入图谱,建议随后重建向量 | +| 重建图谱 | 操作 → 图谱管理 | 危险操作:清空后从当前聊天重提 | +| 备份到云端 | 配置 → 功能开关 → 云端存储模式 | 手动模式下主动上传备份 | +| 从云端获取备份 | 配置 → 功能开关 → 云端存储模式 | 手动模式下主动恢复备份 | +| 取消全部隐藏 | 配置 → 功能开关 → 隐藏旧楼层 | 恢复当前聊天由 ST-BME 隐藏的楼层 | --- -## 🏗️ 开发者参考 +## 数据存储与同步 -### 文件结构 +### 本地主存储 + +- 主存储使用 IndexedDB。 +- 数据库按聊天隔离,命名类似 `STBME_{chatId}`。 +- 热路径使用增量提交,避免整图替换。 +- 加载时优先从本地数据库恢复图谱。 + +### 云端镜像 + +云端同步使用 SillyTavern 已有文件 API,不需要自定义后端路由。 + +- 自动模式: + - 本地写入后按当前镜像逻辑同步。 + +- 手动模式: + - 本地写入仍正常进行。 + - 不自动写云端。 + - 需要点击“备份到云端”或“从云端获取备份”。 + +### 兼容与兜底 + +- 旧版 `chat_metadata.st_bme_graph` 仅作为迁移和兜底来源。 +- shadow snapshot 和 metadata-full 是 recoverable 锚点,不是首选主存储。 +- tombstone 用于同步删除状态,避免旧数据复活。 +- 插件设置存放在 SillyTavern 的 `extension_settings.st_bme`。 +- 消息级召回存放在对应用户消息的 `message.extra.bme_recall`。 + +### 持久召回卡片 + +带有有效 `message.extra.bme_recall` 的用户消息会显示召回卡片: + +- 展开后可查看召回文本。 +- 可查看召回子图。 +- 可点击节点查看详情。 +- 可编辑注入文本。 +- 可删除持久召回。 +- 可重新召回并覆盖记录。 + +优先级: + +1. 本轮有新召回成功时,使用新召回并写回目标用户楼层。 +2. 本轮无新召回时,从当前生成对应用户楼层读取持久召回作为回退。 +3. 两者都没有时,清空注入。 + +--- + +## 排障指南 + +### 面板打不开 + +- 刷新 SillyTavern 页面。 +- 确认扩展目录包含 `manifest.json`、`index.js`、`style.css`。 +- 打开浏览器控制台搜索 `[ST-BME]`。 +- 检查是否有其他扩展覆盖了左上角菜单结构。 + +### 没有自动提取 + +- 确认插件已启用。 +- 确认当前聊天已有助手回复。 +- 查看“总览 → 最近提取”和“任务 → 管线总览”。 +- 检查记忆 LLM 是否可用。 +- 如果开启智能触发,确认当前内容满足触发条件。 +- 如果处于恢复锁或持久化加载中,等待状态恢复。 + +### 召回质量差 + +- 配置或修复 Embedding。 +- 执行“重建向量”。 +- 检查召回 Top-K、最终节点上限、LLM 精排是否开启。 +- 检查节点是否过多过散,可执行整合或压缩。 +- 查看消息级召回卡片确认实际注入内容。 + +### 旧楼层隐藏后模型仍看到太多内容 + +- “限制聊天区渲染楼层”只减少前端加载,不负责节省 token。 +- 真正控制上下文需要开启“隐藏旧楼层”。 +- 设置修改后可点击“重新应用当前隐藏”。 + +### 手动提取时提示历史恢复暂停 + +通常是因为开启了“限制聊天区渲染楼层”,当前前端只加载了最近 N 条。 + +处理方式: + +1. 临时关闭“限制聊天区渲染楼层”,或把 N 调大到覆盖需要处理的范围。 +2. 刷新当前聊天。 +3. 再执行“提取未处理”或“重新提取范围”。 + +这是保护机制,不代表图谱丢失。 + +### 节点看起来突然清空 + +- 先刷新页面。 +- 如果刷新后恢复,通常是运行时状态暂时不一致,持久化图谱没有丢。 +- 查看“总览 → 最近恢复”和“任务 → 持久化”。 +- 不要立刻执行“重建图谱”,除非确认要从聊天记录重新生成全部记忆。 + +### 召回卡片不显示 + +- 确认目标楼层是用户消息。 +- 确认 `message.extra.bme_recall.injectionText` 非空。 +- 第三方主题需要保留 `#chat .mes` 消息节点和稳定楼层索引属性,例如 `mesid`、`data-mesid` 或 `data-message-id`。 +- 打开调试日志后搜索 `[ST-BME] Recall Card UI`。 + +### 直连 Embedding 失败 + +- 检查 API 地址和模型名。 +- 检查 Key。 +- 检查浏览器 CORS。 +- 优先尝试后端模式。 + +--- + +## 开发者参考 + +### 目录结构 ```text ST-BME/ -├── index.js # 主入口:事件绑定、流程调度、历史恢复、持久化协调 -├── manifest.json # SillyTavern 扩展清单 -├── style.css # 全部样式 +├── index.js # 主入口:事件绑定、流程调度、历史恢复、持久化协调 +├── manifest.json # SillyTavern 扩展清单 +├── style.css # 扩展样式 +├── package.json # 测试与开发脚本 │ -├── graph/ # 图数据模型与领域状态 -│ ├── graph.js # 节点/边 CRUD、序列化、版本迁移 -│ ├── graph-persistence.js # 聊天元数据、commit marker、shadow snapshot、加载状态 -│ ├── schema.js # 节点类型 Schema 定义(8 种节点 + 8 种关系) -│ ├── memory-scope.js # 主客观分层、空间区域归属 -│ ├── knowledge-state.js # 认知归属、可见性、区域状态 -│ ├── story-timeline.js # 故事时间线、时间桶分类、时间跨度 -│ ├── summary-state.js # 活跃总结状态管理 -│ └── node-labels.js # 节点显示名截断 +├── graph/ # 图数据模型与领域状态 +│ ├── graph.js # 节点/边 CRUD、序列化、迁移 +│ ├── graph-persistence.js # 持久化常量、加载状态、身份别名 +│ ├── schema.js # 节点和关系 Schema +│ ├── memory-scope.js # 主客观作用域与空间区域 +│ ├── knowledge-state.js # 认知归属、可见性、区域状态 +│ ├── story-timeline.js # 故事时间线 +│ ├── summary-state.js # 活跃总结状态 +│ └── node-labels.js # 节点显示名工具 │ -├── maintenance/ # 写入链路 -│ ├── extractor.js # LLM 记忆提取管线(对话 → 节点/边 → 图操作) -│ ├── extraction-controller.js# 提取任务编排、范围重提、批处理持久化快照 -│ ├── extraction-context.js # 结构化消息预处理、assistant 边界过滤 -│ ├── chat-history.js # 对话楼层管理、hash 检测、恢复日志 -│ ├── consolidator.js # 统一记忆整合(Mem0 对照 + A-MEM 进化) -│ ├── compressor.js # 层级压缩与遗忘 -│ ├── hierarchical-summary.js # 层级摘要折叠 -│ ├── smart-trigger.js # 智能触发决策 -│ └── task-graph-stats.js # 任务级图谱统计(共享排序核心) +├── maintenance/ # 写入链路 +│ ├── extractor.js # LLM 提取管线 +│ ├── extraction-controller.js # 自动/手动提取编排 +│ ├── extraction-context.js # 结构化消息和边界过滤 +│ ├── chat-history.js # 楼层、hash、历史恢复工具 +│ ├── consolidator.js # 记忆整合 +│ ├── compressor.js # 压缩与遗忘 +│ ├── hierarchical-summary.js # 小总结和折叠总结 +│ ├── smart-trigger.js # 智能触发 +│ └── task-graph-stats.js # 任务图谱统计 │ -├── retrieval/ # 读取链路 -│ ├── retriever.js # 三层混合检索编排(向量 + 图扩散 + LLM 精排) -│ ├── shared-ranking.js # 共享排序核心(查询归一化、上下文混合、向量预筛、词法评分、图扩散、混合打分) -│ ├── recall-controller.js # 召回输入解析与注入控制 -│ ├── retrieval-enhancer.js # 多意图拆分、共现增强、DPP 多样性采样、残差召回 -│ ├── diffusion.js # 图扩散算法 -│ ├── dynamics.js # 混合评分与访问强化 -│ ├── injector.js # 召回结果格式化注入 -│ └── recall-persistence.js # 持久召回记录 +├── retrieval/ # 读取链路 +│ ├── retriever.js # 召回编排 +│ ├── shared-ranking.js # 共享排序核心 +│ ├── recall-controller.js # 召回输入和注入控制 +│ ├── recall-persistence.js # 消息级召回持久化 +│ ├── retrieval-enhancer.js # 多意图、DPP、残差召回 +│ ├── diffusion.js # 图扩散 +│ ├── dynamics.js # 混合评分与访问强化 +│ └── injector.js # 注入格式化 │ -├── prompting/ # Prompt 构建与模板 -│ ├── prompt-builder.js # 任务 Prompt 组装(分层上下文 + 分段 transcript) -│ ├── prompt-profiles.js # 任务预设定义与全局正则预设 -│ ├── default-task-profile-templates.js # 默认任务模板源 -│ ├── prompt-node-references.js# Prompt 节点短引用与截断标签 -│ ├── task-regex.js # 任务正则执行器(复用酒馆正则 + 本地规则) -│ ├── task-worldinfo.js # 任务级世界书激活引擎(含 EJS 支持) -│ ├── task-ejs.js # 任务 EJS 模板渲染 -│ ├── injection-sanitizer.js # 注入内容清洗(MVU 兼容 + 正则清理) -│ └── mvu-compat.js # MVU (MagVarUpdate) 兼容层 +├── prompting/ # Prompt 与任务预设 +│ ├── prompt-builder.js +│ ├── prompt-profiles.js +│ ├── default-task-profile-templates.js +│ ├── prompt-node-references.js +│ ├── task-regex.js +│ ├── task-worldinfo.js +│ ├── task-ejs.js +│ ├── injection-sanitizer.js +│ └── mvu-compat.js │ -├── llm/ # LLM 请求封装 -│ ├── llm.js # 记忆 LLM 请求、JSON 输出、流式 SSE、超时、调试脱敏 -│ └── llm-preset-utils.js # LLM 预设工具、OpenAI 兼容提供商检测 +├── llm/ # LLM 请求封装 +│ ├── llm.js +│ └── llm-preset-utils.js │ -├── vector/ # 向量索引 -│ ├── vector-index.js # Embedding 配置、验证、向量文本构造、检索入口 -│ └── embedding.js # 直连 Embedding API 封装 +├── vector/ # 向量索引与直连 Embedding +│ ├── vector-index.js +│ └── embedding.js │ -├── runtime/ # 运行时状态 -│ ├── runtime-state.js # 楼层 hash、dirty 标记、批日志、恢复点、归一化 -│ ├── settings-defaults.js # 默认设置定义与迁移 -│ ├── generation-options.js # 生成选项解析 -│ ├── user-alias-utils.js # 用户别名检测与匹配 -│ ├── debug-logging.js # 调试日志工具 -│ ├── runtime-debug.js # 运行时诊断 -│ ├── request-timeout.js # 请求超时常量 -│ └── planner-tag-utils.js # Planner 标签工具 +├── runtime/ # 运行时状态和设置 +│ ├── runtime-state.js +│ ├── settings-defaults.js +│ ├── generation-options.js +│ ├── planner-tag-utils.js +│ ├── request-timeout.js +│ ├── runtime-debug.js +│ ├── debug-logging.js +│ └── user-alias-utils.js │ -├── sync/ # 持久化与同步 -│ ├── bme-db.js # IndexedDB (Dexie) 数据层、增量提交、快照 -│ ├── bme-sync.js # 云同步(/user/files/ 镜像)、备份/恢复、冲突合并 -│ └── bme-chat-manager.js # chatId → BmeDatabase 生命周期管理 +├── sync/ # 持久化与同步 +│ ├── bme-db.js # IndexedDB 数据层 +│ ├── bme-opfs-store.js # OPFS/sidecar 存储 +│ ├── bme-sync.js # 云端镜像与备份恢复 +│ └── bme-chat-manager.js # chatId → 数据库生命周期 │ -├── host/ # SillyTavern 宿主适配 -│ ├── event-binding.js # 宿主事件注册与调度 -│ ├── st-context.js # 酒馆上下文快照 -│ ├── st-native-render.js # 酒馆原生 EJS 渲染兼容 -│ └── adapter/ # 宿主能力适配层 -│ ├── index.js # 适配器入口 -│ ├── capabilities.js # 宿主能力检测 -│ ├── context.js # 上下文适配 -│ ├── injection.js # 注入适配 -│ ├── regex.js # 正则适配(复用酒馆原生正则引擎) -│ └── worldbook.js # 世界书适配 +├── host/ # SillyTavern 宿主适配 +│ ├── event-binding.js +│ ├── runtime-host-adapter.js +│ ├── st-context.js +│ ├── st-native-render.js +│ └── adapter/ │ -├── ui/ # 用户界面 -│ ├── panel.js # 操控面板交互逻辑 -│ ├── panel.html # 面板 HTML 模板 -│ ├── panel-bridge.js # 懒加载面板与菜单注入 -│ ├── ui-actions-controller.js# 面板 action 逻辑封装 -│ ├── ui-status.js # 持久化状态 UI 文案 -│ ├── graph-renderer.js # Canvas 力导向图谱渲染器 -│ ├── graph-renderer-utils.js # 渲染工具函数 -│ ├── panel-graph-refresh-utils.js # 面板图谱刷新工具 -│ ├── panel-ena-sections.js # ENA Planner 原生配置区绑定 -│ ├── recall-message-ui.js # 消息级召回卡片 UI(子图渲染 + 侧边栏编辑) -│ ├── hide-engine.js # 旧消息隐藏引擎(使用酒馆原生 /hide /unhide) -│ ├── notice.js # 通知系统 -│ └── themes.js # 4 套主题配色 +├── ui/ # 面板、图谱和消息级 UI +│ ├── panel.html +│ ├── panel.js +│ ├── panel-bridge.js +│ ├── panel-ena-sections.js +│ ├── ui-actions-controller.js +│ ├── ui-status.js +│ ├── graph-renderer.js +│ ├── graph-layout-solver.js +│ ├── graph-native-bridge.js +│ ├── recall-message-ui.js +│ ├── hide-engine.js +│ ├── notice.js +│ └── themes.js │ -├── ena-planner/ # ENA Planner 子模块 -│ ├── ena-planner.js # Planner 主逻辑 -│ ├── ena-planner-storage.js # Planner 存储 -│ ├── ena-planner-presets.js # Planner 预设 -│ └── (UI 已并入主面板配置页) -│ -├── vendor/ # 第三方依赖 -│ └── js-yaml.mjs # YAML 解析器 -│ -└── tests/ # 测试脚本(50+ 测试文件) - ├── p0-regressions.mjs # P0 回归测试集 - ├── graph-persistence.mjs # 图持久化测试 - ├── shared-ranking.mjs # 共享排序测试 - └── ... # 其他专项测试 +├── ena-planner/ # ENA Planner +├── native/ # Native/WASM 源码与构建产物相关目录 +├── vendor/ # vendored 依赖 +├── lib/ # 浏览器侧库文件 +└── tests/ # Node 回归测试与性能测试 ``` -### 数据存储 +### 本地开发 -- **图谱主存储(本地优先)** → `IndexedDB`(Dexie) - - DB 名固定:`STBME_{chatId}` - - 热路径走增量提交(`buildPersistDelta`),不再整图替换 - - 运行时主读取路径:优先 IndexedDB -- **跨设备同步镜像** → SillyTavern 文件 API `/user/files/` - - 同步文件名:`ST-BME_sync_{sanitizedChatId}.json` - - 备份文件名:`ST-BME_backup_{slug}-{hash}.json` - - 冲突合并:`updatedAt` 新者胜;tombstone `deletedAt` 优先;`lastProcessedFloor/extractionCount` 取 `max` - - `meta` 为同步 JSON 顶层首字段,`revision` 全程单调递增 - - 支持自动/手动两种云存储模式 -- **兼容兜底(迁移窗口)** → `chat_metadata.st_bme_graph` - - 仅用于 legacy 兼容与迁移,不再是主路径 -- **墓碑(tombstones)** → 保留期固定 30 天 -- **插件设置** → SillyTavern 的 `extension_settings.st_bme` -- **向量索引** → 后端模式走酒馆 API;直连模式存在节点内 -- **召回持久注入** → `chat[x].extra.bme_recall`(消息级) +安装依赖: -### 持久化稳态架构 - -```text -写入路径: - 提取结果 → baseSnapshot → buildSnapshotFromGraph → buildPersistDelta → db.commitDelta - ↓ - 单事务内:差量 upsert/delete/tombstone + meta/revision/syncDirty - -持久化回退链: - 1. IndexedDB(accepted=true) ← 首选 - 2. chat-state(accepted=true) ← IndexedDB 不可用时的 accepted fallback - 3. shadow / metadata-full(recoverable=true, accepted=false) ← 仅恢复锚点 - 4. pending persist 队列 ← 全部不可用时排队等重试 - -Restore Lock 门禁: - manual rebuild / graph import / summary rebuild / cloud restore / restore rollback - → 期间自动暂停:自动提取恢复 / 持久化重试 / 召回失效 / 历史恢复 +```bash +npm install ``` -### 兼容迁移策略(legacy metadata → IndexedDB) +语法检查: -- 触发:聊天加载/切换后,若目标 `STBME_{chatId}` 为空且存在 legacy `chat_metadata` 图谱 -- 行为:自动一次性迁移到 IndexedDB,并立即尝试同步到 `/user/files/` -- 幂等: - - 若 `migrationCompletedAt > 0`,跳过 - - 若 IndexedDB 已非空,跳过 -- 迁移记录: - - `migrationCompletedAt` - - `migrationSource`(默认 `chat_metadata`) - - `legacyRetentionUntil`(30 天) +```bash +npm run check +``` + +稳定测试集: + +```bash +npm run test:stable +``` + +P0 回归: + +```bash +npm run test:p0 +``` + +持久化矩阵: + +```bash +npm run test:persistence-matrix +``` + +IndexedDB 专项: + +```bash +npm run test:indexeddb +``` + +Native/性能相关: + +```bash +npm run test:native-layout-parity +npm run bench:graph-layout +npm run bench:persist-delta +npm run bench:persist-load +npm run bench:load-preapply +``` + +构建 Native WASM: + +```bash +npm run build:native:wasm +``` + +更新 manifest 版本: + +```bash +npm run version:bump-manifest +``` + +### 重要测试文件 + +- **`tests/p0-regressions.mjs`** + - 主回归集合,覆盖提取、召回、恢复、UI 关键路径。 + +- **`tests/runtime-history.mjs`** + - 消息 hash、历史 dirty、恢复状态。 + +- **`tests/message-render-limit.mjs`** + - 聊天区渲染限制和渲染切片历史保护。 + +- **`tests/graph-persistence.mjs`** + - 图谱持久化基础行为。 + +- **`tests/indexeddb-persistence.mjs`** + - IndexedDB 快照、增量提交、hydrate。 + +- **`tests/indexeddb-sync.mjs`** + - 云端同步与冲突合并。 + +- **`tests/native-rollout-matrix.mjs`** + - Native 灰度开关和阈值迁移。 + +- **`tests/task-profile-migration.mjs`** + - 任务预设迁移。 ### 事件挂载 -| SillyTavern 事件 | 做什么 | -| ------ | ------ | -| `CHAT_CHANGED` | IndexedDB 优先加载 + 自动同步 | -| `GENERATION_AFTER_COMMANDS` | AI 回复后提取记忆 | +| SillyTavern 事件 | ST-BME 行为 | +| --- | --- | +| `CHAT_CHANGED` | 加载当前聊天图谱,恢复持久状态,应用隐藏/渲染限制 | +| `GENERATION_AFTER_COMMANDS` | 助手回复后触发自动提取 | | `GENERATE_BEFORE_COMBINE_PROMPTS` | 生成前召回并注入 | -| `MESSAGE_RECEIVED` | 触发图谱持久化(IndexedDB 增量提交) | -| `MESSAGE_SENT` | 发送意图钩子,捕获权威输入 | -| 删除 / 编辑 / Swipe | 触发历史变动检测与恢复 | +| `MESSAGE_SENT` | 捕获发送意图和权威用户输入 | +| `MESSAGE_RECEIVED` | 更新自动提取队列和持久化状态 | +| 编辑 / 删除 / Swipe | 检测历史变化并恢复 | -### 召回流水线 +### 贡献注意事项 -```text -用户输入 → 多意图拆分 → 上下文混合查询 - → 向量预筛 → 图扩散 → 词法增强 - → 认知边界过滤 → 混合评分 → 多样性采样 - → [可选 LLM 精排] → 场景重构 → 分桶注入 -``` - -### 提取管线 - -```text -AI 回复 → 结构化消息预处理 - → Assistant 边界过滤(排除推理标签) - → 分层上下文组装(对话 + 图谱 + 总结 + 时间线 + Schema) - → [可选世界书扫描] - → LLM 提取 → 近邻对照 → 认知归属判定 - → 写入图谱 + 同步向量 + 故事时间线 - → [后续维护:整合/压缩/层级总结/反思/遗忘] -``` - -### Prompt 构建架构 - -```text -任务预设模板(taskProfiles) → buildTaskPrompt - ├── system: 角色指引 + 规则 + 格式定义 - ├── context blocks: - │ ├── recentMessages(分段:上下文回顾 / 当前目标) - │ ├── graphStats(共享排序核心,G1/G2 风格引用,无裸 UUID) - │ ├── activeSummaries - │ ├── storyTimeContext - │ └── worldInfo(任务级世界书扫描 + EJS 渲染) - ├── Schema 定义 - └── 用户 prompt - -全局正则(globalTaskRegex)→ 按 prompt 阶段执行清理 -任务本地正则(localRules)→ 按消息级 role 递归应用 -注入清洗(injection-sanitizer)→ MVU 兼容 + 最终安全检查 -``` - -### 持久召回注入(`message.extra.bme_recall`) - -召回注入支持消息级持久化,存放在对应用户楼层: - -- 路径:`chat[x].extra.bme_recall` -- 主要字段: - - `version` - - `injectionText` - - `selectedNodeIds` - - `recallInput` - - `recallSource` - - `hookName` - - `tokenEstimate` - - `createdAt` / `updatedAt` - - `generationCount`(**仅**在该持久注入被实际用作生成回退时递增) - - `manuallyEdited`(仅表示来源是否为人工编辑) - -注入优先级(避免双重注入): - -1. **本轮有新召回成功**:仅使用新召回注入(临时注入),并覆盖写入目标用户楼层的 `bme_recall`。 -2. **本轮无新召回结果**:仅从"当前生成对应的用户楼层"读取 `bme_recall` 作为回退注入。 -3. **两者都无**:清空注入。 - -> `manuallyEdited` 不参与优先级判断,不会强制覆盖系统召回。 - -消息级 UI: - -- 带有 `bme_recall` 的用户消息会显示内联卡片(含用户消息 + 🧠 召回条 + 记忆数 badge)。 -- 显示前提:必须同时满足 **用户楼层**、`message.extra.bme_recall` 存在、且 `injectionText` 为非空字符串。 -- 点击召回条展开,显示**力导向子图**(仅渲染被召回的节点和它们之间的边,复用 `GraphRenderer`)。 -- 子图中节点可拖拽/缩放,点击节点打开**右侧边栏**查看节点详情。 -- 操作按钮(展开态底部): - - **✏️ 编辑**:打开侧边栏编辑注入文本(实时 token 计数),保存后标记 `manuallyEdited=true`。 - - **🗑 删除**:二次确认(按钮变红 3s 超时重置),确认后移除持久召回记录。 - - **🔄 重新召回**:重新执行召回并覆盖记录,`manuallyEdited` 重置为 `false`。 -- 不再使用 `prompt()` / `alert()` / `confirm()` 浏览器原生对话框。 -- 当聊天 DOM 延迟插入时,插件会执行**有界重试 + 短生命周期 MutationObserver 补偿**,避免单次刷新错过挂载。 - -兼容性说明: - -- 旧聊天(无 `extra` 或无 `bme_recall`)会自动按"无持久记录"处理,不会报错。 -- Recall Card 依赖消息楼层存在稳定索引属性(如 `mesid` / `data-mesid` / `data-message-id`),不会再回退到 DOM 顺序猜测,以避免误挂载到错误楼层。 -- 第三方主题至少需要保留 `#chat .mes` 外层消息节点;卡片会优先尝试挂载到 `.mes_block`,其次 `.mes_text` 的父节点,最后回退到 `.mes` 根节点。 -- 若第三方主题完全移除了这些锚点或稳定索引属性,插件会选择**跳过挂载并输出 `[ST-BME]` 调试日志**,而不是静默挂到错误位置。 - -排障建议(数据存在但 UI 不显示时): - -1. 打开浏览器控制台,搜索 `[ST-BME] Recall Card UI` 或 `[ST-BME] Recall Card persist` 调试日志。 -2. 确认目标楼层是否为**用户消息**,并检查 `message.extra.bme_recall.injectionText` 是否非空。 -3. 检查消息 DOM 是否仍带有稳定楼层索引属性(`mesid`、`data-mesid`、`data-message-id` 等)。 -4. 若使用第三方主题,确认消息节点仍包含 `#chat .mes`,且消息内容区域未完全移除 `.mes_block` / `.mes_text` 相关结构。 -5. 如果聊天是异步渲染的,等待一小段时间后再次观察;插件会在短时间内自动补偿重试,而不是只尝试一次。 +- 优先保持扩展侧实现,不要把核心能力依赖到自定义 SillyTavern server plugin。 +- 修改中心抽象时,补充或更新对应测试。 +- 涉及持久化、历史恢复、导入/恢复等路径时,优先防止空图覆盖和并发写入。 +- 涉及 prompt 或正则迁移时,保留旧设置兼容。 +- 提交前至少运行 `npm run check` 和相关专项测试。 --- -## ⚠️ 已知限制 +## 已知限制 -1. **记忆质量取决于 LLM** — 模型提取不准,记忆也会不准 -2. **直连模式有跨域风险** — 浏览器的 CORS 限制可能导致请求失败 -3. **后端向量仅支持酒馆已有 provider** — 不在列表里的需要用直连 -4. **恢复优先正确性** — 批次日志缺失时会退化为全量重建,可能较慢 -5. **主观记忆依赖提取质量** — 角色视角记忆的"误解"效果需要模型配合 +- **记忆质量依赖 LLM** + - 提取模型理解错误时,记忆也会错误。 + +- **Embedding 决定召回下限** + - 没有高质量向量,召回会更依赖词法和图结构。 + +- **直连模式可能受 CORS 影响** + - 浏览器安全策略可能阻止请求。 + +- **超长聊天仍有成本** + - 隐藏旧楼层、渲染限制、总结折叠可以降低压力,但不能消除所有开销。 + +- **历史恢复优先正确性** + - 日志不足时会退化全量重建,可能较慢。 + +- **第三方主题可能影响召回卡片挂载** + - 如果主题移除了标准消息 DOM 或楼层索引属性,卡片可能跳过挂载。 + +- **Native 加速是灰度能力** + - 默认 fail-open,失败时回退 JS;遇到异常可在面板中强制关闭 Native。 --- -## 📄 License +## License -AGPLv3 — 详见 [LICENSE](./LICENSE) +AGPLv3 — 详见 [LICENSE](./LICENSE)。