罗德岛通讯与技术部

记忆、压缩与上下文工程

MEMORY & CONTEXT

│ └─ 提取 → L3 长期(ChromaDB + BM25 RRF)

状态:🔴 历史 · 最后核对 2026-08-06

2026-06-24 · 综合对话压缩审计、酒馆架构分析、漂移防御实践、向量化升级讨论

相关文档:architecture · CHANGELOG · competitive-analysis · character-consistency-research


⚠️ 本文档写于向量化升级之前,"现状"部分已全部过期(复核于 2026-07-28):

文中说 实际
§1.1 / §1.4 嵌入模型是 MiniLM 384d 已迁到 BGE-small-zh-v1.5 512d(中途试过 BGE-M3 1024d 又退回,CPU 推理 4s→9ms)
§1.1 L3 检索含 BM25 BM25 已删除(2026-06-25,-197 行),改纯双集合稠密检索。
⚠️ 2026-08-05 差点原路走回去:backlog F20 登记的是「混合检索(关键词 + 向量)」,而我是从零重新推导出「词法帮倒忙」的,没先来看这一行。改成了交叉编码器重排,见 decisions
§1.2 深聊每 5/20 轮压缩、核心叙事 ~1000 tokens、上下文 20 轮 改为每 10 轮合并 / 每 50 轮重写,叙事预算 5000 tokens,上下文 200 轮(2026-07-12)
§2.3 检索是主动触发的 每轮被动检索已实施
§2.6 context 无硬上限 窗口化上下文已实施,50 轮硬上限 + 状态快照
第五节整章的"向量化升级路线" P0-P3 全部已实施,此章现在是历史记录而非计划

仍然有效的部分:第三节(SillyTavern 机制分析)、第四节(窗口化设计原理)、 第七节(总览图)。系统当前状态以 architecture.md §3.2/§3.10/§3.11 为准。


一、现状:我们有什么

1.1 三层记忆管道

用户消息
  │
  ├─ L1 短期(原始消息)
  │   按语义 chunk 分块,嵌入漂移检测自动切块
  │   硬上限 200 条,锚点权重保护
  │   活跃 chunk ≤ 20 条保留在 context
  │
  ├─ 触发压缩(>20条)→ 后台 LLM
  │    ├─ 摘要 → L2 中期(30 条 slice)
  │    │   遗忘曲线 + 显著性 + 主题标签
  │    │   Hub 升级:注入 ≥ 3 次 → L3
  │    │
  │    └─ 提取 → L3 长期(ChromaDB + BM25 RRF)
  │        每干员 500 条事实,去重 + 贝叶斯置信度
  │        LLM Wiki:高分互动后自动写洞察
  │
  └─ 检索(每轮)
      协调器 Z-Score 混排:L2/L3 各取 top-30
      → 双时间轴衰减 → 信赖维度调制 → 填充预算

1.2 深聊独立管道

深聊不经过 L1 压缩流水线。独立 SQLite 存储。

核心叙事(~1000 tokens)
  ├─ [ANCHORS] 星标时刻——告白、承诺、冲突和解——永不过期
  ├─ [ARC] 最近 20 轮连贯叙事 ~1200 字
  └─ [ECHO] 20 轮以前模糊摘要 ~300 字

压缩节奏:每 5 轮增量合并 → 每 20 轮完整重写

辅助索引:细节索引(每轮提取 1-3,星标永不过期)
          消息索引(用户消息 + 嵌入,200 条 FIFO)
          情绪弧线(60 条记录,含身体锚点)

桥接到 L2/L3:结束 → memory capsule → L2 + L3

1.3 抗退化防御

机制 触发 原理
周期身份重锚定 每 15 轮 身份信息重新放到注意力 U 型右端点
元认知重述 每 10 轮 LLM 在 <thinking> 自己重述身份+铁律
代理信号监控 长度递增/句式密度/躯体脱钩 → 2+ 触发 注入强制重锚定块
Nautilus Compass 每轮 embedding 对比行为锚点 偏离时注入 reaffirmation
身份守卫 L1-L3 攻击/覆写检测 状态机防御

1.4 嵌入模型

