站点图标 高效码农

KV缓存揭秘:为什么ChatGPT第一个字慢但后续飞快?5倍推理加速的背后真相

深入解析 LLM 推理加速的核心技术:KV Caching 是如何让大模型快 5 倍的?

每当你使用 ChatGPT 或 Claude 等大模型应用时,你一定注意到了一个细微但普遍的现象:第一个生成的 token(字词片段)总是需要稍等片刻才会出现,但一旦它出现,随后的文字就会像流水一样瞬间倾泻而出。

「这并非 UI 的设计缺陷,也不是网络波动,而是一项深思熟虑的工程决策——KV Caching(键值缓存)。」 这项技术将大模型(LLM)的推理速度提升了大约 5 倍。本文将从第一性原理出发,深入探讨 KV Caching 的工作机制、它如何解决计算冗余、带来的首字延迟(TTFT)权衡,以及在规模化部署时面临的显存挑战。


1. Transformer 模型生成 Token 的基本原理

本段核心问题

在生成式大模型中,从输入文本到输出下一个字,模型内部到底发生了什么?

理解模型的生成流程

要理解 KV Caching 的价值,我们首先必须回归基础,理解 Transformer 模型是如何生成 token 的。这个过程并非简单的“输入-输出”,而是一个复杂的数学变换流程。

  1. 「输入处理」:当你输入一段文本时,模型首先将其分割成一个个 token,并将每个 token 转换为向量。
  2. 「隐藏状态生成」:Transformer 模型处理输入序列中的所有 token,并为每一个 token 生成一个“隐藏状态”。这些隐藏状态是模型对当前 token 及其上下文的深层理解。
  3. 「映射到词汇空间」:这些隐藏状态随后被投影到“词汇空间”,产生 Logits( logits 可以理解为词汇表中每个词的得分)。
  4. 「采样与循环」:最关键的一步来了——「只有最后一个 token 的 Logits 才具有实际意义」。模型基于这最后一个 token 的 Logits 进行采样,得到下一个 token,将其追加到输入序列的末尾,然后重复上述过程。

「场景示例」
假设你输入“天空是”,模型处理这两个 token 后,重点在于最后一个 token “是”的隐藏状态。基于这个状态,模型预测下一个词可能是“蓝色的”。然后,“蓝色的”成为新的输入末端,模型再次运行。

「反思 / 学到的教训」
很多初学者误以为模型每次生成都在“重读”整篇文章。实际上,模型是在不断通过最新的状态来推测下一个字。这种“自回归”的特性,既是大模型流畅生成的基石,也是计算瓶颈的根源。


2. Attention 机制到底在计算什么?

本段核心问题

在 Transformer 模型内部,Attention 机制是如何利用 Query、Key 和 Value 向量来确定上下文关系的?

深入注意力层

在 Transformer 的每一层中,每个 token 都会被赋予三个至关重要的向量:查询向量、键向量 和 值向量。

  1. 「Q (Query)」:代表当前 token 想要“寻找”什么信息。
  2. 「K (Key)」:代表其他 token 包含什么信息,作为匹配的依据。
  3. 「V (Value)」:代表 token 的实际内容信息。

Attention 的计算过程本质上是 Q 与 K 的点积运算,以此得出注意力分数,再利用这些分数对 V 进行加权求和。

聚焦最后一个 Token

让我们将视角缩小到生成过程中的「最后一个 token」

  • 「计算关系」:在注意力矩阵 的最后一行中,计算涉及的是:
    • 「最后一个 token 的 Query 向量」
    • 「序列中所有 token 的 Key 向量」
  • 「输出结果」:最终该行的 Attention 输出使用了:
    • 「同一个 Query 向量」
    • 「序列中所有 token 的 Key 和 Value 向量」

这意味着,为了生成下一个 token,模型的每一层 Attention 机制都需要:「最新 token 的 Q」,以及「历史所有 token 的 K 和 V」

「反思 / 独特见解」
这解释了为什么 LLM 能够保持长上下文的连贯性。每一次生成,其实都是最新的 Query 在对历史所有的 Keys 进行一次“全面检索”。只要这种检索机制不丢失,上下文逻辑就能得以延续。


3. 冗余计算:性能瓶颈的真相

本段核心问题

在不使用缓存的情况下,自回归生成为什么会导致巨大的算力浪费?

O(n) 的重复劳动

现在,让我们看看这种机制在实际运行中是如何产生冗余的。

  • 「生成第 50 个 token 时」:模型需要第 1 到第 50 个 token 的 K 和 V 向量。
  • 「生成第 51 个 token 时」:模型需要第 1 到第 51 个 token 的 K 和 V 向量。

问题的关键在于:「第 1 到第 49 个 token 的 K 和 V 向量,在第 50 步时已经计算过了。」 输入没变,参数没变,输出自然也不会变。然而,标准的处理流程却要求模型在第 51 步(以及后续的每一步)都从头开始重新计算这些向量。


