diff --git a/README.md b/README.md index 9f07b37..064c5d2 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ flowchart LR - **整合** — 相似记忆合并(Mem0 精确对照 + A-MEM 进化) - **压缩** — 太多类似的事件记忆会被层级合并 -- **概要** — 自动生成"之前发生了什么"的总结(含层级摘要折叠) +- **层级总结** — 基于近期原文窗口生成小总结,并在前沿过厚时继续做总结折叠 - **反思** — 长期模式总结,生成叙事指导原则 - **遗忘** — 很久没被用到的记忆降低优先级 @@ -88,7 +88,7 @@ flowchart LR 注入的内容分成两层: -- **Core(常驻层)** — 规则、概要、主线这类始终需要的 +- **Core(常驻层)** — 规则、主线,以及在没有活跃总结前沿时兜底的旧式全局概要 - **Recalled(动态层)** — 根据当前对话语境召回的 每层内进一步按用途分桶:当前状态 / 情景事件 / 反思锚点 / 规则约束。 @@ -121,12 +121,15 @@ ST-BME 的处理方式是: ### 方法一:通过 SillyTavern 扩展安装 1. 打开 SillyTavern → 扩展 → 安装扩展 -2. 输入仓库地址: - ```text - https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology - ``` - 注意:请粘贴仓库根地址,不要使用像 `/graphs/code-frequency` 这样的 GitHub 子页面地址。 -3. 刷新页面 +1. 输入仓库地址: + +```text +https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology +``` + +注意:请粘贴仓库根地址,不要使用像 `/graphs/code-frequency` 这样的 GitHub 子页面地址。 + +1. 刷新页面 ### 方法二:手动安装 @@ -161,7 +164,7 @@ git clone https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology.git st-bme | 📍 地点 | 地点状态 | "废弃实验室,门被锁上了" | | 📌 规则 | 世界观设定、约束 | "魔法会消耗生命力" | | 🧵 主线 | 任务线/剧情线 | "寻找失踪的项链" | -| 📜 概要 | 自动生成的前情提要 | — | +| 📜 全局概要(旧) | 单条全局前情提要,现主要用于兼容 / 迁移兜底 | — | | 💭 反思 | 长期规律总结 | "他们经常在夕阳下聊天" | | 👁️ 主观记忆 | 角色视角下的记忆,含误解和情绪 | "她以为他离开了,其实他躲起来了" | @@ -187,13 +190,17 @@ ST-BME 的记忆不是扁平的——它模拟了真实的认知分层: - 时间线上下文可注入 prompt,帮助模型保持时间感知 - 支持软引导(`storyTimeSoftDirecting`),不强制但提示模型注意时间流 +### 总结状态 + +当前主用的总结体系不是 `synopsis` 节点,而是 `summaryState` 中持续演化的「小总结 + 总结折叠」活跃前沿。 + --- ## 🔧 设置说明 ### 记忆 LLM -用来做提取、压缩、整合、概要、反思等任务的模型。 +用来做提取、压缩、整合、小总结、总结折叠、反思等任务的模型。 - **留空** → 复用当前 SillyTavern 的聊天模型(最简配置) - **填写** → 你可以指定一个独立的 OpenAI-compatible 模型专门处理记忆 @@ -261,11 +268,12 @@ ST-BME 的记忆不是扁平的——它模拟了真实的认知分层: | ------ | ------ | ------ | | 启用整合 | 开 | 相似记忆自动合并 | | 整合阈值 | 0.85 | 向量相似度高于此值时触发合并 | -| 启用概要 | 开 | 定期生成前情提要 | -| 启用层级摘要 | 开 | 摘要自动折叠合并 | +| 启用层级总结 | 开 | 启用「小总结 + 总结折叠」主路径(兼容旧 `enableSynopsis` 命名) | +| 小总结频率 | 3 次提取 | 每累计多少次提取生成一条新的小总结 | +| 折叠扇入 | 3 | 同层活跃总结达到多少条时触发一次折叠 | | 启用反思 | 开 | 让 AI 总结长期模式 | | 启用自动压缩 | 开 | 事件/主线节点过多时自动层级合并 | -| 启用主动遗忘 | 开 | 太久没用的记忆降低优先级 | +| 启用主动遗忘 | 开 | 太久没被用到的记忆降低优先级 | | 启用智能触发 | 关 | 仅在检测到关键内容时才提取 | | 启用概率召回 | 关 | 以一定概率触发召回,减少 token 消耗 | @@ -307,9 +315,11 @@ ST-BME 的记忆不是扁平的——它模拟了真实的认知分层: ### 操作 Tab - 手动提取 — 立即从当前对话提取(模式选择跨会话记忆) -- 手动压缩 — 合并重复/过时记忆 -- 执行遗忘 — 主动降级低价值记忆 -- 更新概要 — 重新生成前情提要 +- 手动压缩 — 合并重复/冗余的事件 +- 执行遗忘 — 降低长期未使用记忆的优先级 +- 生成小总结 — 基于近期原文窗口生成阶段性总结 +- 执行总结折叠 — 折叠当前活跃总结前沿 +- 重建总结状态 — 从提取批次重建小总结与折叠总结 - 导出 / 导入图谱 - 重建图谱 — 从当前聊天重新提取全部记忆 - 重建向量 — 重建全部向量索引 @@ -318,6 +328,7 @@ ST-BME 的记忆不是扁平的——它模拟了真实的认知分层: ### 配置 Tab 配置页是一个完整的工作区,分成 5 个子页: + - **API 配置** — 记忆 LLM、Embedding 向量源 - **功能开关** — 提取/召回/维护各项功能的启用开关 - **详细参数** — 检索流水线、认知架构、维护阈值等细粒度参数 @@ -328,7 +339,7 @@ ST-BME 的记忆不是扁平的——它模拟了真实的认知分层: ### 图谱可视化 -桌面端右侧大区域显示力导向图谱,节点可拖拽、缩放、点击查看详情。支持 4 套配色主题切换。 +桌面端右侧大区域显示力导向图谱,节点可拖拽、缩放、点击查看详情。支持 4 套主题配色切换。 --- @@ -359,7 +370,9 @@ ST-BME 的记忆不是扁平的——它模拟了真实的认知分层: | 手动提取 | 不等自动触发,立刻提取当前对话 | | 手动压缩 | 把重复/冗余的事件合并 | | 执行遗忘 | 降低长期未使用记忆的优先级 | -| 更新概要 | 重新生成全局前情提要 | +| 生成小总结 | 基于近期原文窗口生成一条新的阶段性总结 | +| 执行总结折叠 | 将多条同层活跃总结折叠成更高层总结 | +| 重建总结状态 | 从提取批次重建小总结与折叠总结 | | 导出图谱 | 下载当前图谱 JSON(不含向量) | | 导入图谱 | 导入图谱文件(导入后需重建向量) | | 重建图谱 | ⚠️ 清空现有图谱,从聊天记录重新提取 | @@ -566,7 +579,7 @@ AI 回复 → 结构化消息预处理 → [可选世界书扫描] → LLM 提取 → 近邻对照 → 认知归属判定 → 写入图谱 + 同步向量 + 故事时间线 - → [后续维护:整合/压缩/概要/反思/遗忘] + → [后续维护:整合/压缩/层级总结/反思/遗忘] ``` ### Prompt 构建架构 diff --git a/graph/schema.js b/graph/schema.js index 6ea88cf..cd10ea0 100644 --- a/graph/schema.js +++ b/graph/schema.js @@ -149,15 +149,15 @@ export const DEFAULT_NODE_SCHEMA = [ // ====== v2 新增节点类型 ====== { id: "synopsis", - label: "全局概要", + label: "全局概要(旧)", tableName: "synopsis_table", columns: [ { name: "summary", - hint: "当前故事的全局概要(前情提要)", + hint: "旧式单条全局前情提要(兼容 / 迁移兜底)", required: true, }, - { name: "scope", hint: "概要覆盖的楼层范围", required: false }, + { name: "scope", hint: "该旧式概要覆盖的楼层范围", required: false }, ], alwaysInject: true, // 常驻注入(MemoRAG 启发) latestOnly: true, // 只保留最新版本 diff --git a/index.js b/index.js index d9b3d4c..7c4ba36 100644 --- a/index.js +++ b/index.js @@ -11041,7 +11041,7 @@ async function handleExtractionSuccess( typeof runHierarchicalSummaryPostProcess === "function" ? "层级总结" : typeof generateSynopsis === "function" - ? "概要生成" + ? "旧式全局概要生成" : "层级总结"; const cloneMaintenanceSnapshot = typeof cloneGraphSnapshot === "function" @@ -11163,9 +11163,9 @@ async function handleExtractionSuccess( ? getContext().chat : []; updateExtractionPostProcessStatus( - summaryStageLabel === "概要生成" ? "概要更新中" : "层级总结处理中", - summaryStageLabel === "概要生成" - ? `${extractionCount} 次提取,正在生成全局概要` + summaryStageLabel === "旧式全局概要生成" ? "旧式全局概要更新中" : "层级总结处理中", + summaryStageLabel === "旧式全局概要生成" + ? `${extractionCount} 次提取,正在生成旧式全局概要` : `${extractionCount} 次提取,正在检查小总结与折叠总结`, ); const summaryResult = await runSummaryPostProcess({ diff --git a/maintenance/task-graph-stats.js b/maintenance/task-graph-stats.js index 15727e2..7e562f2 100644 --- a/maintenance/task-graph-stats.js +++ b/maintenance/task-graph-stats.js @@ -8,7 +8,7 @@ const DEFAULT_TYPE_LABELS = Object.freeze({ location: "地点", rule: "规则", thread: "主线", - synopsis: "全局概要", + synopsis: "全局概要(旧)", reflection: "反思", pov_memory: "主观记忆", }); diff --git a/prompting/prompt-profiles.js b/prompting/prompt-profiles.js index 65f2974..24a49f2 100644 --- a/prompting/prompt-profiles.js +++ b/prompting/prompt-profiles.js @@ -26,8 +26,8 @@ const TASK_TYPE_META = { description: "合并并压缩高层节点内容。", }, synopsis: { - label: "概要", - description: "生成阶段性的全局剧情提要。", + label: "小总结", + description: "基于近期原文窗口生成阶段性小总结。", }, summary_rollup: { label: "总结折叠", diff --git a/tests/p0-regressions.mjs b/tests/p0-regressions.mjs index ece6400..5c301cf 100644 --- a/tests/p0-regressions.mjs +++ b/tests/p0-regressions.mjs @@ -225,7 +225,7 @@ const schema = [ }, { id: "synopsis", - label: "概要", + label: "全局概要(旧)", columns: [{ name: "summary" }, { name: "scope" }], }, ]; @@ -2108,10 +2108,10 @@ async function testConsolidatorMergeFallbackKeepsNodeWhenTargetMissing() { const restoreOverrides = pushTestOverrides({ embedding: { async embedBatch() { - return [[0.2, 0.3]]; + return [[0.4, 0.5]]; }, async embedText() { - return [0.2, 0.3]; + return [0.4, 0.5]; }, searchSimilar() { return [{ nodeId: target.id, score: 0.99 }]; @@ -2600,7 +2600,7 @@ async function testReverseJournalRollbackStateFormsReplayClosure() { const journal = createBatchJournalEntry(before, after, { processedRange: [4, 6], - extractionCountBefore: before.historyState.extractionCount, + vectorHashesInserted: ["hash_added"], }); const runtimeGraph = normalizeGraphRuntimeState( @@ -2818,7 +2818,7 @@ async function testBatchStatusSemanticFailureDoesNotHideCoreSuccess() { assert.equal(effects.batchStatus.stages.finalize.outcome, "success"); assert.equal(effects.batchStatus.outcome, "failed"); assert.equal(effects.batchStatus.completed, true); - assert.match(effects.batchStatus.errors[0], /概要生成失败/); + assert.match(effects.batchStatus.errors[0], /旧式全局概要生成失败/); } async function testExtractionPostProcessStatusesExposeMaintenancePhases() { @@ -2881,7 +2881,7 @@ async function testExtractionPostProcessStatusesExposeMaintenancePhases() { const statusTexts = harness.extractionStatuses.map((entry) => entry[0]); assert.ok(statusTexts.includes("提取收尾中")); assert.ok(statusTexts.includes("整合/进化中")); - assert.ok(statusTexts.includes("概要更新中")); + assert.ok(statusTexts.includes("旧式全局概要更新中")); assert.ok(statusTexts.includes("反思生成中")); assert.ok(statusTexts.includes("主动遗忘中")); assert.ok(statusTexts.includes("自动压缩中")); diff --git a/ui/panel.html b/ui/panel.html index a0a9e7a..ea83d8a 100644 --- a/ui/panel.html +++ b/ui/panel.html @@ -291,12 +291,11 @@ - - + diff --git a/ui/panel.js b/ui/panel.js index 436ab3f..fd82632 100644 --- a/ui/panel.js +++ b/ui/panel.js @@ -3163,7 +3163,7 @@ function _buildLegend() { { key: "location", label: "地点" }, { key: "thread", label: "主线" }, { key: "rule", label: "规则" }, - { key: "synopsis", label: "概要" }, + { key: "synopsis", label: "全局概要(旧)" }, { key: "reflection", label: "反思" }, { key: "pov_memory", label: "主观记忆" }, ]; @@ -10783,7 +10783,7 @@ function _typeLabel(type) { location: "地点", thread: "主线", rule: "规则", - synopsis: "概要", + synopsis: "全局概要(旧)", reflection: "反思", pov_memory: "主观记忆", };