long-term-memory-architecture-v2.md 9.8 KB

长期记忆现有架构设计

文档定位

本文只描述当前仓库里已经落地、并被主写作链路实际消费的长期记忆架构。

这里不再保留历史改造计划,也不把理想态蓝图混进来。判断标准只有一个:当前代码里是否真实存在、是否已经接入主链路。

一句话结论

当前长期记忆的真实实现是:

  • .webnovel/memory_scratchpad.json 作为长期语义记忆缓存
  • index.dbsummaries/state.json 作为近期状态和历史证据层
  • MemoryOrchestrator 组装 working / episodic / semantic 三层结果
  • 再由 ContextManagerextract_chapter_context.pyMemoryContractAdapter 对外消费

它已经是一条可运行的数据链,但还不是完全独立的记忆子系统。

核心边界

已经属于长期记忆主链路

  • scripts/data_modules/memory/schema.py
  • scripts/data_modules/memory/store.py
  • scripts/data_modules/memory/writer.py
  • scripts/data_modules/memory/orchestrator.py
  • scripts/data_modules/memory/bootstrap.py
  • scripts/data_modules/memory/compactor.py
  • scripts/data_modules/memory_contract_adapter.py
  • scripts/memory_cli.py
  • scripts/data_modules/context_manager.py 中的 long_term_memory 注入

仍然是旁路或相邻能力

  • .webnovel/project_memory.json
  • /webnovel-learn 产出的项目经验记忆
  • ContextManager 里的 memory section

这部分会被上下文一起读取,但不等同于 memory_scratchpad.json 这条长期记忆主链路。

现有架构图

章节结果 / 审查产物
        │
        ▼
MemoryWriter
        │
        ├── 写入 memory_scratchpad.json
        ├── 维护 active/outdated/contradicted/tentative
        └── 触发压缩与冲突检查

state.json / index.db / summaries/ / memory_scratchpad.json
        │
        ▼
MemoryOrchestrator
        │
        ├── working_memory
        ├── episodic_memory
        ├── semantic_memory
        └── long_term_facts / active_constraints / warnings / stats

        ▼
ContextManager
        │
        ├── long_term_memory section
        ├── extract_chapter_context.py
        └── MemoryContractAdapter / memory CLI

        ▼
webnovel-write / review / query / 其他消费端

数据分层

1. Working Memory

当前不是单独存储,而是运行时临时拼装,主要来源于:

  • 本章章纲
  • 最近几章摘要
  • state.json 中的主角状态、情节线程、待消歧项

这层由 MemoryOrchestrator._build_working_memory() 生成。

2. Episodic Memory

当前主要来自 index.db 的近期结构化证据,而不是独立的通用历史检索系统。

主要来源:

  • 最近状态变化
  • 最近关系变化
  • 最近出场记录

这层由 MemoryOrchestrator._build_episodic_memory() 生成,特点是偏“最近证据”,不是全量全库语义召回。

3. Semantic Memory

当前长期记忆的核心存储是 .webnovel/memory_scratchpad.json

它由 ScratchpadManager 读写,按分类分桶保存:

  • character_state
  • story_facts
  • world_rules
  • timeline
  • open_loops
  • reader_promises
  • relationships

每条记忆项统一使用 MemoryItem 结构,核心字段包括:

  • id
  • layer
  • category
  • subject
  • field
  • value
  • payload
  • status
  • source_chapter
  • evidence
  • updated_at

支持的状态为:

  • active
  • outdated
  • contradicted
  • tentative

写入链路

1. 章节结果进入 MemoryWriter

写作主链在章节提交后,会把结构化结果交给 MemoryWriter.update_from_chapter_result()

当前已实现的写入来源包括:

  • state_changes
  • entities_new
  • relationships_new
  • chapter_meta.hook
  • memory_facts

其中 memory_facts 用于更深一层的结构化映射,当前支持:

  • timeline_events
  • world_rules
  • open_loops
  • reader_promises

2. ScratchpadManager 做去重与状态收敛

ScratchpadManager.upsert_item() 的核心规则是:

  • 按分类主键规则计算去重 key
  • 同 key 的旧值降级为 outdated
  • 新值写成当前有效项
  • 保留旧值用于审计和回溯

当前各分类的主键规则由 schema.py 统一定义,例如:

  • character_statesubject + field
  • relationshipsubject + field
  • world_rulesubject + field
  • open_loopsubject

3. 超阈值时压缩

ScratchpadManager.save() 会在达到阈值后调用 compactor.py

当前压缩策略包括:

  • 同 key 的 outdated 只保留最新一条
  • 清理已回收的伏笔
  • 过旧时间线合并为摘要型 story_fact
  • 总量仍超限时按状态和新鲜度做全局截断

4. 历史项目可回填

memory bootstrap 会从现有 index.dbsummaries/ 回填出一版初始长期记忆。

当前可回填的内容包括:

  • 角色当前状态
  • 历史状态变化
  • 最近关系
  • 摘要中的“伏笔”区块