图片来源:Unsplash

场景化描述

想象你在写一份很长的报告。每次你想写一个新句子,你都把之前写过的所有句子重新抄一遍,然后再写新的一句。这不仅荒谬,而且低效。在 LLM 推理中,这种低效就是计算资源的黑洞。

  • 「单步冗余」:每一步生成中,都有 O(n) 的工作是重复的(n 为序列长度)。
  • 「整体浪费」:在整个生成过程中,这种冗余导致的浪费高达 O(n²)。

在生成几千字的长文本时,这种指数级增长的算力消耗是不可接受的。


4. 解决方案:KV Caching 的实现逻辑

本段核心问题

如何通过存储中间计算结果,将昂贵的重复计算转化为廉价的内存读取?

KV Caching 的工作原理

为了解决上述冗余,工程师们引入了 KV Caching。它的核心思想非常直观:「不要重复计算,要记住结果」

具体实现步骤如下:

  1. 「仅计算新增部分」:当生成一个新 token 时,只在每一层计算这个「最新 token」 的 Q、K 和 V 向量。
  2. 「追加缓存」:将这个新 token 的 K 和 V 向量追加到该层的缓存中。
  3. 「读取历史数据」:从缓存中检索之前所有 token 的 K 和 V 向量。
  4. 「执行 Attention」:使用最新的 Q 向量,与“完整的缓存 K 和 V”进行 Attention 运算。

效果对比

阶段 无 KV Caching 有 KV Caching
「计算 K/V」 每步计算所有历史 token 每步仅计算新 token
「计算量」 随序列长度 O(n) 增长 固定 O(1)(针对投影部分)
「内存消耗」 较低(即时计算) 较高(需存储 K/V)
「生成速度」 慢(呈二次方级下降) 快(线性且稳定)

这就是 KV Caching 的本质:每个层、每一步只产生一个新的 K 和一个新的 V,其他一切都来自内存。

虽然 Attention 的计算量仍然随着序列长度的增加而增加(因为你仍然要关注所有的 Keys 和 Values),但「最昂贵的、将向量投影为 K 和 V 的线性变换」,每个 token 只需要执行一次。


图片来源:Unsplash


5. Time-to-First-Token (TTFT):为何第一个字总是慢?

本段核心问题

既然 KV Caching 如此高效,为什么我们在等待第一个字出现时依然会有明显的延迟?

预填充阶段

理解了 KV Caching,就不难理解 TTFT 的来源。当你发送一个 Prompt(提示词)给模型时:

  1. 「一次性处理」:模型必须在一个前向传播中处理整个输入序列。
  2. 「构建缓存」:在这个阶段,模型的主要任务是计算并缓存输入中每一个 token 的 K 和 V 向量。
  3. 「计算密集型」:这个过程被称为“预填充”阶段。它是整个请求中计算最密集、最耗时的部分。

缓存的热与冷

  • 「冷缓存」:在预填充阶段之前,没有任何缓存数据,一切都需要从头算起。这就是为什么长 Prompt 会让人等待更久——Prompt 越长,需要预填充的 KV Cache 就越多。
  • 「热缓存」:一旦预填充完成,缓存就“热”了。后续每个 token 的生成只需要针对单个 token 进行前向传播,因此速度极快。

虽然业界有各种优化 TTFT 的技术(如分块预填充、投机解码、Prompt Caching),但底层逻辑始终如一:「构建缓存是昂贵的,读取缓存是廉价的。」

「反思 / 实际观察」
这种动态直接影响了用户体验设计。很多应用为了掩盖 TTFT,会采用“流式输出”的方式,让用户在第一个字出来后立刻感受到连贯的反馈,从而忽略最初的等待时间。这是一层精妙的交互心理学掩盖底层工程特性的典型案例。


6. 权衡之术:显存成为新的瓶颈

本段核心问题

KV Caching 以空间换时间,这种置换在工程落地时带来了哪些显存挑战?

显存消耗的数学陷阱

KV Caching 并非没有代价。它用计算换取了内存(显存)。每一个模型的每一层,都需要存储序列中每一个 token 的 K 和 V 向量。

对于一个像 Qwen 2.5 72B 这样的大规模参数模型,显存压力是惊人的:

  • 「80 个层」:每一层都要存。
  • 「32K 上下文」:支持的序列越长,存的向量越多。
  • 「Hidden Dim 8192」:每个向量的维度很大。

在这种配置下,「单个请求的 KV Cache 就可能消耗数 GB 的 GPU 显存」。当并发请求达到成百上千时,KV Cache 占用的显存总量往往会超过模型权重本身的体积。

应对策略:GQA 与 MQA

为了缓解这一问题,工程界引入了 Grouped-Query Attention (GQA) 和 Multi-Query Attention (MQA)。

  • 「原理」:让多个 Query 头共享同一组 Key 和 Value 头。
  • 「效果」:大幅减少显存占用,同时将模型质量的损失降至最低。

