06 · Prefix Cache:复用已经计算过的前缀
哪些场景会共享前缀
- 大量请求使用相同 system prompt。
- 同一份长文档被不同问题重复引用。
- 多轮对话的历史部分相同。
- Few-shot 示例固定,只变化最后的用户输入。
如果每次都重新做相同前缀的 Prefill,会浪费 GPU 计算和带宽。Prefix Cache 让后来的 Sequence 直接复用已有完整 KV block。
为什么按“完整 block”缓存
一个 block 只有在 token 已填满并稳定后,才适合形成可复用缓存条目。部分 block 仍可能继续追加 token,直接共享会产生写冲突和语义复杂度。
链式 hash
BlockManager 不是只对当前 block 的 token 做 hash,而是把前一个 block 的 hash 作为 prefix 输入:
text
h0 = hash(block0)
h1 = hash(h0, block1)
h2 = hash(h1, block2)这样同样的局部 token block 出现在不同前缀后面,不会被错误认为是同一个完整上下文。
命中流程
can_allocate(seq) 从第一个完整 block 开始计算 hash:
- hash 存在,且 block token 内容一致:命中,继续下一个 block。
- hash 不存在或内容不同:停止命中。
- 计算新请求还需要多少 block,若空闲不足返回失败。
分配时,命中 block 的 ref_count 增加;新 block 才从 free 队列获取。
缓存不是越多越好
Prefix Cache 会占用 block,旧条目何时淘汰、hash 冲突如何处理、缓存命中是否值得维护,都属于生产系统需要进一步设计的策略。nano-vLLM 的实现适合作为最小正确模型,而不是完整缓存产品。
HTML INTERACTIVE LAB06 · Prefix Cache:复用已经计算过的前缀
单独打开 ↗课后习题等待完成
为什么 Prefix Cache 的 hash 要包含前一个 block 的 hash?
动手任务
准备两个共享 8 个 token、block_size=4 的 prompt,再让第 9 个 token 不同。写出可复用 block 数,并解释为什么部分 block 不复用。
下一节:Prefill 与 Decode