- 引入 MemoryRouterXL 与 v5/v6 流式多线程训练/编码管线 - 修复 prepare_memory_router_dataset 候选池重建缺陷(mega 家族 3568x 加速,输出逐字节相同) - 修复 v5 被破坏的拒答与多跳标签(train 未知样本 319 -> 16319,multi_hop 平均正例 1.00 -> 2.00) - 同存储预算下 V2-128 v6 逐轴 22/22 通过:Top-1 41.12% -> 94.62%,未知拒答 0.00% -> 100.00% - 记录三条被实测推翻的显然优化(logits_to_keep=1 反而慢 55%、XL 容量未带来收益) - 记忆手术跨架构可移植性 14/14,读写关闭时与原生模型逐位相同
14 KiB
Natural Memory v2
对外技术说明
版本:v2
本文只描述当前实现已经完成并实际测量的内容。它不把系统描述成通用智能,也不把实验室结果表述成线上服务承诺。
1. 一句话说明
Natural Memory v2 是接在本地 Qwen3.5-4B 上的一个模型内记忆层:它把适合长期复用的个人事实、项目事实和短对话片段写入有地址的记忆记录,当前问题只读取少量相关记录,再把这些记录作为模型内部前缀交给 Qwen 生成答案。
它要解决的具体问题是:模型重启后不携带历史聊天记录,仍能访问已经保存的个人或项目事实,同时不把全部历史转换成 GPU 上的长 KV Cache。
2. 当前实现
2.1 记忆与 KV 的分工
最近对话 Qwen 热 KV
长期个人事实/项目事实 Natural Memory 记录
当前问题 有界路由与 Top-K 读取
原始持久化状态 嵌入式 memory safetensors 切片
Memory Slot 不试图逐 token 模拟完整 KV。它保存的是更适合跨会话复用的内容:事实、版本、来源、短文本证据和语义地址。当前对话的顺序关系仍由 Qwen 的普通上下文负责。
2.2 读取路径
用户问题
-> Qwen hidden state 生成紧凑查询地址
-> LSH/地址粗索引
-> 候选页
-> 页内记录重排
-> Top-K 记录
-> 证据前缀注入 Qwen
-> 普通生成
当前 token 不会与全部记忆记录做全量注意力。当前默认读取上限为少量页面和记录;实际运行中只把命中的短证据提升到 GPU,记忆主体保留在进程内存。
2.3 写入与版本
每条记录包含:
- 原始短文本和可选 token 序列;
- 语义地址、实体、属性和值;
- 时间、来源、置信度、重要性;
- active、superseded、retracted、quarantined 状态;
- 版本关系和审计信息。
同一实体和属性出现新值时,旧值会被标记为 superseded。低置信度内容可以进入 quarantine,不参与正常读取。撤回记录不会从审计中消失,而是变成 retracted。
2.4 重启与存储
当前交付配置采用 embedded weight-shard:记忆快照、路由器参数、页面元数据和短文本证据写入模型包的 memory safetensors 切片。启动时加载到进程内存,命中的热点记录才进入有界 GPU cache。
当前默认路径不使用 SQLite,也不使用磁盘分页。该设计减少了运行时依赖,但意味着模型包会随持久化记忆增长而变大,且需要重新保存权重切片才能固化更新。
3. 正式脏数据迁移测试
3.1 数据来源
本次正式测试使用了两类来源:
- 当前 Natural Memory 工程自身的真实源码、文档和少量随包配置:65 个文件、1,110,524 字节、620 个源码/文档分片。
- 用户在本项目对话中明确说过的短事实和工程要求:15 条记录,包含工作目录变更、模型命名、对照模型、存储限制、显存限制、训练取向和模型内读取要求。
本轮由这些记录派生出的用户对话题共 44 题,其中 38 个可回答、6 个未知;其余 220 题来自真实源码和文档。
为了避免答案泄漏,正式数据排除了:
- 以前的 benchmark JSON 结果;
- synthetic hardset 和其他合成数据集;
- checkpoint 和模型权重;
- tokenizer 大文件。
用户对话部分不是从外部用户数据库导出的日志。它是本次项目对话里用户已经明确写出的要求;其测试问题由人工改写成口语、跨会话、时间冲突和未知问题。不能把这部分描述成大规模真人日志验证。
3.2 测试协议
- 模型:本地 Qwen3.5-4B 原版与 Natural Memory v2;
- 量化:4-bit NF4;
- 解码:greedy;
- 最大新生成:64 token;
- GPU 进程上限:10 GiB;
- Natural Memory 读取:最多 2 条记录;
- 语义地址编码:单条 batch,避免 12 GiB 显卡在源码证据编码阶段产生瞬时峰值;
- 题目总数:264;
- 可回答题:246;
- 未知/拒答题:18。
题目类型不是单纯的随机字符串记忆,包括:
- 真实函数和类的源码定位;
- 面向工程使用的架构解释;
- 用户事实的自然改写;
- 早期目录到当前目录的时间冲突;
- 写入安全、版本替换和显存约束;
- 目标不存在时的拒答。
3.3 总体结果
| 系统 | 可回答正确率 | 未知拒答正确率 | 总体正确率 |
|---|---|---|---|
| 原版 Qwen3.5-4B,无记忆 | 3/246 = 1.22% | 17/18 = 94.44% | 20/264 = 7.58% |
| Natural Memory v2 | 154/246 = 62.60% | 16/18 = 88.89% | 170/264 = 64.39% |
Natural Memory 把真实工程与用户事实带来的可回答率从 1.22% 提升到 62.60%。这证明记忆路径能够迁移到非构造的短事实和真实代码内容,但距离稳定的生产级自然语言记忆仍有明显差距。
3.4 按数据域拆分
| 数据域 | 系统 | 可回答结果 | 未知拒答 |
|---|---|---|---|
| 用户对话事实 | 原版 Qwen | 1/38 = 2.63% | 6/6 = 100.00% |
| 用户对话事实 | Natural Memory v2 | 21/38 = 55.26% | 6/6 = 100.00% |
| 真实源码/文档 | 原版 Qwen | 2/208 = 0.96% | 11/12 = 91.67% |
| 真实源码/文档 | Natural Memory v2 | 133/208 = 63.94% | 10/12 = 83.33% |
源码定位是当前表现最好的真实任务:
- 用户对话事实:21/38 = 55.26%;
- 符号定位:129/192 = 67.19%;
- 时间冲突目录查询:2/2;
- 写入安全解释:2/2;
- 基线局限说明:2/2;
- 用户自然改写:4/5;
- 用户约束类问题:1/4;
- 开放式架构解释类问题:当前严格锚点评估中仍不稳定。
3.5 路由与生成的差距
Natural Memory 在 246 个可回答问题上的目标记忆召回为 166/246 = 67.48%,最终回答正确为 154/246 = 62.60%。这说明当前主要问题已经不只是“有没有记忆”,而是两段链路都需要改进:
- 路由器在口语化问题、短问题和没有显式文件名的问题上会召回相邻但错误的记录;
- 即使证据已进入前缀,Qwen 仍可能拒答、过度解释或没有按要求输出关键事实。
因此,当前结果不能写成“检索准确率等于回答准确率”,两者必须分开报告。
4. 显存、速度和记忆容量
以下数字来自同一次正式脏数据测试。显存字段是每次请求结束后的 allocated/reserved 快照,不是 torch.cuda.max_memory_allocated() 记录的严格峰值;reserved 还包含 PyTorch 分配器保留的缓存。
| 指标 | 原版 Qwen3.5-4B | Natural Memory v2 | 变化 |
|---|---|---|---|
| 平均总延迟 | 2650.4 ms | 2718.9 ms | +2.58% |
| 平均解码速度 | 24.06 tok/s | 21.68 tok/s | -9.90% |
| 平均输入 token | 30.8 | 641.4 | 记忆证据前缀增加 |
| 读取额外耗时 | 无 | 61.1 ms | 新增路径 |
| allocated 快照峰值 | 3.084 GiB | 3.134 GiB | +0.050 GiB |
| reserved 快照峰值 | 3.234 GiB | 5.021 GiB | +1.787 GiB |
本次记忆状态统计:
- active records:723;
- pages:23;
- 页面容量:32 records/page;
- 设计容量:1,048,576 records;
- GPU cache 上限:256 records、131,072 token;
- 实际 GPU cache token:15,885;
- GPU cache fallback:0;
- GPU cache allocation failure:0;
- cold page:0,原因是本次使用 embedded/process-RAM 模式。
这里的“一百万记录容量”是地址空间和分页结构的容量,不是本次已经装入了一百万条语义记忆,也不是一百万条记录已经通过端到端测试。
5. 之前的同协议工程基准
下面是先前在当前工程项目库上的 Stage 5 对照,用于说明系统在结构化项目事实上的上限。它与本次脏数据迁移集不是同一题集,不能合并成一个总分。
通用个人事实
| 系统 | 可回答 | 未知拒答 | 平均延迟 | 解码速度 |
|---|---|---|---|---|
| 原版 Qwen3.5-4B | 4/107 = 3.74% | 21/21 = 100% | 1233.2 ms | 23.51 tok/s |
| 强 RAG 基线 | 106/107 = 99.07% | 20/21 = 95.24% | 885.8 ms | 21.67 tok/s |
| Natural Memory v2 | 107/107 = 100% | 21/21 = 100% | 994.3 ms | 21.70 tok/s |
项目库
| 系统 | 正确率 | 平均延迟 | 解码速度 |
|---|---|---|---|
| 原版 Qwen3.5-4B | 45/64 = 70.31% | 1351.5 ms | 23.70 tok/s |
| 强 RAG 基线 | 64/64 = 100% | 1395.3 ms | 22.94 tok/s |
| Natural Memory v2 | 64/64 = 100% | 1463.2 ms | 21.85 tok/s |
该强 RAG 使用本地 CPU bert-base-chinese 向量、稀疏特征和固定规则重排。它不是训练好的公开 cross-encoder,因此可以作为更强的本地基线,但不能代表所有生产 RAG 服务。
6. 已经解决的问题
当前实现已经能够在本地 12 GiB GPU 上完成以下闭环:
- 普通自然语言触发自动记忆读取,不要求用户输入
/remember; - 模型重启后不回放历史聊天,只加载已保存的 memory shard;
- 旧值和新值保留版本关系,旧值不会继续作为 active 事实参与正常读取;
- 记忆读取器、地址索引和证据注入位于模型适配架构内部;
- 记忆主体留在进程内存,热点记录使用有界 GPU cache;
- 当前问题只读取 Top-K 记录,不对全量 slot 做注意力;
- 低置信度写入、撤回和审计状态有独立表示;
- 在真实工程源码定位任务上,相比无记忆 Qwen 有明显的可回答性提升。
7. 当前不能宣称的内容
以下说法目前没有足够证据支持:
- “Natural Memory 已经等价于百万 token 的完整 KV”;
- “Natural Memory 已经击败生产级 embedding + reranker RAG”;
- “任何自然语言表达都能稳定召回正确记忆”;
- “记忆写入永远不会出错”;
- “一百万条记录已经完成端到端验证”;
- “当前 4B 结果可以直接外推到 14B、32B 或更大模型”;
- “reserved VRAM 就是实际模型峰值显存”;
- “本次用户事实测试代表大规模真实用户群体”。
8. 主要局限
8.1 训练数据仍不够自然
当前路由器的主体训练仍来自本地构造的实体—属性—值事实和 hard negatives。正式脏数据集虽然使用了真实工程内容和真实项目对话片段,但自然改写仍是人工编写的测试变体,不是大规模脱敏真人会话。
8.2 真实仓库的语义索引覆盖有限
本次运行把全部 620 个真实源码/文档分片放入记忆库,但为控制 GPU 压力,只有 96 个符号目标和 8 个操作性事实建立了 Qwen 语义地址,其余分片作为真实背景记录保留。这使测试更安全、更可复现,但不能等同于“整个仓库都被高质量语义索引”。
8.3 开放式解释弱于明确定位
对于“某个函数在哪个文件”这类有明确地址的任务,表现明显好于“结合多个文件解释系统为什么这样设计”。后者需要多跳证据合并、冲突处理和生成控制,当前仍会出现证据已召回但最终回答不完整的情况。
8.4 速度仍有真实代价
正式脏数据测试中,Natural Memory 平均延迟高约 2.58%,解码速度低约 9.90%,并增加了平均输入前缀长度。这个代价来自 Qwen 查询编码、稀疏路由、证据前缀和热点缓存,而不是免费获得的能力。
8.5 生产级基线还不完整
本次正式脏库对照聚焦原版 Qwen3.5-4B 无记忆基线。要作出服务经济学结论,还需要在同一脏数据、同一题集上加入强 embedding 检索器、cross-encoder 或训练好的 reranker、滑动窗口和分页 KV 等基线。
9. 下一阶段的工程任务
按对正确率最有帮助的顺序:
- 使用有用户同意的脱敏对话,增加自然省略、指代、错别字、时间间隔、互相矛盾的旧说法和多轮项目协作样本;
- 重新训练路由器,重点覆盖“同一事实的多种问法”和“相似但错误的记录”;
- 对“检索正确但回答错误”的样本单独训练证据使用与拒答策略;
- 将真实仓库的语义地址覆盖从目标记录扩展到完整索引,仍保持单条/小批次编码以保护显存;
- 加入多跳证据合并和当前版本优先规则;
- 将写入、冲突解决和摘要从生成热路径移到回合边界或后台线程;
- 把显存测试改为记录真正的 CUDA high-water mark,并分别报告 live allocated、reserved 和 cache payload;
- 在同一协议下补齐强 RAG、滑动窗口和分页 KV 的成本—质量曲线。
10. 复现实验
在 H:\Memory 下运行:
& C:\Users\Administrator\miniconda3\envs\LLM\python.exe `
-m V2_dpskw.benchmark_dirty_real_corpus_4b `
--project-records 8192 `
--project-targets 96 `
--max-new-tokens 64 `
--encode-batch-size 1 `
--skip-chunk-rag `
--output H:\Memory\V2_dpskw\dirty_real_corpus_compare_4b.json
对应的原始结果文件为:
H:\Memory\V2_dpskw\dirty_real_corpus_compare_4b.json
评测脚本为:
H:\Memory\V2_dpskw\benchmark_dirty_real_corpus_4b.py
11. 结论
Natural Memory v2 当前已经不是只有构造数据上的演示:在真实工程源码、文档和本项目用户要求组成的脏数据迁移测试中,它显著提高了窗口外事实的可回答性,并在 10 GiB GPU 进程上完成了 723 条 active records 的读取运行。
同时,62.60% 的可回答正确率、88.89% 的未知拒答正确率和约 10% 的解码速度下降说明它仍处于研究原型到工程验证之间。当前最值得继续投入的不是增加宣传口径,而是提高自然语言路由泛化、证据到回答的闭环稳定性,并在同一题集上完成强 RAG 和 KV 基线的公平对照。