KV Cache
[!Important]
- Query, Key, Value
- self-attention: 自注意力机制

本图表详细解释了大型语言模型(LLM)推理过程中的 KV-Cache(Key-Value Cache,键值缓存) 机制。该机制是提高 LLM 生成速度的核心技术,它通过避免重复计算来加速 token 的生成。
图表结构与流程
图表分为四个主要部分,从宏观到微观展示了 KV-Cache 的全貌:
LLM 推理概览 (LLM Inference Overview):
- 展示了 LLM 生成文本的基本过程。输入提示(Prompt)后,模型会逐个生成 token。生成一个 token 后,它会与之前的输入一起再次输入模型,以生成下一个 token。这是一个循环过程。
对比:无与有 KV-Cache (Comparison: Without vs. With KV-Cache):
- 无 KV-Cache(左侧红色区域):在生成第 3 个 token 时,模型必须重新计算所有先前 token(Token 1 和 Token 2)的自注意力矩阵(Q, K, V)。图中使用红色虚线和文本强调了这种“重新计算”导致的低效和高延迟(Latency: O(N^2))。
- 有 KV-Cache(右侧绿色区域):在生成第 3 个 token 时,模型只需要计算当前新 token 的 Q, K, V。然后,它会直接从 [KV-Cache 存储器] 中“读取”之前所有 token 的 K 和 V 矩阵,将它们与新 token 的 K, V 拼接。这样就极大地减少了计算量,实现了低延迟(Latency: O(N))。
KV-Cache 的详细机制 (The KV-Cache Mechanism in Attention):
- 这一部分是核心,详细说明了缓存的运作。
- 阶段 1:预填充 (Prefill - Prompt Processing):当模型第一次处理完整的 Prompt 时,它会计算所有输入 token 的 Q, K, V 矩阵。所有计算出的 K 矩阵(蓝色)和 V 矩阵(绿色)都被存储到 [KV-Cache] 中。
- 阶段 2:解码 (Decode - Token Generation):当生成新的 token 时:
- 模型仅计算新 token 的 Q_new, K_new, V_new。
- 在注意力步骤中,新 token 的
Query(Q_new) 会关注从缓存中读取的所有旧的 K、V 矩阵(K_cache, V_cache)以及自己的 K_new, V_new。图中的“拼接”操作形象地展示了这一点。
KV-Cache 总结表 (KV-Cache Summary):
- 图表右下角的表格清晰地对比了有无 KV-Cache 的关键指标:
- 每个 Token 的计算量:O(1)(有)vs O(N)(无),N 为 Token 数。
- KV 存储:N 个 Token(有)vs 无(无)。
- 速度:快(有)vs 慢(无)。
- 内存使用:高(有)vs 低(无)。
- 图表右下角的表格清晰地对比了有无 KV-Cache 的关键指标:
总结
总而言之,KV-Cache 是一种空间换时间的策略。它利用内存存储了先前计算过的 Key 和 Value 矩阵,从而在推理的每一步解码过程中,只需计算一个新 token 的值。这种设计显著降低了计算量,是使 LLM(如 ChatGPT)能够实时生成文本的关键技术。

本图表详细解释了在大型语言模型 (LLM) 推理过程中,Key-Value Cache (KV-Cache) 机制是如何利用和存储 Query (Q)、Key (K) 和 Value (V) 向量,从而实现高效生成的。
图表结构与流程
图表分为三个主要部分,从对比的角度展示了 KV-Cache 的全貌:
无 KV-Cache 的 LLM 推理(慢速) (LLM INFERENCE WITHOUT KV-CACHE (SLOW)):
- 展示了在生成多个 token 时,模型必须为每一个新 token 重新计算所有先前 token 的 K 和 V 矩阵。
- 例如,在生成第 3 个 token (T3) 时,模型必须再次计算 (Prompt, T1, T2) 的 K 和 V。这种“重新计算”随着生成序列的变长,计算量会呈二次方增长 (Quadratic Cost),从而导致延迟非常高。红色文本强调了这一点:SLOW & INEFFICIENT。
有 KV-Cache 的 LLM 推理(快速) (LLM INFERENCE WITH KV-CACHE (FAST)):
- 展示了核心优化机制。模型会“记住”先前 token 的计算结果,将其存储在 KV-Cache 中。
- 步骤 1 (T1 生成):模型计算 Q1, K1, V1。然后,它会将 $K_1, V_1$ 存储在 [KV-Cache] 存储器中(图中使用数据库图标表示)。
- 步骤 2 (T2 生成):当生成新的 T2 时,模型只计算新 token (T2) 的 Q2, K2, V2。然后,它从 [KV-Cache] 中直接读取之前存储的 $K_1, V_1$。
- 在自注意力机制中,Q2 只会关注新计算的 K2 和 V2,以及从缓存中读取的 $K_1, V_1$,而无需重新计算 T1 的 K、V。这种方法实现了线性计算成本 (Linear Cost)。绿色文本强调了这一点:FAST & EFFICIENT。
KV-Cache 自注意力机制的详细内部原理 (INSIDE THE SELF-ATTENTION BLOCK WITH KV-CACHE):
- 这一部分是核心,详细说明了缓存的运作。
- 输入:新的输入 token (Ti) 和来自 KV-Cache 的先前 K、V ($K_{1 \dots i-1}, V_{1 \dots i-1}$)。
- 模型计算:从 Ti 派生出 $Q_i, K_i, V_i$。
- 缓存更新 (UPDATE KV-CACHE):将新计算出的 $K_i, V_i$ 追加 (Append) 到缓存中。
- 注意力计算 (ATTENTION COMPUTATION):图中使用手绘的 Softmax 图标展示了注意力操作。
- Q_i (Query) 与所有 K 向量的点积:Attention 权重 = $\text{Softmax}(Q_i \cdot K_{\text{all}}^T / \sqrt{d})$。
- 权重乘以所有 V 向量:最终 Output Vector = 权重 $\cdot V_{\text{all}}$。
- 图表中明确指出 $K_{\text{all}}$ 是缓存 $K_{1 \dots i-1}$ 和新 $K_i$ 的拼接,同样的,$V_{\text{all}}$ 也是拼接。
总结
总而言之,KV-Cache 是一种将先前 token 的 K 和 V 矩阵存储在内存中的优化技术。这样,在推理的每一步解码过程中,只需计算一个新 token 的值,极大地降低了计算量,从而加速了 LLM 的生成速度。

