Files
natural-memory/Natural_Memory_v2_Paper.md
T

313 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Natural Memory v2:面向长期交互的分层神经记忆与稀疏地址路由
## 摘要
大语言模型的长期记忆通常有两种实现:把历史对话原样放回上下文,或者把历史写入外部检索系统。前者的计算和显存成本随历史长度增长,后者虽然实用,却把记忆写入、读取和纠错放在模型之外,模型本身并不知道记忆为何存在、是否可信以及何时应该停止检索。
本文提出 Natural Memory v2,一种附着在冻结 Qwen3.5-4B 主干上的分层记忆架构。它不试图让 Memory Slot 复现完整 KV Cache,而是把长期、昂贵、适合结构化复用的历史信息编码成紧凑地址和版本化证据记录;当前窗口继续由热 KV 负责精确顺序和局部连贯性。V2 的查询路径固定为“粗索引—候选页—精确重排—Top-K 读取”,因此查询复杂度不随全部记忆槽做全量注意力。系统还加入了自动写入策略、置信度隔离、冲突版本、纠错、撤回、多跳关联和嵌入式持久化。
在本地控制变量实验中,20,000 条合成记录被组织为 626 个页面,平均只进入 178.13 个候选页(28.45%);记录 Recall@K 与页 Recall@K 均为 100%,多跳和导出恢复测试均通过。通用路由器的候选 route accuracy 为 99.32%,Qwen hidden-state 路由器在 103 条 held-out 事实上的 route accuracy 为 91.26%。在 120 个固定的通用、数学、推理、语言、知识、逻辑和上下文用例上,Natural Memory v2 与原版 Qwen3.5-4B 的总分都为 0.85833,回归差值为 0。真实模型重启实验中,模型没有收到历史聊天记录,仍通过嵌入式 memory shard 找到目标事实并正确生成;未知事实经过阈值校准后不再进入内部证据前缀。
这些结果证明的是架构闭环和工程可行性,而不是已经解决百万级自然语言记忆。本文同时报告多跳路由不足、训练数据规模有限、NVMe 级分页注意力尚未完成等限制,并给出下一阶段的训练与系统路线。
**关键词:** 大语言模型、长期记忆、Memory Slot、KV Cache、稀疏路由、分页索引、持续学习、事实纠错
## 1. 问题定义
设当前对话的 token 序列为 (x_{1:t}),模型的热 KV 为 (K_t,V_t)。如果所有历史都保留在注意力上下文中,序列长度 (t) 变大时,注意力计算和 KV 显存都会持续增加。另一种做法是把历史写入外部数据库,再由固定程序检索结果并拼接进 prompt。后一种方法把检索变成了应用层逻辑:模型通常无法区分未经确认的推断、已经被纠正的旧值和当前有效值。
Natural Memory 的目标不是让一个固定大小的张量保存所有原始历史,而是让模型拥有一种长期运行的神经记忆接口:
1. 重要的个人事实、项目约束和事件关系可以自动进入记忆;
2. 查询只访问少量有地址的记忆单元;
3. 新旧事实具有可解释的版本关系;
4. 证据不足时模型可以拒绝读取,而不是把相似内容强行当答案;
5. 记忆状态可以在模型重启后恢复,而不需要重放聊天记录。
这里的“神经记忆”指记忆读取和写入策略是模型架构的一部分,并不意味着所有存储介质都必须是 GPU 上的可训练参数。长期记忆可以是模型拥有的状态快照,读取器、路由器和写入控制器则直接参与模型运行。运行时优先将热点记录提升到 VRAM,同时保留显存安全余量;无法安全提升的记录继续驻留在系统 RAM。
## 2. 设计原则
### 2.1 Memory Slot 不模拟 KV
KV Cache 适合保存近期 token 的精确顺序;Memory Slot 适合保存跨会话仍有价值的事实、摘要和关联。两者承担不同的任务:
```text
热 KV = 当前工作内存,强调顺序和细节
Memory Slot = 长期神经 RAM,强调地址、复用和生命周期
冷页面 = 更大容量的历史存储,按需加载
```
如果要求 Memory Slot 无损等价于数百万 token 的原始 KV,那么它最终仍然需要保存近似相同的信息量,只是换了数据结构。V2 选择有损但可审计的语义压缩:长期证据优先,当前上下文精确。
### 2.2 任何大规模读取都必须有界
不允许当前 token 对全部槽位直接做注意力。V2 采用两阶段路由:
1. 用 LSH 粗索引从页面签名中取候选页面;
2. 对候选页面做页级和记录级精确重排;
3. 只将 Top-K 记录的 token 证据送回 Qwen。
页面签名同时包含页面中心和记录地址。这样可以避免混合主题页面的中心向量把某一条稀有但相关的记录“平均掉”。当前实现还会探测查询签名的 Hamming 距离 1 和 2 的桶,并始终保留少量热页作为安全候选。
### 2.3 错误必须进入状态机
长期记忆最危险的不是暂时漏召回,而是一次错误写入之后长期污染回答。因此一条记录除了文本和向量外,还带有:
- 来源和证据;
- 置信度和重要性;
- 创建时间、访问次数和版本;
- 实体—属性—值冲突键;
- `active`、`superseded`、`retracted`、`quarantined` 状态;
- `supersedes` 和 `related_ids` 关系。
重复写入是幂等的;同一实体和属性的新值会 supersede 旧值;不可信写入进入 quarantine,不参与普通读取;显式纠错生成新版本;撤回记录仍保留审计信息但不再被读取。
## 3. 架构
### 3.1 路由器
给定查询 hidden state (q) 和候选记忆键 (k_i),路由器先把两者投影到 (d=128) 的紧凑地址空间:
[
hat q = \operatorname{norm}(W_q q), \qquad
hat k_i = \operatorname{norm}(W_k k_i).
]
V2 使用 8 个路由头。每个头计算局部相似度,头门控对各头加权;随后将查询、候选和差向量送入 pair scorer。路由器同时输出:
- 候选记录分数;
- 是否需要记忆的二分类 logit;
- 多跳步数预测;
- 每个路由头的诊断分数。
存储侧只保留紧凑地址,而不保存每条记录的 2560 维 Qwen hidden state。查询时只把当前 query 和已经由粗索引筛出的候选键放到路由器所在设备。
### 3.2 分页记忆库
一个页面包含有限数量的记录、页面中心、摘要中心、重要性和冷热等级。默认页面容量为 32 条记录,最大页面数为 32768,懒分配容量为:
[
32768 \times 32 = 1,048,576
]
这只是地址空间上限,不代表启动时分配一百万条记录。写入侧只在开放页的有界窗口中选择目标页,避免随着页面数增长而扫描整个写入空间。达到硬上限后系统抛出明确的容量错误,要求先 consolidation 或提高容量,而不是静默超过限制。
### 3.3 多跳检索
一次查询先得到候选页面和记录。被选记录可以带关联记录 ID,下一跳只在关联记录所在的页面中继续搜索。每跳都记录访问轨迹、去重集合和停止原因。系统在达到 Top-K、最大 hop、无新关联或没有新证据时停止。
### 3.4 Qwen 集成
V2 作为 Qwen3.5-4B 的附加模块接入:
- Qwen 主干冻结;
- 原有 memory controller、自然语言写入策略和热文本 bank 保留兼容性;
- V2 router 注册为模型模块并可单独训练;
- 生成前由当前查询 hidden state 触发 V2 读取;
- 选中记录的 token 序列在模型内部形成证据前缀;
- 生成本身不更新持久记忆,写入发生在当前用户回合结束前;
- memory state、路由器参数、页面元数据和记录 token 可写入 safetensors memory shard。
该设计使模型重启时只需要重新加载模型包和内嵌状态,不需要把历史聊天重新放入 prompt,也不需要依赖一个固定的外部数据库读取程序。
## 4. 训练方法
### 4.1 路由训练目标
训练损失由三部分组成:
[
\mathcal L = \mathcal L_{candidate}
+ \lambda_n \mathcal L_{need}
+ \lambda_h \mathcal L_{hop}.
]
其中候选损失使用包含 hard negatives 的交叉熵;need loss 判断问题是否需要记忆;hop loss 预测继续关联检索所需的步数。负样本不仅包括随机记录,还包括相同实体、相近属性、共享词汇但答案不同的记录。无记忆问题作为独立类别参与训练,使路由器有机会学会 abstain。
### 4.2 两个训练阶段
第一阶段使用共享潜在因子训练通用路由器,验证分页、地址投影和损失函数是否稳定。第二阶段使用真实 Qwen3.5-4B 的 hidden state 编码实体—属性—值事实,并在不同实体、不同属性和 hard negative 上训练 Qwen 专用路由器。
第二阶段目前使用 512 条本地合成事实,409 条用于训练、103 条用于 held-out。这样做主要是工程启动数据,不足以代表真实用户对话的分布。正式版本需要加入:
- 同一事实的多种问法;
- 省略主语、代词和跨语言表达;
- 时间先后和旧值修正;
- 多事实组合与多跳路径;
- 没有记录时的拒答;
- 误导性相似事实和记忆污染样本。
## 5. 实验设置
### 5.1 硬件与加载
实验使用 RTX 5070,报告的总显存为 11.94 GiB;Qwen 使用 4-bit NF4 加载。主干权重保持冻结。结果来自本地工程测试,不是公开排行榜结果。
### 5.2 核心组件测试
单元测试共 18 项,覆盖:
- 路由器输入输出形状与紧凑地址;
- 页面粗索引候选边界;
- 版本冲突、纠错和 slot 替换;
- quarantine、批准和撤回;
- 多跳关联;
- safetensors 前的导出/恢复语义;
- KV 预算和页容量上限。
结果为 18/18 通过。
### 5.3 分页检索实验
在 20,000 条合成记录、626 页、Top-K 页面和记录限制下,结果如下:
| 指标 | 结果 |
|---|---:|
| 粗候选页平均数 | 178.13 |
| 粗候选页最大数 | 429 |
| 粗候选页占全部页面 | 28.45% |
| 记录 Recall@K | 100% |
| 页面 Recall@K | 100% |
| 多跳成功 | 100% |
| 多跳步数 | 2 |
| 导出恢复后召回 | 100% |
| 冲突版本与纠错 | 通过 |
| quarantine 隔离与批准 | 通过 |
| 撤回隔离 | 通过 |
| 重复写入幂等 | 通过 |
页面容量配置为 32768 页 × 32 条记录,地址空间为 1,048,576 条记录。除 20,000 条分页检索实验外,项目还完成了 1,000,000 条轻量记录的 durable page store 压力测试:31,250 页实际落盘,重启后记录总数保持 1,000,000,64 个常驻页对应约 160 条常驻记录,目标记录通过精确粗桶召回。该结果证明的是存储、冷热分层和地址路径,不声称已经完成一百万条完整自然语言长文本的 Qwen 端到端质量验证。
通用路由器在 40 个评估批次上的结果为:route accuracy 99.32%,need-memory precision、recall、specificity 均为 100%,hop accuracy 为 86.25%。这些数字来自合成分布,不能直接推断真实对话泛化。
### 5.4 Qwen hidden-state 路由器
Qwen 专用路由器的 held-out 结果:
| 指标 | 结果 |
|---|---:|
| held-out 事实 | 103 |
| route accuracy | 91.26% |
| need precision | 100% |
| need recall | 100% |
| need specificity | 100% |
| hop accuracy | 36.70% |
多跳控制器明显弱于候选记录路由。这意味着当前系统的可靠性主要来自显式关联关系、页面约束和记录状态机,不能把 hop prediction 当作唯一的正确性保证。
### 5.5 与原版 Qwen3.5-4B 的回归
综合测试使用同一组 120 个固定用例,包含通用能力、数学、推理、语言、知识、逻辑和 512—8192 token 的上下文定位。基线和 V2 均使用贪心解码与 4-bit NF4:
| 指标 | 原版 Qwen3.5-4B | Natural Memory v2 |
|---|---:|---:|
| 总分 | 0.85833 | 0.85833 |
| 总分差值 | - | 0 |
| 各分类差值 | - | 全部 0 |
| 自动写入 precision | - | 100% |
| 自动写入 recall | - | 100% |
| 自动写入 specificity | - | 100% |
| 无历史重启恢复 | - | 通过 |
| 清理后停止召回 | - | 通过 |
这说明在当前测试集合上,接入 V2 没有造成可测的通用能力退化;它不等于在所有任务、所有长度和所有语言上都没有退化。
### 5.6 真实重启实验
实验先给模型一条普通自然语言事实:
> 我正在开发一个长期项目,项目内部代号是 NM-V2-RESTART,使用中文。
没有使用 `/remember`。自动写入成功后,系统把状态保存进 memory safetensors shard,释放第一个模型,再加载第二个模型。第二个模型只收到新问题,没有聊天记录。结果如下:
- router 找到 `page_00000001` 和目标记录;
- 内部证据前缀长度为 36 token;
- 生成结果为 `NM-V2-RESTART`;
- 记录在报告中显示为 `evidence_found`;
- 测试结束后清理操作将页面数和记录数恢复为 0。
在未知事实边界测试中,写入“我的长期项目代号是 ZX-77”后询问“我的血型是什么”,阈值校准前会出现低分无关召回;阈值设为 0.65 后,路由结果为 `below_read_threshold`,内部前缀长度为 0。这个修复体现了一个重要原则:回答碰巧说“不知道”不能代替读取器本身拒绝无关证据。
## 6. 长上下文与容量边界
直接 KV 压力测试在当前机器上约 8192 token 可以运行,16384 和 32768 token 会 OOM。这个结果与 V2 的作用并不矛盾:V2 的目标是把长期信息移出热 KV,而不是自动让原始长文本注意力变成低成本。
当前还不能声称支持 200M—300M 原始 token 上下文。百万级轻量记录的 durable page store 已经实现;同时,Qwen 生成路径已经接入 CPU-backed `DynamicCache(offloading=True)`,并加入了模型内的旧前缀分块归档和热窗口裁剪。真实自动路径把 371 token 压缩为 32 token,写入 22 条上下文记录后完成生成。要达到原始长上下文目标,仍然需要:
1. GPU 热页、RAM 温页、磁盘冷页之间更细粒度的统一 page manager,以及面向 NVMe 的分页调度;
2. 原文页与摘要页的可逆压缩;
3. 更高吞吐的 CPU/NVMe KV offload 与分页注意力;
4. 128K 热窗口到百万级历史的课程训练;
5. 大规模多跳、冲突、污染和纠错数据;
6. 召回失败时的保守拒答和校准评测。
V2 已经把地址空间、页路由、版本状态机、持久化接口和 CPU KV offload 接在一起;当前证据仍然是轻量记录压力测试和短自动压缩验证,不是百万 token 原始上下文的端到端质量证明。
## 7. 讨论
### 7.1 与外部 RAG 的差异
V2 与普通 RAG 的主要区别不在于“是否存在向量”,而在于记忆生命周期由模型运行时直接控制。路由器学习问题是否需要记忆,写入策略决定什么值得保留,记录状态机维护冲突和撤回,证据前缀由模型内部读取路径生成。本次交付的默认实现不启用磁盘分页:完整 V2 记录随第三个 safetensors memory shard 载入进程内存,只有有限的热点地址和 token payload 进入 VRAM cache。未来更大规模部署可以增加冷页后端,但那是容量扩展,不是当前正确性路径。
### 7.2 与扩大 KV 的差异
扩大 KV 对最近历史的细节保持最好,但长期存储成本高,而且每个查询都容易被无关上下文拖慢。Memory Slot 主动丢弃顺序细节,只保存事实和结构化证据,因此更适合个人偏好、项目决策、联系人属性和长期计划。两者应该组合使用,而不是互相替代。
### 7.3 为什么训练比扩大张量更难
增加 slot 数量只改变了容量,不会教会模型如何寻址。真正困难的是建立稳定的写入地址、区分相似事件、关联多个记录、修正旧版本,以及在没有答案时停下来。当前 Qwen 路由器的 hop accuracy 已经显示,候选选择和多跳控制是两个不同的学习问题,不能用单一的相似度损失解决。
## 8. 可复现性
项目目录为 `W:\Flash\model\dynamic_memory_lab`。核心命令:
```powershell
Set-Location W:\Flash\model
# 单元测试
& C:\Users\Administrator\miniconda3\envs\LLM\python.exe `
-m unittest discover -s dynamic_memory_lab\tests -v
# V2 存储与路由评测
& C:\Users\Administrator\miniconda3\envs\LLM\python.exe `
-m dynamic_memory_lab.benchmark_memory_v2
# Qwen3.5-4B 综合回归
& C:\Users\Administrator\miniconda3\envs\LLM\python.exe `
-m dynamic_memory_lab.benchmark_natural_memory_v1 `
--base-model W:\Flash\model `
--memory-model W:\Flash\model\dynamic_memory_lab\qwen3_5_4b_natural_memory_v2 `
--output W:\Flash\model\dynamic_memory_lab\natural_memory_v2_full_benchmark.json
# 真实重启测试
& C:\Users\Administrator\miniconda3\envs\LLM\python.exe `
-m dynamic_memory_lab.test_natural_memory_v2_restart
# KV offload 与自动长上下文压缩
& C:\Users\Administrator\miniconda3\envs\LLM\python.exe `
-m dynamic_memory_lab.benchmark_kv_offload
```
关键结果文件:
- `natural_memory_v2_benchmark.json`:分页、路由、完整性和恢复;
- `natural_memory_v2_full_benchmark.json`:Qwen 基线回归;
- `natural_memory_v2_restart_test.json`:无历史重启;
- `qwen_router_v2_training.json`:Qwen 专用路由器训练与 held-out 指标。
## 9. 局限与未来工作
本文的实现仍然是研究原型,距离可公开部署还有几项关键工作:
1. 用脱敏真实对话替代小规模合成事实,并按用户、项目和时间做严格数据隔离;
2. 训练多跳控制器和不确定性校准,而不是只优化 top-1 路由;
3. 引入事实来源签名、用户确认策略和可撤销日志;
4. 将页对象替换为压缩列式存储,降低百万记录的 Python 对象开销;
5. 完成 GPU/RAM/NVMe 三级冷热迁移和 NVMe page cache;
6. 实现摘要页与原文页之间的按需恢复;
7. 建立跨会话、跨语言、长时间连续运行的污染测试;
8. 在 128K 热 KV 和百万级历史上进行端到端吞吐、延迟、质量和故障恢复评测。
Natural Memory v2 最重要的成果不是一个更大的 slot 张量,而是把“记忆是什么、如何寻址、何时读取、怎样纠错、何时拒绝”放进了一个可测试的模型架构中。后续版本的主要任务,是让这个架构在更大规模和更真实的分布上保持同样的克制与可解释性。