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