上下文长度的困境

这也是为什么将 LLM 的上下文长度翻倍如此困难。

  • 「显存翻倍」:上下文窗口扩大一倍,意味着每个请求的 KV Cache 也要扩大一倍。
  • 「并发能力下降」:在有限的 GPU 显存下,单个请求占用的显存越多,系统能同时服务的用户数量就越少。

因此,在扩展上下文长度时,必须在“用户体验”和“服务成本/并发能力”之间做出艰难的平衡。


图片来源:Unsplash


7. 总结与行业实践

本段核心问题

KV Caching 在现代 LLM 服务栈中扮演着怎样的角色?

KV Caching 消除了自回归生成过程中的冗余计算。由于之前的 token 总是产生相同的 K 和 V 向量,我们只需计算一次并存储。后续的每个新 token 只需计算它自己的 Q、K 和 V,然后对完整的缓存运行 Attention。

这项技术在实践中带来了 「5 倍的推理加速」。其代价是 GPU 显存,在规模化部署时,显存往往成为最紧张的约束资源。

目前,几乎所有主流的 LLM 推理服务栈——包括 vLLM、TGI (Text Generation Inference) 和 TensorRT-LLM——都构建在这一核心思想之上。它们利用先进的显存管理技术(如 PagedAttention)来高效地管理这些 KV Cache,从而在速度和资源利用率之间达到最佳平衡。


实用摘要 / 操作清单

  1. 「识别瓶颈」:如果你的 LLM 应用在生成后续 token 时速度很慢,首先检查推理框架是否启用了 KV Caching。
  2. 「监控 TTFT」:关注 Time-to-First-Token 指标。TTFT 过长通常意味着预填充阶段的计算压力大,考虑优化 Prompt 长度或使用预填充优化技术。
  3. 「评估显存」:在规划并发量时,不仅要计算模型权重的显存占用,还要根据最大上下文长度和并发请求数估算 KV Cache 的显存需求(公式参考:2 * layers * hidden_dim * seq_len * batch_size * bytes_per_param)。
  4. 「选择模型架构」:在显存受限的场景下,优先支持 GQA 或 MQA 的模型架构(如 Qwen2, Llama3),以降低 KV Cache 的开销。

一页速览

概念 关键点 影响
「KV Caching」 存储历史 token 的 Key 和 Value 向量,避免重复计算。 推理速度提升约 5 倍。
「生成原理」 仅最后一个 token 的 Logits 用于预测下一个字。 确定了仅需关注最新状态的必要性。
「Attention 计算」 新 Q 对比 全部。 Attention 计算量仍随长度增长,但 K/V 投影仅一次。
「TTFT (首字延迟)」 处理 Prompt 并建立缓存的阶段。 Prompt 越长,TTFT 越长;是用户体验的关键节点。
「计算 vs 显存」 用显存空间换取计算时间。 显存成为高并发场景下的主要瓶颈。
「优化技术」 GQA, MQA, PagedAttention. 在降低显存占用的同时维持模型质量。

常见问题 (FAQ)

「Q1:为什么我在使用本地模型跑推理时,显存会随着生成长度的增加而增加?」
「A」:这是因为启用了 KV Caching。随着你生成的 token 越来越多,模型需要存储的 K 和 V 向量也就越来越多,显存占用随之线性增长。

「Q2:KV Caching 会改变模型的生成结果吗?」
「A」:不会。KV Caching 只是一种计算优化技术,它存储的是原本就需要计算出来的中间结果。从数学上讲,它不改变模型的输出分布。

「Q3:什么是 “Prefill” 阶段,它和 “Decoding” 阶段有什么区别?」
「A」:Prefill 是处理输入 Prompt 并构建 KV Cache 的阶段,特点是计算密集型;Decoding 是基于已有 Cache 逐个生成新 token 的阶段,特点是内存访问密集型。

「Q4:为什么增加上下文长度(Context Window)这么难?」
「A」:因为上下文长度直接决定了 KV Cache 的最大容量。翻倍上下文通常意味着翻倍的显存需求,这会急剧增加硬件成本或降低并发服务能力。

「Q5:所有的大模型推理框架都支持 KV Caching 吗?」
「A」:几乎所有的现代生产级框架(如 vLLM, TGI, TensorRT-LLM)默认都支持并依赖于 KV Caching。不支持 KV Caching 的框架在处理长文本生成时效率极低,不具备实用性。

「Q6:除了 KV Caching,还有哪些方法可以加速推理?」
「A」:文中提到的投机解码和分块预填充是针对 TTFT 和生成阶段的优化。此外,量化、模型剪枝以及 FlashAttention 等算子优化也是常用的手段。

「Q7:GQA 是如何帮助节省显存的?」
「A」:GQA (Grouped-Query Attention) 通过让多个 Query 头共享 Key 和 Value 头,减少了需要存储的 K 和 V 向量的总数量,从而显著降低了 KV Cache 的显存占用。

退出移动版