长期记忆技术方案

修行问答:长期记忆技术方案

目标:为修行问答系统引入长期记忆能力,在控制 Token 消耗的前提下,保持上下文一致性,准确维护用户偏好、历史状态等实心实体,并在出现信息冲突时优先采纳最新内容,同时向用户标记矛盾点。

适用范围:修行(Cultivation)问答模块,基于 RAG + LLM 的对话系统。


目录


一、背景与问题

当前修行问答系统基于 RAG:用户提问 → 检索修行文档 → 组装 Prompt → LLM 生成回答。但该流程存在以下局限:

  1. 无状态对话:每次提问独立,模型无法记住用户上次的偏好、修行进度、习惯。
  2. Token 浪费:随着对话轮次增加,完整历史容易超出上下文窗口,导致成本上升或回答质量下降。
  3. 信息冲突:用户可能在不同时间表达矛盾偏好(如先喜欢冥想音乐,后改为静音),模型缺乏一致性校验机制。
  4. 关键信息丢失:用户明确提到的偏好、目标、上次问题等"实心实体"没有持久化维护。

本方案通过引入分层长期记忆解决上述问题。


二、设计目标

目标 说明
Token 可控 无论历史多长,输入 LLM 的上下文 Token 保持在预算范围内。
上下文一致 每次回复前校验历史状态,确保模型基于最新、最可靠的信息作答。
实时压缩 对话过程中即时压缩冗余内容,不依赖离线批处理。
摘要压缩 长历史自动提炼为结构化摘要,替代原始对话。
语义压缩 合并语义相近的多条记忆,减少重复表达。
选择性召回 根据当前问题,仅召回最相关的记忆片段。
实体状态维护 持久化用户偏好、上次询问内容、修行目标等关键实体。
冲突可见 发现矛盾时优先用最新信息,并向用户明确标记矛盾点,请求确认。

三、核心原则

  1. 最新优先原则(Recency Wins)
    当同一实体存在多个版本时,以时间戳最新的记录为准。

  2. 显式标记原则(Explicit Conflict Flag)
    模型不能静默覆盖旧信息。发现冲突时,必须在回复中提示用户:

    "你之前提到喜欢冥想音乐,这次说希望静音,我以最新偏好(静音)为准,是否需要调整?"

  3. 最小上下文原则(Minimal Context)
    只把与当前问题最相关的记忆放入 Prompt,避免历史堆砌。

  4. 可解释召回原则(Explainable Recall)
    每条被召回的记忆都应能说明召回原因(相关度分数、实体匹配、时间衰减等)。

  5. 分层存储原则(Tiered Memory)
    原始对话、摘要、实体状态分别存储,各自有独立的更新和压缩策略。


四、总体架构

用户提问
    │
    ▼
┌─────────────────────────────────────────────────────────────┐
│                    长期记忆管理器 (Memory Manager)            │
│  ┌───────────────┐  ┌───────────────┐  ┌─────────────────┐ │
│  │  工作记忆 WM   │  │  短期记忆 STM  │  │  长期记忆 LTM    │ │
│  │ 当前对话轮次   │  │ 近期摘要      │  │ 实体状态 + 历史  │ │
│  │ 原始消息       │  │ 主题片段      │  │ 语义向量索引     │ │
│  └───────┬───────┘  └───────┬───────┘  └────────┬────────┘ │
│          │                  │                   │          │
│          └──────────────────┴───────────────────┘          │
│                              │                              │
│                    ┌─────────┴─────────┐                   │
│                    ▼                   ▼                   │
│           ┌─────────────┐    ┌─────────────────┐          │
│           │ 一致性检查器 │    │ 选择性召回引擎   │          │
│           │ 冲突检测    │    │ 语义 + 实体召回  │          │
│           └──────┬──────┘    └────────┬────────┘          │
│                  │                    │                    │
│                  └────────┬───────────┘                    │
│                           ▼                                │
│                  ┌─────────────────┐                       │
│                  │  压缩与组装模块  │                       │
│                  │ 实时/摘要/语义   │                       │
│                  └────────┬────────┘                       │
└───────────────────────────┼─────────────────────────────────┘
                            │
                            ▼
                  ┌─────────────────┐
                  │   Prompt 组装    │
                  │ 系统指令 + 记忆  │
                  │ + 知识库 + 问题  │
                  └────────┬────────┘
                           │
                           ▼
                  ┌─────────────────┐
                  │    LLM 生成     │
                  └────────┬────────┘
                           │
                           ▼
                  ┌─────────────────┐
                  │  更新记忆存储   │
                  │ 实体 / 摘要 / 向量│
                  └─────────────────┘

