KV Cache:大模型推理的加速引擎

一句话理解

KV Cache 是大模型推理时的"缓存加速器"——它把已经计算过的注意力键值保存下来,避免重复计算,让生成速度飙升。

没有KV Cache:每次生成一个Token,都要重新计算之前所有Token的注意力 → 慢!

有KV Cache:只计算新Token的注意力,之前的结果直接复用 → 快!

为什么需要KV Cache?

大模型推理分为两个阶段:

1. Prefill阶段(首次计算)

输入:"今天天气"
  ↓
计算每个Token的K(键)和V(值)
  ↓
生成第一个输出Token

2. Decode阶段(逐个生成)

生成"很" → 需要关注"今天天气很"
生成"好" → 需要关注"今天天气很好"
生成"。" → 需要关注"今天天气很好。"

问题来了:每次生成新Token,都要重新计算之前所有Token的注意力,开销巨大!

Token序列长度: 1 → 2 → 3 → 4 → 5 → ... → N
计算复杂度:     O(1) → O(2) → O(3) → O(4) → O(5) → ... → O(N)

O(N²)的复杂度,这就是"Context越长,推理越慢"的原因。


KV Cache的工作原理

┌─────────────────────────────────────────────────────────┐
│                      没有KV Cache                        
│                                                          
│   Token 1 → 计算 K1, V1                                  
│      ↓                                                   
│   Token 2 → 计算 K2, V2 + 重新计算 K1, V1 的注意力      
│      ↓                                                   
│   Token 3 → 计算 K3, V3 + 重新计算 K1, K2, V1, V2 的注意力
│      ↓                                                   
│   ... 重复计算,浪费资源!                               
└─────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────┐
│                      有KV Cache                          
│                                                          
│   Token 1 → 计算 K1, V1,存入Cache                        
│      ↓                                                   
│   Token 2 → 计算 K2, V2,复用Cache中的K1, V1             
│      ↓                                                   
│   Token 3 → 计算 K3, V3,复用Cache中的K1, K2, V1, V2    
│      ↓                                                   
│   ... 只计算新Token,充分利用缓存!                       
└─────────────────────────────────────────────────────────┘

数学原理

Transformer注意力计算

Attention(Q, K, V) = softmax(QK^T / √d) × V

其中:

  • Q(Query):当前位置的查询
  • K(Key):所有位置的键
  • V(Value):所有位置的值

Decode阶段的优化

# 原始做法:每次都重新计算所有注意力
def generate_token_naive(tokens):
    for i in range(max_length):
        # 每次都用所有历史tokens计算
        hidden_states = model(torch.cat(tokens))  # O(N) 的复杂度
        new_token = sample(hidden_states[-1])
        tokens.append(new_token)

# 使用KV Cache:只计算新增Token的注意力
def generate_token_with_kv_cache(tokens, kv_cache):
    # 只计算新token的Q
    q_new = compute_query(tokens[-1])
    
    # 从缓存获取历史的K和V
    k_all = torch.cat([kv_cache.k, q_new.k])  # O(1) 复用
    v_all = torch.cat([kv_cache.v, q_new.v])  # O(1) 复用
    
    # 计算注意力
    attention = softmax(q_new @ k_all.T / √d) @ v_all
    
    # 更新缓存
    kv_cache.update(k_new, v_new)
    
    return new_token

KV Cache的代价

KV Cache快是真快,但也有代价:

1. 显存占用巨大

公式:显存 ≈ 2 × 层数 × 隐藏维度 × BatchSize × SequenceLength × 2(Keys+Values)

以LLaMA 7B为例:
- 32层
- 隐藏维度4096
- 半精度(2字节)
- 上下文长度2048

每1万个Token需要:32 × 4096 × 2 × 10000 × 2 ≈ 5GB显存!

2. 显存碎片化

问题:预留太多 → 浪费
      预留太少 → 无法处理长序列

┌────────────────────────────────────────┐
│  GPU显存                               
│  ┌──────────┐  ┌──────────┐           
│  │ KV Cache    │ KV Cache   ...      
│  │ 请求1        │ 请求2             
│  │ 1000 tokens │ 500 tokens          
│  └──────────┘  └──────────┘           
│        ↑                              
│   大小不一,碎片化严重                  
└────────────────────────────────────────┘

2026年最新优化技术

1. PagedAttention(vLLM的核心技术)

受操作系统分页启发,按块管理KV Cache:

┌─────────────────────────────────────────────────┐
│                                                  
│   传统方式:请求 → 整个分配(要么全要,要么不要)
│                                                  
│   PagedAttention:分块管理(按需分配,灵活高效) 
│                                                  
│   KV Cache:| Block 0  | Block 1  | Block 2   | ...
│             | AIGC...  | ,今天... | ,天气...  │ ← 按块存储
│                                                  
│   优势:                                          
│   ├─ 显存利用率提升 60%+                          
│   ├─ 支持更多并发请求                             
│   └─ 处理更长上下文成为可能                       
│                                                  
└─────────────────────────────────────────────────┘