读取与编排链路

1. MemoryOrchestrator 负责统一出包

MemoryOrchestrator.build_memory_pack() 是当前长期记忆的统一读取入口。

它会做四件事:

  1. 构建 working_memory
  2. 构建 episodic_memory
  3. 读取 memory_scratchpad.json 中的 active
  4. 过滤、限额、补充告警与统计信息

输出的核心字段包括:

  • working_memory
  • episodic_memory
  • semantic_memory
  • long_term_facts
  • active_constraints
  • recent_changes
  • warnings
  • stats

其中:

  • semantic_memorylong_term_facts 当前是同一批可直接注入的长期语义事实
  • active_constraints 主要抽取 world_ruleopen_loop
  • warnings 当前主要用于暴露记忆冲突

2. 当前过滤规则

semantic_memory 不是全量注入,而是先做一轮轻量过滤。

现有过滤依据:

  • 记忆项的 subject / field / value 是否出现在本章章纲中
  • 来源章节是否落在配置允许的窗口内

然后再按预算截断。当前预算由 budget.py 和配置项共同控制。

消费层

1. ContextManager

ContextManager 仍然是写作上下文的总装配器。

context_use_memory_orchestrator=true 时,它会:

  • 调用 MemoryOrchestrator.build_memory_pack()
  • 把结果注入到 long_term_memory section
  • 再和 reader_signal / genre_profile / writing_guidance / plot_structure 一起组装最终 context

所以当前真实关系不是“记忆系统完全替代 ContextManager”,而是“记忆系统已经接入 ContextManager”。

2. extract_chapter_context.py

写作前置上下文脚本会从 ContextManager 里抽取几个关键 section,其中已经包含:

  • reader_signal
  • genre_profile
  • writing_guidance
  • plot_structure
  • long_term_memory

这意味着长期记忆已经进入主写作上下文,而不是停留在独立实验脚本里。

3. MemoryContractAdapter

MemoryContractAdapter 是对外的薄适配层。

它会把现有模块包装成统一接口,提供:

  • commit_chapter()
  • load_context()
  • query_entity()
  • query_rules()
  • read_summary()
  • get_open_loops()
  • get_timeline()

这层的意义是:当前记忆链路已经有稳定接口,但底层存储仍然复用现有 state / index / scratchpad / summaries

4. CLI

当前长期记忆相关的 CLI 分成两类:

  • webnovel.py memory ...
  • memory_cli.py

常用命令包括:

  • memory stats
  • memory query
  • memory dump
  • memory conflicts
  • memory bootstrap
  • memory update

存储职责划分

state.json

负责运行时状态,不负责长期知识沉淀。

当前主要承载:

  • 主角快照
  • 进度
  • 情节线程
  • 待消歧项

index.db

负责结构化历史证据。

当前长期记忆在读取 episodic_memory 时,主要从这里拿:

  • 状态变化
  • 关系
  • 出场记录
  • 部分追读力与审查数据

summaries/

负责章节摘要与最近写作上下文。

在长期记忆链路里,它有两个作用:

  • 作为 working_memory 的最近摘要来源
  • bootstrap 时用于回填“伏笔”类开放问题

memory_scratchpad.json

负责长期语义记忆缓存,是当前长期记忆的主真源。

project_memory.json

负责项目经验/学习沉淀,当前仍是独立旁路,不与 memory_scratchpad.json 合并。

当前已实现的关键能力

  • 长期记忆已可持久化读写
  • 已有统一 schema、状态枚举和分桶结构
  • 已有冲突检测与简单状态降级
  • 已有压缩器防止 scratchpad 持续膨胀
  • 已能把长期记忆注入主写作上下文
  • 已有 CLI 查询、回填和手工更新入口
  • 已有 MemoryContractAdapter 作为稳定外部接口

当前边界与限制

1. 不是完全独立的 memory runtime

当前仍依赖:

  • ContextManager 做最终装配
  • index.db 提供近期历史证据
  • state.json 提供运行时快照

2. episodic_memory 偏近期,不是全量历史召回

目前更像“最近结构化证据层”,不是统一的跨全书语义回忆系统。

3. semantic_memory 仍是 JSON scratchpad

当前没有单独的长期语义向量层,也没有图数据库层。

4. project_memory.json 与长期记忆主链还未统一

项目经验记忆和剧情长期记忆现在是两套并行数据源。

5. 冲突裁决还是轻量规则

当前主要是:

  • 主键去重
  • 旧值降级
  • 冲突统计

还没有更重的跨章节语义裁决流程。

结论

当前仓库里的长期记忆已经从“方案讨论”进入“可运行架构”阶段,但它的真实定位应当是:

  • 已接入主写作链路
  • 已有持久化、编排、消费和运维入口
  • 仍然建立在现有 ContextManager + state/index/summaries 生态之上

因此,这份文档只保留“现状架构说明”。

历史计划文档已经移除;如果后续继续演进,应重新按当时的真实代码状态单独写新 spec。