五、记忆分层模型

5.1 工作记忆(Working Memory, WM)

  • 内容:当前会话最近 N 轮(如 3-5 轮)原始对话。
  • 作用:保证对话连贯性,处理指代、追问等。
  • 压缩策略:当轮次超过阈值,触发实时压缩,移入短期记忆。

5.2 短期记忆(Short-Term Memory, STM)

  • 内容:近期会话的摘要、主题片段、关键事件。
  • 作用:补充工作记忆,覆盖最近几次会话的核心信息。
  • 压缩策略:按主题聚类,定期摘要;语义相近的片段合并。

5.3 长期记忆(Long-Term Memory, LTM)

  • 内容
    • 实体状态(Solid Entities):用户偏好、修行目标、习惯、上次询问内容等。
    • 历史摘要:按时间线的压缩摘要。
    • 语义向量索引:所有记忆的向量化表示,支持语义召回。
  • 作用:跨会话持久化,支持长期个性化。
  • 压缩策略:摘要压缩 + 语义压缩 + 实体冲突消解。

5.4 存储示例

{
  "working_memory": {
    "session_id": "sess_20250826_001",
    "turns": [
      {"role": "user", "content": "我昨天冥想时总走神", "timestamp": "2026-08-25T21:00:00Z"},
      {"role": "assistant", "content": "走神是正常的...", "timestamp": "2026-08-25T21:01:00Z"}
    ]
  },
  "short_term_memory": {
    "summaries": [
      {
        "topic": "冥想走神处理",
        "summary": "用户反馈冥想走神,建议从 5 分钟短时冥想开始,使用计数呼吸法。",
        "start_time": "2026-08-25T21:00:00Z",
        "end_time": "2026-08-25T21:05:00Z"
      }
    ]
  },
  "long_term_memory": {
    "entities": {
      "user_preferences": {
        "meditation_sound": {
          "value": "静音",
          "updated_at": "2026-08-26T00:03:00Z",
          "source_turn_id": "turn_123",
          "confidence": 0.95
        },
        "meditation_duration": {
          "value": "15分钟",
          "updated_at": "2026-08-25T21:00:00Z",
          "source_turn_id": "turn_120",
          "confidence": 0.9
        }
      },
      "last_queries": {
        "topic": "冥想走神",
        "content": "我昨天冥想时总走神",
        "timestamp": "2026-08-25T21:00:00Z"
      },
      "goals": {
        "daily_meditation": {
          "value": "每天早晚各 15 分钟",
          "updated_at": "2026-08-20T08:00:00Z"
        }
      }
    },
    "vector_index": "chroma_db/memory"
  }
}

六、Token 优化策略

6.1 实时压缩

目标:在对话进行过程中,立即压缩刚刚发生的对话内容,避免工作记忆无限增长。

触发条件

  • 工作记忆轮次超过 N(如 5 轮)。
  • 单轮消息 Token 数超过阈值。
  • 检测到当前轮次主题已结束(用户切换话题)。

压缩方式

  1. 去除冗余礼貌语:如"你好"、"谢谢"等不影响语义的内容可简化。
  2. 提取动作-结果对:把用户行为与助手建议压缩为"问题→结论"结构。
  3. 合并连续追问:同一主题的多轮追问合并为一条。

示例

原始对话:

用户:我最近冥想总是走神,怎么办?
助手:走神很正常,可以尝试把注意力放在呼吸上。
用户:我试了,但还是会想工作的事情。
助手:这是常见的,建议你在冥想前先写下待办事项,把念头释放出来。
用户:好的,我今晚试试。

实时压缩后:

