# KV 缓存最小实验：先把状态复用做出来

这是补充教材的可运行伴随实验，版本 1.0，整理于 2026-10-09。
**它不是原附录 A 中 Qwen3-0.6B 实验的复现，也不是训练好的语言模型。**

## 跑什么

`kv_lab.py` 从固定随机种子构建三层因果 Transformer：4 个 Q 头、2 个 KV 头、每头 8 维、RoPE、RMSNorm、前馈层和词表输出。词表为 41 个整数 ID，无分词器、外部数据集、模型下载或付费 API。

它包含完整前缀缓存（16 token 一块、链式 SHA-256、权重和命名空间身份、私有复制）、在线 softmax、实际打包的 INT4，以及独立的共享页／写时复制模拟器。

## 运行

需要 Python 3.10 及以上。本次验证环境是 Python 3.13.5、NumPy 2.3.5、CPU。
已有 NumPy 时可直接运行；需要安装时由你执行：

```bash
python -m pip install numpy==2.3.5
python -m unittest -v
python kv_lab.py --output my_results.json
```

在 macOS / Linux 上可用 `OPENBLAS_NUM_THREADS=1 python kv_lab.py --output my_results.json` 固定 BLAS 线程数。本次记录使用该设置。测试不要求每一种硬件都与所附 JSON 逐位相同，而是检查 FP64 / FP32 对应的数值容差。NumPy 2.3.5 的 Python 支持范围以安装环境为准；Python 3.10 用户可使用支持该版本的 NumPy，实际结果应记录版本。

## 先预测，再看结果

1. 两个输入共享前 42 个 token，缓存以 16 token 为单位，只保存整块。第二个输入共 47 token。命中 32，重算 15；不是共享的 42 都能复用。
2. “不查表，只把输入分两段计算”是必要对照：它能分离分段执行带来的数值差异与缓存管理错误。
3. 把文档的旧 K/V 接到长度相同、内容不同的前文后，位置不变仍然可能错。重放文档是精确修复对照；本实验**没有实现 CacheBlend**。
4. `PagePool` 中先让两个使用者共享一页，再结束其中一个；另一人没结束之前，不能覆盖。写共享尾页之前先复制。
5. INT4 两个码打包为 1 字节。每 16 个数一个 FP32 缩放系数，因此 2,048 个数的载荷是 1,024 + 512 = 1,536 字节。**这不是 NVFP4 格式**，也未计 Python 对象、对齐及工作区。

## 文件

- `kv_lab.py`：完整模型与缓存实验；会写入你指定的结果 JSON。
- `test_kv_lab.py`：15 项自动测试。
- `results.json`：本次实际运行的测量值与环境，不是示例数字。
- `tests.txt`：本次测试原始输出。
- `requirements.txt`：本次 NumPy 版本。
- `SOURCE_NOTES.md`：机制依据与实验范围。

## 有意没有实现的东西

没有真实 GPU 内核、异步网络传输、跨进程并发、语义正确率评测、生产安全隔离、缓存持久化或训练。`PrefixCache` 的复制与回收完全串行；`PagePool` 是另一个独立生命周期模拟，不是 `TinyDecoder` 的分页注意力后端。不能据此声称已经复现 vLLM、FlashAttention、NVFP4、CacheBlend 或云端服务。

缓存权重身份包含实际数组的 SHA-256，而不是只用模型名字；实验中的命名空间是本地隔离示例，不是线上鉴权或秘密 salt 的替代。JSON 中的 `run_date` 是本版记录的整理日；重跑时应另外保存自己的日期／环境。