Q K V
可以把 KV-cache 里的 Q / K / V 理解成注意力机制里的三种“角色”:
- Q(Query):当前 token 想“查什么”
- K(Key):每个历史 token 提供的“索引/标签”
- V(Value):每个历史 token 真正携带的“内容”
1. 先从类比理解
想象你在图书馆找资料:
- Q:你手里的检索需求
“我要找和‘法国首都’相关的信息”
- K:每本书的目录卡/标签
“地理”“欧洲”“法国”……
- V:书里真正的内容
“巴黎是法国首都”
流程就是:
- 用 Q 去和所有 K 做匹配
- 看哪些 K 最相关
- 把这些相关位置对应的 V 加权取出来
这就是 attention 的核心。
2. 在 Transformer 里它们怎么来的
对每个 token 的隐藏状态 (x),模型会通过三组不同的线性变换得到:
[
Q = xW_Q,\quad K = xW_K,\quad V = xW_V
]
所以:
- Q:表示“这个位置现在要关注什么”
- K:表示“这个位置能被怎样检索到”
- V:表示“这个位置要贡献什么信息”
注意力分数一般是:
[
\text{Attention}(Q, K, V) = \text{softmax}\left (\frac{QK^T}{\sqrt{d_k}}\right) V
]
含义:
- (QK^T):算相似度
- softmax:变成权重
- 再乘 (V):把内容按权重聚合
3. 为什么推理时只缓存 K 和 V,不缓存 Q?
这是 KV-cache 最关键的问题。
在自回归生成里,模型是一个 token 一个 token 往后生成:
- 第 1 步生成第 1 个新 token
- 第 2 步生成第 2 个新 token
- ……
当生成当前位置时:
- 当前 token 的 Q 只用于“这一次查询”
- 历史 token 的 K / V 会被后续所有步骤反复使用
所以:
- Q:每一步都重新算,没必要缓存
- K / V:历史不变,后面一直要用,缓存起来最划算
因此叫 KV-cache,而不是 QKV-cache。
4. 一个更直观的生成过程
假设上下文是:
“The capital of France is”
现在模型要预测下一个词。
已有历史 token
每个历史 token 都已经生成了自己的:
- (K_1, V_1)
- (K_2, V_2)
- …
- (K_t, V_t)
这些会被存进 cache。
当前步骤
模型对当前位置算出当前的 Q_t
然后:
- 用 (Q_t) 和历史所有 (K_1… K_t) 做匹配
- 得到注意力权重
- 对应加权汇总 (V_1… V_t)
- 得到当前上下文表示
- 预测下一个 token,例如
Paris
生成完这个新 token 后,再为它计算自己的 K, V,追加到 cache 里,供下一步使用。
5. 为什么 KV-cache 能加速
如果没有 cache,每生成一个新 token,都要对之前所有 token 重新计算 K 和 V。
例如已经有 1000 个 token:
- 生成第 1001 个 token 时
- 如果不缓存,要把前面 1000 个 token 又过一遍,重新算 K/V
- 很浪费
有了 KV-cache:
- 前面 1000 个 token 的 K/V 已经算好了
- 这一步只需要算新 token 的 Q,以及新 token 的 K/V
- 再拿 Q 去跟缓存里的 K 做 attention
所以它主要节���的是 重复计算。
6. 但为什么它会占显存?
因为你要把每一层、每个 head、每个历史位置的 K/V 都存下来。
缓存大小大致和这些因素成正比:
- batch size
- 序列长度
- 层数
- attention heads
- hidden dimension
- 数据类型(fp 16 / bf 16 / fp 8 等)
所以常见现象是:
- KV-cache 提升速度
- 但会增加显存占用
这也是长上下文推理很吃显存的重要原因之一。
7. Q / K / V 的“本质理解”
可以这么记:
- Q = 我现在想找什么
- K = 你这里能提供什么索引
- V = 你这里真正提供什么内容
注意力不是“把所有历史都平均看一遍”,而是:
当前 token 拿着自己的 Q,去历史 token 的 K 里检索,然后把对应的 V 取回来。
8. 一个常见误区
误区:K 和 V 是“固定语义”
不完全对。
虽然可以直观理解成:
- K 像标签
- V 像内容
但它们本质上都是模型学出来的向量投影,不一定能严格对应自然语言中的“标签”和“正文”。这只是帮助理解的比喻。
误区:Q 不重要,因为不缓存
也不对。
Q 非常重要,只是它的生命周期很短:
- 只服务当前这一步的注意力计算
- 用完就没必要留了
9. 一句话总结
在 KV-cache 中:Q 是当前查询,K 是历史位置的可匹配索引,V 是历史位置承载的��息;推理时缓存 K/V 是因为它们会被反复复用,而 Q 每一步都要重新生成。
如果你愿意,我还可以继续给你讲:
- prefill 和 decode 阶段里 KV-cache 的区别
- 为什么 attention 复杂度会从重复计算中受益
- 从代码实现角度看 KV-cache tensor shape 是什么样的