主题:冥想走神
用户问题:冥想时走神,会想到工作。
建议方案:使用呼吸专注法,冥想前写下待办事项释放念头。
用户反馈:计划今晚尝试。

6.2 摘要压缩

目标:将较长历史对话提炼为高密度摘要,替代原始消息进入 Prompt。

摘要生成策略

  1. 滑动窗口摘要:每 K 轮对话生成一段摘要,保留关键信息。
  2. 分层摘要:低层摘要继续合并为高层摘要,形成金字塔结构。
  3. 实体感知摘要:摘要中必须保留与实体状态相关的事实。

摘要模板

时间段:2026-08-20 ~ 2026-08-25
主题:冥想习惯建立
关键事件:
- 用户设定目标:每天早晚各 15 分钟冥想(8/20)。
- 用户反馈走神问题,建议使用呼吸法和事前释放法(8/25)。
- 用户偏好:冥想时使用静音(8/26)。

6.3 语义压缩

目标:识别并合并语义相近的记忆片段,减少重复存储和重复召回。

实现步骤

  1. 对记忆片段编码向量。
  2. 计算片段间余弦相似度。
  3. 相似度超过阈值(如 0.85)的片段合并为一条。
  4. 合并时保留最新时间戳,融合不同角度信息。

示例

片段 A:"用户喜欢晚上冥想。"
片段 B:"用户通常在睡前冥想。"

语义压缩后:

用户偏好:晚上/睡前进行冥想。
来源:A, B
更新时间:取最新

6.4 Token 预算分配

假设 LLM 上下文窗口为 8K,总 Token 预算分配如下:

模块 Token 上限 说明
系统指令 500 角色定义、输出规则、冲突提示规则。
实体状态 800 用户偏好、目标、上次询问等。
知识库召回 1500 修行文档相关段落。
工作记忆 1000 最近 3-5 轮原始对话。
短期/长期记忆 1500 相关摘要与历史片段。
用户问题 500 当前问题。
预留 2200 给模型输出和安全冗余。

当某部分超出预算时,优先压缩长期记忆摘要,其次工作记忆,实体状态一般只保留最高置信度的条目。


七、选择性召回

7.1 召回来源

根据当前问题,从以下三类来源召回记忆:

  1. 实体状态:与用户偏好、目标、习惯、上次询问相关的记录。
  2. 短期摘要:与当前主题相关的近期摘要。
  3. 长期语义索引:与问题语义最相似的历史片段。

7.2 召回策略

7.2.1 实体触发召回

解析当前问题中的实体关键词,直接命中实体状态:

  • 问题中提到"冥想" → 召回 user_preferences.meditation_*
  • 问题中提到"上次" → 召回 last_queries

7.2.2 语义相似度召回

使用向量检索,召回与问题最相关的历史摘要或片段。

def semantic_recall(query: str, top_k: int = 3):
    query_vec = embedder.encode(query)
    results = vector_index.query(query_vec, n_results=top_k)
    # 过滤:相关度分数 > 0.7
    return [r for r in results if r.score > 0.7]

7.2.3 时间衰减召回

近期记忆权重更高,但也要保留重要的远期记忆(如用户核心目标)。

def time_decay_score(timestamp, half_life_days=7):
    days_ago = (now - timestamp).days
    return 0.5 ** (days_ago / half_life_days)

7.2.4 综合排序

最终召回分数:

score = w1 * semantic_score + w2 * entity_match + w3 * time_decay

其中 w1 + w2 + w3 = 1,根据场景可调。

7.3 召回去重

召回结果中可能存在重复或互相包含的内容,需要再次语义去重,避免 Prompt 冗余。


八、实体状态维护

8.1 实心实体定义

实心实体是指需要长期维护、对个性化回答至关重要的信息:

实体类别 示例 更新频率
用户偏好 冥想是否开声音、喜欢的修行方式、回答风格偏好 每次对话
修行目标 每日冥想时长、戒烟目标、读经计划 用户主动设定
行为习惯 通常修行时间、常见困扰、进步节奏 持续观察
上次询问 上一个问题的主题与内容 每轮更新
事实状态 当前戒烟第几天、连续冥想天数 每次确认