当前:paraphrase-multilingual-MiniLM-L12-v2(384 维,2021 年)
备选:智谱 embedding-2(远端 API)
BM25:自写 bigram 分词 + 标准 BM25 公式(k1=1.2, b=0.75)

二、问题:哪里有缺口

2.1 压缩的结构性不对称

普通聊天 L1→L2 深聊 core_narrative
格式 {topic, summary, key_facts} [ANCHORS] → [ARC] → [ECHO]
锚定 ——摘要不含身份锚点 ——ANCHORS 段天然锚定
重写周期 被动(消息超阈值才触发) 主动(每 5/20 轮定期)
衰减精度 扁平——所有 chunk 摘要精度相同 三层——全精 / 精 / 模糊

普通聊天的压缩没有"锚定格式"。LLM 生成摘要时不包含"她是谁"和"她怎么说话"——这恰是我们在漂移分析里说的"朴素摘要加速漂移"。

2.2 没有压缩后验证

摘要直接写盘,不检查是否保留了关键约束。如果摘要在写入时已有偏差,后续所有检索都基于偏差。

2.3 检索是主动的,不是被动的

跨块回溯只在用户说"你还记得吗"时触发。酒馆的聊天向量化是每轮被动检索——不等用户问,自动拉回最相关的旧内容。

2.4 检索目标的"信息密度"问题

酒馆社区的共识:原始消息向量检索有致命缺陷——"几十条战斗描述淹没一条魔法剑的关键信息"。解决方案是先摘要再向量化。你们 L1→L2→L3 已经在做这个,但检索时 L2/L3 的结构化字段(topic_tags, emotion_valence, category)没有用于检索过滤,仅用于排序加权。

2.5 嵌入模型已旧

MiniLM 384 维是 2021 年模型,中文不是一等公民。BGE-M3(1024 维 + dense + sparse 双输出)是当前 SOTA,可以一个模型统一替代 MiniLM + 手写 BM25

2.6 Context Window 没有硬上限

靠 L1 压缩延后问题——压缩是被动触发的(消息数超阈值),不是主动的(轮次到上限就切窗口)。深聊有 20 轮重写周期做结构重置,普通聊天没有。


三、酒馆(SillyTavern)的参考

3.1 核心机制:聊天向量化