2. ChunkKV(长上下文优化)

针对超长上下文(100K+ tokens)的KV Cache压缩:

原始KV Cache:[K1, K2, K3, ..., K100K]
                     ↓ 语义压缩
压缩后KV Cache:[K1', K3', K7', ..., K100K']  ← 保留关键块

3. ThinKV(推理模型优化)

专门为Reasoning Model设计的KV Cache压缩:

Reasoning Model特点:CoT过程长,生成几百个Token很正常
问题:KV Cache爆炸性增长

ThinKV方案:
1. 检测思考过程中的"关键决策点"
2. 只保留这些关键点的KV
3. 中间过程用隐式压缩代替显式存储

4. LongSpec(长上下文投机解码)

让投机解码(Speculative Decoding)也能处理长上下文:

投机解码:用一个"小模型"猜测多个Token,大模型验证
问题:长上下文下,验证速度也变慢

LongSpec解决方案:
- 分段验证,避免全量计算
- 局部验证 + 全局采样

KV Cache实战配置

vLLM配置示例

from vllm import LLM, SamplingParams

# 初始化模型,自动启用PagedAttention
llm = LLM(
    model="meta-llama/Llama-3.1-8B-Instruct",
    gpu_memory_utilization=0.9,  # 90%显存用于KV Cache
    max_model_len=32768,          # 最大上下文长度
)

sampling_params = SamplingParams(
    temperature=0.7,
    max_tokens=1024,
)

# 请求会自动使用KV Cache加速
outputs = llm.generate(prompts, sampling_params)

Hugging Face配置示例

from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

model_id = "meta-llama/Llama-3.1-8B-Instruct"

tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    torch_dtype=torch.float16,
    device_map="auto",
)

# 启用KV Cache(默认启用)
inputs = tokenizer("今天天气", return_tensors="pt").to(model.device)

# 第一次生成
output = model.generate(**inputs, max_new_tokens=100, use_cache=True)

不同框架的KV Cache支持

框架 KV Cache 分页管理 备注
vLLM ✅ PagedAttention 生产级推荐
TensorRT-LLM NVIDIA官方优化
Hugging Face 简单场景够用
LightLLM 国产高性能框架
Text generation inference HuggingFace官方

KV Cache的质量指标

命中率(Hit Rate)

命中率 = Cache命中次数 / 总访问次数

理想情况:首次 Prefill 后,所有 Decode 请求都命中 Cache
实际情况:多个并发请求会竞争 Cache 空间

吞吐量和延迟

没有KV Cache:
- 吞吐量:10 tokens/s
- 延迟:100ms per token

有KV Cache(短上下文):
- 吞吐量:50 tokens/s (↑5倍)
- 延迟:20ms per token (↓5倍)

有KV Cache(长上下文 + PagedAttention):
- 吞吐量:100+ tokens/s (↑10倍)
- 延迟:10ms per token (↓10倍)

常见问题

Q1:KV Cache和系统缓存是一回事吗?

不是! 是两个完全不同的概念:

类型 位置 作用
系统缓存 磁盘/内存 避免重复读取磁盘文件
KV Cache GPU显存 避免重复计算Transformer注意力

Q2:Batch Size越大越好吗?

不是,Batch Size增大的代价:

  • 每个请求都需要独立的KV Cache
  • 显存总容量固定
  • Batch大 → 每个请求的Cache少 → 反而可能变慢
最佳策略:
- 长序列 + 小Batch
- 短序列 + 大Batch
- 动态调整,根据实际吞吐选最优

Q3:推理时显存不够怎么办?

# 方法1:减少上下文长度
model.generate(..., max_context_length=2048)  # 截断长输入

# 方法2:使用量化
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    load_in_8bit=True  # 量化到8位,减少KV Cache占用
)

# 方法3:使用Streaming + 滑动窗口
# 只保留最近N个Token的KV Cache

总结

┌────────────────────────────────────────────────────────┐
│                                                         
│   KV Cache的核心价值:                                   
│                                                         
│   ├─ 时间换空间:用显存换速度                            
│   ├─ 避免重复计算:O(N²) → O(N)                         
│   ├─ 吞吐提升:5-10倍甚至更高                           
│   └─ 是大模型推理引擎的标配优化                          
│                                                         
│   2026年进化:                                          
│   ├─ PagedAttention:显存管理革新                       
│   ├─ ChunkKV/ThinKV:长上下文压缩                       
│   └─ LongSpec:超长推理加速                             
│                                                         
│   没有KV Cache,就没有大模型的实时响应体验!              
│                                                         
└────────────────────────────────────────────────────────┘

延伸阅读

相关文章 说明
W20 Speculative Decoding 另一种加速推理的技术
W13 Transformer 了解注意力机制的基础
W07 上下文窗口 上下文与KV Cache的关系

本文收录于「AI词汇专栏」
相关阅读:W07 上下文窗口 · W20 Speculative Decoding

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