8.2 实体提取

每轮对话后,使用轻量级模型或规则从对话中提取实体更新:

def extract_entities(dialog_turn) -> list[EntityUpdate]:
    """
    从单轮对话中提取实体变化。
    返回:(entity_key, value, confidence, source)
    """
    prompt = f"""
    从以下对话中提取用户偏好、目标、习惯等长期信息。
    只输出明确表达的事实,不要推测。
    格式:key | value | confidence(0-1)
    
    对话:
    用户:{dialog_turn.user}
    助手:{dialog_turn.assistant}
    """
    return llm_extract(prompt)

8.3 实体更新规则

  1. 无冲突:直接写入,更新 updated_at
  2. 有冲突:保留最新值,但在 conflicts 列表中记录旧值,供一致性检查使用。
  3. 置信度低:放入待确认区,不直接覆盖旧值。

九、一致性检查与冲突处理

9.1 一致性检查时机

每次生成回复前必须执行一致性检查:

  1. 读取当前实体状态。
  2. 读取本次召回的所有记忆。
  3. 检测是否存在时间戳更近、内容矛盾的记录。
  4. 检查当前用户问题是否与已知实体状态冲突。

9.2 冲突类型

类型 示例 处理方式
实体自我冲突 先喜欢冥想音乐,后改为静音 用最新值,标记矛盾
用户问题与历史冲突 上次说已戒烟,这次问"怎么减少抽烟" 用最新表述,温和确认
摘要与实体冲突 摘要写"每日冥想",实体写"已暂停" 以实体状态为准,更新摘要
知识库与记忆冲突 文档说"双盘 30 分钟",用户说"我只能 5 分钟" 以用户实际状态为准

9.3 冲突处理流程

检测到冲突
    │
    ▼
┌─────────────────┐
│ 1. 取最新时间戳 │
│ 2. 保留旧值为 conflict_record │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│ 组装 Prompt 时  │
│ 把冲突信息注入  │
│ 系统指令        │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│ LLM 生成回复    │
│ 优先按最新信息答 │
│ 末尾提示矛盾点   │
└─────────────────┘

9.4 回复中的矛盾标记

当存在冲突时,模型应在回复末尾以固定格式输出:

【记忆提示】
我注意到你之前提到「喜欢冥想时播放音乐」,这次说「希望冥想时保持静音」。
我已按最新偏好(静音)回答。如果这是口误或偏好已改变,请告诉我。

系统指令模板:

你在回答前会检查历史记忆的一致性。
如果发现用户当前表述与历史记录矛盾,请优先采纳时间最新的信息生成回答,
但必须在回复末尾用【记忆提示】段落说明矛盾点,并请求用户确认。
不要默默忽略旧信息,也不要质问用户。

十、完整实现流程

10.1 对话开始

async def on_user_query(session_id: str, query: str):
    # 1. 加载实体状态
    entities = memory_store.load_entities(session_id)
    
    # 2. 加载工作记忆
    working = memory_store.load_working_memory(session_id)
    
    # 3. 选择性召回
    recalled = selective_recall(query, entities, working)
    
    # 4. 一致性检查
    checked, conflicts = consistency_check(entities, recalled)
    
    # 5. 压缩与 Token 预算控制
    compressed = compress_context(working, recalled, checked, budget=BUDGET)
    
    # 6. 组装 Prompt
    prompt = build_prompt(
        system_instruction=SYSTEM_PROMPT,
        entities=checked,
        memories=compressed,
        knowledge=retrieve_knowledge(query),
        conflicts=conflicts,
        query=query
    )
    
    # 7. 调用 LLM
    answer = await llm.generate(prompt)
    
    # 8. 更新记忆
    update_memory(session_id, query, answer)
    
    return answer

10.2 记忆更新