每轮生成前:
1. 取最后 N 条消息 → embedding → 查询向量
2. 和聊天历史所有消息做余弦相似度
3. 保留最近 M 条不动(Retain# = 5)——保护当前对话流
4. 拉回 top-K 最相关的旧消息(Insert# = 3)
5. 注入到 prompt 开头或底部——"重排序"而非"追加"

本质:利用 LLM 注意力 U 型分布,把可能被遗忘的相关旧消息
      搬到注意力高峰位置。和 periodic re-anchoring 同一理论基础。

3.2 社区方案的关键方向

模式 代表 要点
结构化事件 VectFox 提取 characters, locations, items, concepts 元数据 → 检索时字段过滤
记忆图谱 ST-BME 实体-关系-事件图谱 + 图扩散 + DPP 多样性采样 + LLM 精排
时间衰减 VectHare 指数/线性时间衰减,可设半衰期
认知架构 ST-BME 区分角色 POV / 用户 POV / 客观世界记忆
跨会话连续性 CharMemory 自动提取结构化记忆 → 新聊天也能唤起

3.3 酒馆的共同缺陷

  • 没有漂移防御——答案是"用户自己注意,不行就开新聊天"
  • 摘要退化——社区承认"1000+ 条消息后滚动摘要变成一团模糊"
  • 信息密度不均——原始消息直接向量化会淹没关键信息

3.4 酒馆 vs 罗德岛

机制 酒馆 罗德岛
短期记忆 最近 N 条保留在 context L1 活跃 chunk 保留原始消息(≤20 条触发压缩)
中期记忆 滚动摘要(单块,越来越模糊) L2 结构化 slice + 遗忘曲线 + 显著性 + 主题标签
长期记忆 Data Bank 文件 RAG(手动上传) L3 ChromaDB + BM25 RRF(自动提取)
旧消息拉回 每轮被动检索 + 重排序 跨块回溯(主动触发——用户说"还记得吗")
深层叙事 deep_chat 三层结构 + 情绪弧线 + 详情索引
漂移防御 五层防御体系
压缩品质 滚动摘要退化 结构化 slice + 遗忘曲线

酒馆做得更好:每轮被动检索——不等用户触发,自动拉回相关记忆。 罗德岛做得更好:漂移防御、遗忘曲线、结构化记忆、叙事完整性保护。


四、窗口化上下文管理(新方案)

4.1 核心理念

当前:context 无限增长 → 压缩延后 → 重锚定防御 → 终究会退化

改为:context 硬上限 40-50 轮 → 窗口结束时主动采集状态快照
     → 新窗口从快照恢复 → context 永远在安全范围内

这不是替代现有系统——是给它加一层"结构重置"。窗口内的 L1/L2/L3 管道、漂移检测、身份守卫全部不变。窗口切换只是在管道之上做硬性约束,让 context 永远不超出安全长度。

4.2 窗口切换流程

窗口 N(第 1-50 轮)
  │
  │ 第 45 轮起:后台预采集状态快照
  │   (复用现有 summarize_and_extract_task 的后台模式)
  │
  ├─ 第 50 轮结束:窗口关闭
  │   采集:情绪状态 + 关系状态 + 关键事件([ANCHORS])
  │         + 身体记忆 + 说话方式偏移
  │
  ▼
窗口 N+1(第 51-100 轮)
  │  初始化:从快照恢复状态
  │  system prompt 开头不是"之前发生了什么"
  │  而是"你是翎羽。你现在的状态是..."
  │
  └─ context window 从 0 开始,永远 ≤ 50 轮

4.3 状态快照格式

{
  "window_id": 3,
  "round_range": [101, 150],
  "emotional_state": {
    "tone": "温暖", "intensity": 4, "undertone": "疲惫",
    "trajectory": "从警觉→放松→信任"
  },
  "relationship": {
    "trust": {"professional": 62, "emotional": 71, "rapport": 55},
    "impression": "嘴硬心软",
    "recent_shift": "她开始在他面前不再检查望远镜"
  },
  "anchors": [
    {"round": 123, "type": "promise", "text": "博士说'下次我陪你'——她没回答但耳朵红了"},
    {"round": 138, "type": "confession", "text": "她说'不是因为你是博士——是因为你来了'"}
  ],
  "somatic_memory": {
    "residues": ["右肩紧张已缓解", "说话时不再看门口"],
    "s_shift": {"warmth": +0.12, "tension": -0.08}
  },
  "speech_pattern": {
    "avg_length": "比窗口 1 短了 30%",
    "banned_pattern_triggers": 0,
    "sentence_variety": "正常"
  }
}

4.4 Per-operator 窗口大小

利用漂移信号数据动态调整:

干员 建议窗口 依据
凯尔希 60 轮 沉稳型,话少而精,退化慢
翎羽 50 轮 默认值
拉普兰德 35 轮 情绪波动大,对话节奏快
贝洛内 40 轮 平均会话最长,漂移风险高

五、向量化升级路线

5.1 四个维度总览

维度 做什么 效果 迁移代价
换模型 BGE-M3 替代 MiniLM + BM25 中文质量 ↑↑,一个模型统一稠密+稀疏 中——需重建 ChromaDB
表示方式 分段嵌入替代单向量 长摘要检索精度 ↑ 低——不改模型,只改存储格式
降维量化 Matryoshka 分层精度 去重 1024d / 检索 512d / 话题检测 256d 极低——BGE-M3 天然支持截断
时间感知 向量尾部拼接时间特征 远期记忆天然排名更低 低——检索时计算

5.2 P0:BGE-M3 迁移

为什么先做:一个模型统一稠密 + 稀疏双路检索,删掉手写 bigram 分词器。中文语义区分度从 384 维提升到 1024 维。

怎么迁移(零停机)

  • 新事实写入 BGE-M3 集合
  • 旧事实留在 MiniLM 集合,随窗口切换逐步被新快照替代
  • 检索时两个集合都查,合并结果
  • 过渡期结束后删除 MiniLM 集合

需要注意:所有余弦阈值需要重新标定(话题切换 0.5、L2 相关性 0.35、L3 去重 0.08 都是在 384 维上调的,1024 维空间分布不同)。

5.3 P1:Matryoshka 分层精度

BGE-M3 天然支持截断——存全维,检索时按场景取前 N 维:

场景 维度 理由
L3 去重(写入) 1024 最高精度判断是否重复
L2 检索(注入 prompt) 512 中等精度足够,更快
话题漂移检测(每轮) 256 只需粗粒度语义偏移判断,极快

零额外存储——同一批向量,不同场景不同截断长度。

5.4 P1:每轮被动检索(酒馆模式)

当前:用户说"你还记得吗" → 触发跨块回溯

改为:每轮生成前 → 用本轮对话语义做查询向量
     → 检索 L2 摘要 + L3 事实(不是原始消息)
     → 注入 top-3 最相关记忆到 prompt

复用现有 retrieve_zscore(),改触发条件。和酒馆的聊天向量化同原理,但检索目标是信息密度更高的摘要和事实,而非原始消息。

5.5 P2:结构化事件元数据

在 L2 摘要写入时,LLM 额外提取结构化字段:

{
  "event_type": "emotional_breakthrough",
  "characters_involved": ["翎羽", "博士"],
  "location": "舰桥第五瞭望哨",
  "concepts": ["哨位", "凌晨", "绒羽变色", "陪伴"],
  "emotional_peak": true
}

检索时做元数据过滤 + 向量相似度混合排序——精度从"语义相似"提升到"语义 + 结构 = 精确过滤"。

5.6 P3:时间感知特征拼接

dense_vector (1024d) + [window_age, recency_score, anchor_weight] (3d)

查询向量同样拼接——余弦计算天然包含时间维度。远期记忆在向量空间里"自然地远离"当前查询。


六、实施优先级

近期(1-2 周)—— 低垂果实

改动量 说明
每轮被动检索 复用 retrieve_zscore(),改触发条件。不等用户问,每轮自动拉回相关记忆
压缩后格式验证 极小 摘要写入后跑 BANNED_PATTERNS 正则 + 长度检查
L1→L2 锚定摘要 SUMMARY_PROMPT 加一步:先逐字复制身份+铁律,再写摘要

中期(1 月)—— 结构性改进

改动量 说明
BGE-M3 迁移 双集合过渡,统一稠密+稀疏,删掉手写 BM25
Matryoshka 分层精度 BGE-M3 截断参数,各场景独立阈值
窗口化上下文管理 窗口计数器 + 预采集 + 新窗口初始化 + 状态快照格式

长期(季度)—— 深度优化

改动量 说明
结构化事件元数据 SUMMARY_PROMPT 扩展 + L2 格式升级 + 元数据过滤检索
时间感知特征拼接 3 维时间特征拼入 L3 向量
Per-operator 窗口大小自适应 基于漂移信号数据动态调整窗口上限
记忆图谱 评估 ST-BME 模式是否适合罗德岛的规模

七、总览

┌──────────────────────────────────────────────────────────────┐
│                  Context Window(≤ 50 轮)                     │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌─────────────┐ │
│  │ 氛围块    │  │ 状态快照  │  │ 被动检索  │  │ 硬指令垫底   │ │
│  │ (感官世界)│  │ (身份+关系)│  │ (L2+L3)  │  │ (铁律+CoT)  │ │
│  └──────────┘  └──────────┘  └──────────┘  └─────────────┘ │
│                                                              │
│  窗口内防御:周期性重锚定 · 元认知重述 · 信号监控 · 身份守卫    │
└──────────────────────────────────────────────────────────────┘
                            │ 窗口关闭
                            ▼
┌──────────────────────────────────────────────────────────────┐
│                   状态快照(跨窗口桥接)                        │
│  情绪 · 关系 · ANCHORS · 身体记忆 · 说话方式偏移                │
└──────────────────────────────────────────────────────────────┘
                            │
                            ▼
┌──────────────────────────────────────────────────────────────┐
│                   长期记忆管道(持续运行)                       │
│                                                              │
│  L1(原始消息)→ L2(结构化摘要)→ L3(向量化事实)              │
│                                    │                         │
│                      BGE-M3 1024d + Matryoshka 分层           │
│                      稠密+稀疏双路 + 结构化元数据过滤            │
│                      每轮被动检索 + 时间感知                    │
└──────────────────────────────────────────────────────────────┘