Files
natural-memory-site/division.html
T

285 lines
16 KiB
HTML
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.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>记忆与 KV 的分工 — Natural Memory v2</title>
<meta name="description" content="为什么不是简单加长上下文:哪些东西该留在 Qwen 的热 KV 里,哪些该写入带地址的记忆记录,各自的边界在哪里。">
<meta name="color-scheme" content="dark">
<meta name="theme-color" content="#0a0a0a">
<!-- 动效的初始隐藏态只在 JS 可用时生效;脚本被禁用时内容照常可见 -->
<script>document.documentElement.classList.add("js");</script>
<meta property="og:type" content="website">
<meta property="og:title" content="记忆与 KV 的分工 — Natural Memory v2">
<meta property="og:description" content="为什么不是简单加长上下文:哪些东西该留在 Qwen 的热 KV 里,哪些该写入带地址的记忆记录,各自的边界在哪里。">
<meta name="twitter:card" content="summary_large_image">
<link rel="icon" href="assets/favicon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="assets/favicon.svg">
<link rel="preload" href="assets/fonts/archivo-latin-wdth-normal.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="assets/fonts/geist-mono-latin-wght-normal.woff2" as="font" type="font/woff2" crossorigin>
<!-- 资源带构建指纹:内容一变 URL 就变,浏览器不可能再用到旧 JS/CSS -->
<link rel="stylesheet" href="assets/css/site.css?v=a9c21ef3a8">
</head>
<body data-page="division" data-layout="docs">
<a class="skip" href="#doc">跳到正文</a>
<header class="site" id="site">
<div class="topbar">
<a class="brand" href="./" aria-label="Natural Memory v2 发布页">
<svg class="brand__mark" viewBox="0 0 32 32" aria-hidden="true">
<rect class="dim" x="2" y="2" width="7" height="7" rx="1.5"/>
<rect class="dim" x="12" y="2" width="7" height="7" rx="1.5"/>
<rect class="dim" x="22" y="2" width="7" height="7" rx="1.5"/>
<rect class="dim" x="2" y="12" width="7" height="7" rx="1.5"/>
<rect class="on" x="12" y="12" width="7" height="7" rx="1.5"/>
<rect class="dim" x="22" y="12" width="7" height="7" rx="1.5"/>
<rect class="dim" x="2" y="22" width="7" height="7" rx="1.5"/>
<rect class="dim" x="12" y="22" width="7" height="7" rx="1.5"/>
<rect class="on" x="22" y="22" width="7" height="7" rx="1.5"/>
</svg>
<span class="brand__name">Natural Memory</span>
<span class="pill pill--acc">v2</span>
</a>
<span class="crumb">
<span class="crumb__n">01</span>
<span class="crumb__t">记忆与 KV 的分工</span>
</span>
<span class="topbar__spacer"></span>
<nav class="topnav" aria-label="快速导航">
<a class="topnav__a" href="./">发布页</a> <a class="topnav__a" href="./mechanism">机制</a> <a class="topnav__a" href="./results">测量</a> <a class="topnav__a" href="./nm21">NM2.1</a> <a class="topnav__a" href="./ledger">台账</a> <a class="topnav__a" href="./limits">边界</a> <a class="topnav__a" href="./reproduce">复现</a>
</nav>
<button class="palbtn" id="palBtn" type="button" aria-label="检索全站内容(快捷键 /)">
<span class="palbtn__t">检索</span><span class="kbd">/</span>
</button>
<span class="pill" id="serverChip" title="本站服务端运行时读数">
<i class="dot"></i><span id="serverChipText">读取中</span>
</span>
</div>
<div class="progress" id="progress"></div>
</header>
<div class="shell">
<aside class="side">
<nav class="side__in" aria-label="章节导航">
<a class="side__back" href="./">← 返回发布页</a>
<p class="side__grp">原理</p>
<ul class="side__list">
<li><a class="side__a is-on" href="./division" aria-current="page"><span class="side__n">01</span><span class="side__t">记忆与 KV 的分工</span></a></li>
<li><a class="side__a" href="./mechanism"><span class="side__n">02</span><span class="side__t">一次读取与一次写入</span></a></li>
</ul>
<p class="side__grp">证据</p>
<ul class="side__list">
<li><a class="side__a" href="./results"><span class="side__n">03</span><span class="side__t">测量结果</span></a></li>
<li><a class="side__a" href="./nm21"><span class="side__n">04</span><span class="side__t">NM2.1 · 之后做了什么</span></a></li>
<li><a class="side__a" href="./examples"><span class="side__n">05</span><span class="side__t">实测样例</span></a></li>
<li><a class="side__a" href="./ledger"><span class="side__n">06</span><span class="side__t">真实评测台账</span></a></li>
</ul>
<p class="side__grp">工程</p>
<ul class="side__list">
<li><a class="side__a" href="./cost"><span class="side__n">07</span><span class="side__t">代价账本</span></a></li>
<li><a class="side__a" href="./capacity"><span class="side__n">08</span><span class="side__t">容量与存储</span></a></li>
<li><a class="side__a" href="./limits"><span class="side__n">09</span><span class="side__t">我们不宣称的内容</span></a></li>
<li><a class="side__a" href="./roadmap"><span class="side__n">10</span><span class="side__t">已解决的与下一步</span></a></li>
<li><a class="side__a" href="./reproduce"><span class="side__n">11</span><span class="side__t">复现实验</span></a></li>
</ul>
</nav>
</aside>
<main class="doc" id="doc">
<header class="doc__hd">
<span class="kicker">01 / DIVISION OF LABOUR</span>
<h1 class="doc__h">记忆与 KV 的分工</h1>
<p class="doc__lede">为什么不是简单加长上下文:哪些东西该留在 Qwen 的热 KV 里,哪些该写入带地址的记忆记录,各自的边界在哪里。</p>
<p class="doc__figure">
<span class="mega">441.19<small>tok</small></span>
<span class="doc__figure-n">批次 B 平均输入前缀 token</span>
</p>
</header>
<p class="lede2">
这一节回答一个问题:<strong>既然模型已经有上下文窗口,为什么还要单独做一层记忆?</strong>
答案不是「窗口不够长」,而是<strong>把长期事实塞进上下文,会以线性成本换来极低的复用率</strong>。
下面把「哪些东西留在 Qwen 的热 KV 里、哪些写进记忆记录」这条分界线逐层讲清楚。
</p>
<h2 class="h3" >先看没有这层记忆时会发生什么</h2>
<p class="small" style="max-width:78ch">
同一套题、同一协议下,原版 Qwen3.5-4B 在 246 道<strong>可回答</strong>题上只答对 3 道(1.22%)。
它的典型回答不是答错,而是明确表示拿不到信息:
</p>
<div class="quote" >
<q>作为一个人工智能模型,我无法访问您的个人历史对话记录、系统配置或您之前设定的具体规则……每次对话对我来说都是全新的开始。</q>
<cite>原版 Qwen3.5-4B · 评测样本 user-009 原始回答</cite>
</div>
<p class="small" style="max-width:78ch">
这句话在事实上完全正确——模型确实没有这些信息。问题出在:这些信息<strong>本来就应该被保存下来</strong>,
而它们不属于「当前这轮对话」,所以每轮都重新粘一遍历史是最笨的保存方式。
</p>
<h2 class="h3" >四层分工:谁存什么、为什么</h2>
<p class="small" style="max-width:78ch">
这是整份设计里最核心的一张表。判断标准只有一条:<strong>这份信息是「这一轮才有意义」还是「跨轮次可复用」</strong>。
</p>
<div class="scrollx">
<div class="gt gt--4">
<div class="gt__h"><span>层级</span><span>存放什么</span><span>由谁负责</span><span>为什么放在这一层</span></div>
<div class="gt__r">
<span class="gt__k">最近对话</span>
<span class="gt__v">这一轮前后的原话与顺序</span>
<span class="gt__who">Qwen 热 KV</span>
<span class="gt__why">指代、省略、语气、"你刚才说的那句"都依赖严格的先后顺序。这类信息复用价值低、时效性强,放 KV 最自然。</span>
</div>
<div class="gt__r">
<span class="gt__k">长期个人 / 项目事实</span>
<span class="gt__v">事实、版本、来源、置信度、短文本证据</span>
<span class="gt__who gt__who--acc">Natural Memory 记录</span>
<span class="gt__why">跨会话反复被问到,且需要保留"哪个版本才是当前有效"的关系。它们不依赖顺序,只依赖地址与内容。</span>
</div>
<div class="gt__r">
<span class="gt__k">当前问题</span>
<span class="gt__v">由问题生成的有界读取</span>
<span class="gt__who gt__who--acc">路由 + Top-K</span>
<span class="gt__why">不是所有记忆都该被读。当前问题只与少量页面和记录交互,避免"记忆越多、噪声越大"。</span>
</div>
<div class="gt__r">
<span class="gt__k">原始持久化状态</span>
<span class="gt__v">记忆快照与索引</span>
<span class="gt__who gt__who--acc">嵌入式 memory safetensors</span>
<span class="gt__why">随模型包一起加载,运行时不需要额外数据库进程,也避免了磁盘分页带来的延迟抖动。</span>
</div>
</div>
</div>
<div class="callout" >
<p class="callout__t">关键判断</p>
<p class="callout__b">
Memory Slot <strong>不试图逐 token 模拟完整 KV</strong>。它接管的是 KV 里最昂贵、最适合长期保存、
也最容易重复利用的那一部分;而当前对话的顺序关系,仍然由 Qwen 的原生上下文负责。
</p>
</div>
<h2 class="h3" >分工落到数字上是什么样</h2>
<p class="small" style="max-width:78ch">
下面这组对照最能说明「不是把历史灌进去,而是把命中的少量证据灌进去」。两组数字分别来自批次 A 与批次 B(同一题集、同一协议)。
</p>
<div class="statrow">
<div class="stat">
<span class="stat__k">无记忆时的平均输入</span>
<span class="stat__v">30.75<small>token</small></span>
<span class="stat__d">批次 A 基线:只有问题本身,没有历史</span>
</div>
<div class="stat stat--acc">
<span class="stat__k">有记忆时的平均输入</span>
<span class="stat__v">441.19<small>token</small></span>
<span class="stat__d">批次 B:命中的证据前缀(批次 A 为 641.42)</span>
</div>
<div class="stat">
<span class="stat__k">前缀命中率</span>
<span class="stat__v">96.97<small>%</small></span>
<span class="stat__d">批次 B 实际注入证据的题目占比(批次 A 为 90.91%)</span>
</div>
<div class="stat">
<span class="stat__k">GPU cache 实际用量</span>
<span class="stat__v">17,990<small>token</small></span>
<span class="stat__d">有界上限 131,072 token,用到约 13.7%</span>
</div>
</div>
<p class="small" style="max-width:78ch">
注意最后一项:<strong>上限是 131,072 token,实际只用了 17,990</strong>。
这说明读取路径被"有界"约束住了——不会因为记忆库变大就把显存吃满。
</p>
<h2 class="h3" >这条分工线换来了什么、付出了什么</h2>
<div class="grid g2" >
<div class="card">
<p class="eyebrow" >换来的</p>
<div class="mini">
<div><span>可回答正确率</span><b>1.22% → 82.52%</b></div>
<div><span>目标记忆召回</span><b>0% → 92.68%</b></div>
<div><span>符号定位(192 题)</span><b>0/192 → 181/192</b></div>
<div><span>跨会话问题</span><b>1/6 → 5/6</b></div>
</div>
</div>
<div class="card card--warn">
<p class="eyebrow" style="color:var(--warn)">付出的</p>
<div class="mini">
<div><span>平均输入前缀</span><b>30.75 → 441.19 token</b></div>
<div><span>平均总延迟(批次 B)</span><b>2854.9 → 2878.3 ms</b></div>
<div><span>平均解码速度(批次 B)</span><b>22.34 → 20.68 tok/s</b></div>
<div><span>reserved 显存峰值</span><b>3.234 → 5.180 GiB</b></div>
</div>
</div>
</div>
<h2 class="h3" >这条线不能推到哪里</h2>
<div class="claims claims--loose" >
<div class="claim"><span class="claim__x">✕</span><span class="claim__t">Natural Memory 已经等价于百万 token 的完整 KV</span><span class="claim__s">UNSUPPORTED</span></div>
<div class="claim"><span class="claim__x">✕</span><span class="claim__t">长上下文限制已被解除(实测 8K 可跑,16K / 32K OOM)</span><span class="claim__s">UNSUPPORTED</span></div>
<div class="claim"><span class="claim__x">✕</span><span class="claim__t">设计容量 1,048,576 条记录等于已经装入并验证了这么多</span><span class="claim__s">UNSUPPORTED</span></div>
</div>
<p class="small" style="max-width:78ch">
第三条尤其要注意:<strong>1,048,576 是地址空间与分页结构的容量</strong>,
本次两个批次实际装载的是 723 / 738 条 active records,分别是 23 / 24 个页面。
容量上限与已装入量是两个概念,我们不在页面上把它们混为一谈。
</p>
<nav class="pn" aria-label="章节切换"><a class="pn__a pn__a--prev" href="./" data-dir="prev"><span class="pn__k">上一节 · 00</span><span class="pn__t">总览</span><span class="kbd">&larr;</span></a><a class="pn__a pn__a--next" href="./mechanism" data-dir="next"><span class="pn__k">下一节 · 02</span><span class="pn__t">一次读取与一次写入</span><span class="kbd">&rarr;</span></a></nav>
</main>
</div>
<footer class="footer">
<div class="wrap footer__in">
<div class="footer__col">
<p class="footer__h">作者</p>
<div class="author">
<a class="author__a" href="https://wpyw.site" target="_blank" rel="noopener">
<span class="author__k">个人网站</span><span class="author__v">wpyw.site</span>
</a>
<a class="author__a" href="mailto:[email protected]">
<span class="author__k">邮箱</span><span class="author__v">[email protected]</span>
</a>
</div>
</div>
<div class="footer__col footer__col--wide">
<p class="footer__h">来源</p>
<div class="readout" id="footFiles"></div>
<p class="footer__h" style="margin-top:20px">服务端读数</p>
<div class="readout mono" id="footServer"><span>读取中…</span></div>
</div>
<div class="footer__col footer__col--wide">
<p class="footer__h">说明</p>
<p class="footer__note" id="disclaimer"></p>
<p class="footer__meta">构建于 2026-09-16 20:39 · 所有数字取自工程内的正式报告,未做外推或估算。</p>
</div>
</div>
</footer>
<!-- 全站检索:客户端索引,无后端、无网络请求 -->
<div class="pal" id="pal" hidden>
<div class="pal__mask" id="palMask"></div>
<div class="pal__box" role="dialog" aria-modal="true" aria-label="检索全站内容">
<div class="pal__hd">
<span class="pal__ico" aria-hidden="true"></span>
<input class="pal__in" id="palInput" type="text" role="combobox" aria-expanded="true"
aria-controls="palList" autocomplete="off" spellcheck="false"
placeholder="检索全站内容:章节、数字、术语…">
<span class="kbd">Esc</span>
</div>
<div class="pal__list" id="palList" role="listbox" aria-label="检索结果"></div>
<div class="pal__ft">
<span><span class="kbd">↑</span><span class="kbd">↓</span> 选择</span>
<span><span class="kbd">↵</span> 打开</span>
<span class="pal__n mono" id="palN"></span>
</div>
</div>
</div>
<script src="assets/js/data.js?v=a9c21ef3a8"></script>
<script src="assets/js/examples.js?v=a9c21ef3a8"></script>
<script src="assets/js/restart.js?v=a9c21ef3a8"></script>
<script src="assets/js/nm21.js?v=a9c21ef3a8"></script>
<script src="assets/js/ledger.js?v=a9c21ef3a8"></script>
<script src="assets/js/search.js?v=a9c21ef3a8"></script>
<script src="assets/js/space.js?v=a9c21ef3a8"></script>
<script src="assets/js/site.js?v=a9c21ef3a8"></script>
</body>
</html>