def update_memory(session_id, query, answer):
    turn = {"user": query, "assistant": answer, "timestamp": now()}
    
    # 加入工作记忆
    working_memory.add(session_id, turn)
    
    # 提取实体
    updates = extract_entities(turn)
    for update in updates:
        entity_store.upsert(session_id, update, conflict_policy="latest_wins_flag")
    
    # 工作记忆超限时触发实时压缩
    if working_memory.token_count(session_id) > WM_TOKEN_LIMIT:
        summary = realtime_compress(working_memory.get(session_id))
        short_term_memory.add(session_id, summary)
        working_memory.clear_older(session_id, keep_last=2)
    
    # 更新向量索引
    vector_index.upsert(session_id, [turn, summary])

10.3 定时维护

def scheduled_maintenance():
    """每天或每周运行一次"""
    # 1. 对短期记忆进行摘要压缩
    for session in active_sessions:
        merge_similar_summaries(session)
        generate_high_level_summary(session)
    
    # 2. 语义压缩
    deduplicate_memories(session)
    
    # 3. 清理低置信度实体
    prune_low_confidence_entities(session, threshold=0.5)

十一、与现有系统集成

11.1 接入点

本方案作为独立模块 src/memory/ 接入现有后端:

src/
├── memory/
│   ├── __init__.py
│   ├── manager.py          # MemoryManager 统一入口
│   ├── compression.py      # 实时/摘要/语义压缩
│   ├── recall.py           # 选择性召回
│   ├── entities.py         # 实体状态维护
│   ├── consistency.py      # 一致性检查
│   └── store.py            # 存储层(JSON/向量库)
├── api/
│   └── chat.py             # 问答接口,调用 MemoryManager

11.2 数据存储

  • 实体状态data/memory_entities.json,按 session 索引。
  • 工作记忆:内存 + 可选持久化到 data/working_memory.json
  • 短期/长期摘要data/memory_summaries.json
  • 向量索引:复用现有 data/vectorstore/ 目录,新增 memory collection。

11.3 与 RAG 结合

问答接口的完整 Prompt 结构:

[系统指令]
- 角色定义
- 一致性检查规则
- 矛盾标记规则
- Token 预算意识

[实体状态]
- 用户偏好
- 上次询问
- 修行目标

[相关知识]
- 从修行文档召回的段落

[历史记忆]
- 相关摘要/片段

[工作记忆]
- 最近 3-5 轮对话

[冲突提示]
- 检测到的矛盾点(如有)

[用户问题]

十二、评估与监控

12.1 关键指标

指标 说明 目标
Prompt Token 数 每次请求的输入 Token 稳定在预算内
记忆命中率 用户问题涉及历史信息时,正确召回的比例 > 85%
冲突检出率 实际冲突中被检测出的比例 > 80%
误报冲突率 无冲突时错误提示矛盾的比例 < 10%
用户确认率 用户对冲突提示进行确认/修正的比例 tracked
摘要保留率 关键信息经压缩后仍被保留的比例 > 90%

12.2 日志记录

每次请求记录:

  • 召回来源与分数
  • 检测到的冲突
  • 使用的 Token 分布
  • 最终 Prompt 长度

便于后续调优压缩和召回策略。


十三、示例

13.1 用户偏好冲突

历史记录

  • 8/20:用户说"我喜欢冥想时播放流水声"。
  • 8/26:用户说"以后冥想请保持静音"。

当前问题:"推荐一段适合冥想的背景音乐。"

处理

  1. 召回偏好实体,发现两条记录时间戳不同且内容矛盾。

  2. 以 8/26 的"静音"为准。

  3. 生成回答:

    "你最新提到希望冥想时保持静音,所以这里不为你推荐背景音乐。如果你现在想尝试声音辅助,可以从很轻的流水声开始,音量调到几乎听不见。"

    【记忆提示】你此前曾表示喜欢冥想时播放流水声,最新偏好为静音。如果需要调整,请告诉我。

13.2 上次询问继承

历史记录

  • 上次:用户问"如何提高冥想专注力"。

当前问题:"那我平时走路的时候也可以练吗?"

处理

  1. 代词解析发现"那"指代上次话题。
  2. 召回 last_queries:主题为"提高冥想专注力"。
  3. 生成连贯回答,将专注力训练扩展到行禅/踱步场景。

13.3 长历史压缩

场景:用户连续 30 轮讨论戒烟、冥想、踱步。

处理

  1. 工作记忆只保留最近 4 轮。
  2. 早期对话压缩为三个主题摘要:"戒烟计划"、"冥想走神"、"踱步习惯"。
  3. 当前问题关于"踱步"时,主要召回"踱步习惯"摘要和最近工作记忆。
  4. Prompt Token 控制在预算内。

附录:关键配置项

# config.py
MEMORY_CONFIG = {
    "working_memory_turns": 5,
    "working_memory_token_limit": 1000,
    "short_term_summary_token_limit": 1500,
    "long_term_recall_top_k": 3,
    "semantic_similarity_threshold": 0.85,
    "entity_confidence_threshold": 0.6,
    "time_decay_half_life_days": 7,
    "conflict_flag_enabled": True,
    "total_context_budget": 8000,
}

附录 A:模块接口设计(API 草案,无实现)

以下为建议的 src/memory/ 模块接口,仅描述职责与调用方式,不展开具体代码。

A.1 MemoryManager(统一入口)

class MemoryManager:
    def __init__(self, session_id: str, config: MemoryConfig)
    
    async def prepare_context(self, query: str) -> PreparedContext
    # 职责:加载实体、召回记忆、一致性检查、压缩、组装 Prompt
    
    async def update(self, query: str, answer: str) -> None
    # 职责:更新工作记忆、提取实体、触发压缩、写入向量索引
    
    def get_entities(self) -> EntityState
    def get_conflicts(self) -> list[ConflictRecord]

A.2 EntityStore(实体状态维护)

class EntityStore:
    def load(self, session_id: str) -> EntityState
    def upsert(self, session_id: str, update: EntityUpdate,
               policy: ConflictPolicy = ConflictPolicy.LATEST_WINS_FLAG)
    def get_conflicts(self, session_id: str) -> list[ConflictRecord]
    def prune_low_confidence(self, session_id: str, threshold: float)

A.3 RecallEngine(选择性召回)

class RecallEngine:
    def __init__(self, entity_store: EntityStore,
                 summary_store: SummaryStore,
                 vector_index: VectorIndex)
    
    def recall(self, query: str, entities: EntityState,
               budget: int) -> RecallResult
    # 返回:实体命中、语义召回摘要、时间衰减加权结果

A.4 CompressionEngine(压缩引擎)

class CompressionEngine:
    def realtime_compress(self, turns: list[Turn]) -> CompressedSummary
    def summary_compress(self, summaries: list[Summary]) -> Summary
    def semantic_compress(self, fragments: list[MemoryFragment],
                          threshold: float) -> list[MemoryFragment]
    def fit_budget(self, context: PreparedContext, budget: int) -> PreparedContext

A.5 ConsistencyChecker(一致性检查)

class ConsistencyChecker:
    def check(self, entities: EntityState,
              recalled: RecallResult,
              query: str) -> tuple[EntityState, list[ConflictRecord]]
    # 返回:校验后的实体状态、待提示的冲突列表

附录 B:数据 Schema

B.1 实体状态(memory_entities.json

{
  "session_id": "sess_xxx",
  "entities": {
    "user_preferences": {
      "meditation_sound": {
        "value": "静音",
        "confidence": 0.95,
        "updated_at": "2026-08-26T00:03:00Z",
        "source_turn_id": "turn_123"
      }
    },
    "goals": {
      "daily_meditation": {
        "value": "每天早晚各 15 分钟",
        "confidence": 0.9,
        "updated_at": "2026-08-20T08:00:00Z",
        "source_turn_id": "turn_100"
      }
    },
    "last_queries": {
      "topic": "冥想走神",
      "content": "我昨天冥想时总走神",
      "timestamp": "2026-08-25T21:00:00Z"
    },
    "facts": {
      "smoke_free_days": {
        "value": 12,
        "confidence": 0.85,
        "updated_at": "2026-08-24T10:00:00Z",
        "source_turn_id": "turn_110"
      }
    }
  },
  "conflicts": [
    {
      "entity_key": "user_preferences.meditation_sound",
      "current_value": "静音",
      "previous_value": "流水声",
      "current_time": "2026-08-26T00:03:00Z",
      "previous_time": "2026-08-20T20:00:00Z"
    }
  ]
}

B.2 摘要(memory_summaries.json

{
  "session_id": "sess_xxx",
  "summaries": [
    {
      "id": "sum_001",
      "level": 1,
      "topic": "冥想走神处理",
      "content": "用户反馈冥想走神,建议呼吸专注与事前释放法。",
      "start_time": "2026-08-25T21:00:00Z",
      "end_time": "2026-08-25T21:05:00Z",
      "source_turn_ids": ["turn_120", "turn_121", "turn_122"],
      "embedding_id": "emb_sum_001"
    }
  ]
}

B.3 工作记忆(内存 + 可选持久化)

{
  "session_id": "sess_xxx",
  "turns": [
    {
      "turn_id": "turn_123",
      "role": "user",
      "content": "以后冥想请保持静音",
      "timestamp": "2026-08-26T00:03:00Z"
    },
    {
      "turn_id": "turn_124",
      "role": "assistant",
      "content": "好的,后续冥想建议中不再推荐背景音乐。",
      "timestamp": "2026-08-26T00:03:05Z"
    }
  ]
}

附录 C:接入现有问答接口步骤

C.1 新增文件(不修改业务逻辑,仅新增模块)

src/
├── memory/
│   ├── __init__.py
│   ├── manager.py          # MemoryManager
│   ├── store.py            # EntityStore / SummaryStore
│   ├── entities.py         # 实体提取与更新规则
│   ├── recall.py           # RecallEngine
│   ├── compression.py      # CompressionEngine
│   ├── consistency.py      # ConsistencyChecker
│   └── config.py           # MemoryConfig

C.2 改动点(最小侵入)

  1. src/api/chat.py(或现有问答入口)

    • 在收到用户问题时,根据 session_id 初始化 MemoryManager
    • 调用 memory_manager.prepare_context(query) 获取上下文。
    • 将返回的实体、记忆、冲突信息注入原有 Prompt 组装流程。
    • LLM 生成回答后,调用 memory_manager.update(query, answer)
  2. main.py 或启动脚本

    • 启动时加载向量索引(复用 data/vectorstore/)。
    • 可选:注册定时任务,每天执行一次 scheduled_maintenance()
  3. requirements.txt

    • 若使用向量去重/压缩,可能需要 numpyscikit-learn 等;若复用现有 embedding 则无需新增。

C.3 调用时序

用户请求到达 /chat
    │
    ▼
[chat.py] 初始化 MemoryManager(session_id)
    │
    ▼
[MemoryManager.prepare_context]
  ├─ 加载 EntityStore
  ├─ 加载 Working Memory
  ├─ RecallEngine.recall(query)
  ├─ ConsistencyChecker.check(...)
  ├─ CompressionEngine.fit_budget(...)
  └─ 返回 PreparedContext
    │
    ▼
[chat.py] 原 RAG 知识库召回(不变)
    │
    ▼
[chat.py] 组装完整 Prompt(系统指令 + 实体 + 记忆 + 冲突 + 知识 + 问题)
    │
    ▼
[chat.py] 调用 LLM
    │
    ▼
[chat.py] MemoryManager.update(query, answer)
    │
    ▼
返回回答给用户

C.4 风险与回退

  • 风险 1:实体提取不准确
    • 回退:设置高置信度阈值,低置信度实体不写入实体状态,仅作为临时记忆。
  • 风险 2:冲突误报
    • 回退:通过配置关闭 conflict_flag_enabled,或仅对高置信度实体启用。
  • 风险 3:Token 仍未控住
    • 回退:降低 working_memory_turnslong_term_recall_top_k,优先保证核心实体状态。

结语

本方案通过分层记忆 + 多层压缩 + 选择性召回 + 实体维护 + 一致性校验,在不显著增加 Token 开销的前提下,为修行问答系统赋予长期记忆能力。核心目标是:让模型"记得住"、"记得准"、"放得下"、"说得清"——记得住用户关键信息,记得准最新状态,放得下无关历史,说得清矛盾与取舍。

posted @ 2026-08-26 08:20  黄忠  阅读(4)  评论(0)    收藏  举报