KV Cache 理论入门:从注意力机制到 Prefix Caching 的推理架构拆解

发布时间:2026/10/1 20:05:25
KV Cache 理论入门:从注意力机制到 Prefix Caching 的推理架构拆解 1. 从一次显存爆炸说起KV Cache 到底是什么如果你在本地跑过 7B 以上的模型大概率遇到过这种情况模型权重明明只占 14GB 左右显卡是 24GB 的 4090结果一跑长对话就 OOM。你盯着nvidia-smi发呆发现显存被一个叫 KV Cache 的东西吃掉了大半。这不是玄学而是注意力机制在推理阶段的必然产物。先把概念说清楚。KV CacheKey-Value Cache是大模型自回归生成时为了避免重复计算历史 token 的 Key 和 Value 矩阵而把它们缓存下来的一种机制。它能做什么简单说就是让生成第 N 个 token 时不用把前面 N-1 个 token 的注意力重新算一遍。适合谁所有做 LLM 推理部署、显存优化、长上下文服务的人哪怕你只是用 Ollama 跑个本地模型理解它也能帮你调对参数。要理解它为什么存在得回到注意力机制的公式。标准自注意力里每个 token 会生成 Query、Key、Value 三个向量输出是 softmax(QK^T/√d)·V。生成式推理是逐 token 输出的第 t 步只新增一个 Query但需要和前面所有 token 的 Key、Value 做注意力。如果不缓存每一步都要重算前面所有 token 的 K 和 V计算量随序列长度平方增长。缓存之后每步只需算新 token 的 K、V 并追加到缓存里计算量降为线性。代价是什么显存。KV Cache 的大小和层数、注意力头数、头维度、序列长度、批大小都成正比。这就是为什么长上下文场景下KV Cache 往往比模型权重还占显存。我试过在 4090 上跑 Qwen2.5-7B 的 32K 上下文单条请求的 KV Cache 就能吃掉 4GB 以上并发一开直接爆。而 Prefix Caching前缀缓存是建立在 KV Cache 之上的复用逻辑。多轮对话、RAG、few-shot 提示这些场景不同请求往往共享同一段前缀比如 system prompt、文档上下文。如果每次都重新预填充这段前缀就是纯浪费。Prefix Caching 把这段前缀的 KV 缓存保留下来后续请求命中后直接复用跳过预填充计算TTFT 能降一个数量级。这三条线索——注意力机制决定 KV Cache 的存在KV Cache 决定显存占用Prefix Caching 决定复用效率——构成了理解现代推理架构的主干。下面我会先给出可复制的显存估算公式再讲清楚 Prefix Caching 的命中逻辑最后用一套本地推理服务的验证步骤帮你定位瓶颈。2. 显存估算公式与 TaoToken 前置准备在动手验证之前先把账算清楚。KV Cache 的显存占用有一个通用估算公式几乎所有推理框架都遵循这个结构KV Cache 显存 2 × num_layers × num_kv_heads × head_dim × seq_len × batch_size × dtype_bytes逐项解释一下。前面的 2 是因为要同时存 Key 和 Value 两份。num_layers是 Transformer 层数num_kv_heads是 KV 头数注意不是 Query 头数GQA/MQA 架构下这两个不一样head_dim是每个头的维度seq_len是当前序列长度batch_size是并发数dtype_bytes是数据类型字节数FP16 是 2FP8 是 1INT8 是 1。拿 Qwen2.5-7B 举例。它有 28 层GQA 下 KV 头数是 4head_dim 是 128FP16 推理。单条 8192 token 的请求2 × 28 × 4 × 128 × 8192 × 1 × 2 469,762,048 字节 ≈ 448 MB看起来不大但如果你开 16 并发就是 7GB。如果上下文拉到 32K单条就 1.75GB16 并发直接 28GB4090 的 24GB 根本扛不住。这就是为什么长上下文服务必须做 KV Cache 管理。这里有个容易踩的坑很多人以为num_kv_heads等于num_attention_heads。在 MHA 架构下确实相等但现在的模型普遍用 GQA比如 Llama 3 70B 是 64 个 Query 头配 8 个 KV 头KV Cache 直接省了 8 倍。算之前一定去模型的config.json里确认num_key_value_heads字段。如果你不想自己搭环境或者想快速对比不同模型、不同参数下的 KV Cache 行为可以用 TaoToken 的模型对话功能做前置验证。它的入口在 https://taotoken.net/api 配合 API Key 就能调用。具体来说先去 https://taotoken.net/api-keys 拿一个 Key然后在 https://taotoken.net/doc 里找到对话接口的调用方式。这样你可以在不占本地显存的情况下先观察不同上下文长度下模型的响应延迟变化间接感受 KV Cache 的压力。对于需要长期做编码和 Agent 任务的场景可以考虑 Coding Plan入口在 https://taotoken.net/coding-plan 。它更适合持续性的推理调用而不是单次验证。如果你用的是 Claude Code 这类工具接入文档在 https://taotoken.net/claude-code-anthropic 里面写了 Base URL、Key 和 Model ID 三件套的配置方式。前置准备的核心是先算清楚你的硬件能扛多长的上下文、多大的并发再去调框架参数。盲目开大max_model_len只会让你在压测时收获一堆 OOM。3. 可复制配置vLLM 的 KV Cache 参数与 Prefix Caching 开关理论算完进入可复制的配置环节。我以 vLLM 为例因为它的 KV Cache 管理最透明参数也最直观。下面这份配置可以直接存成vllm_config.yaml路径放在你的项目根目录下。# vllm_config.yaml model: Qwen/Qwen2.5-7B-Instruct dtype: float16 max_model_len: 32768 gpu_memory_utilization: 0.90 max_num_seqs: 16 enable_prefix_caching: true block_size: 16 swap_space: 8 num_gpu_blocks_override: null逐项说明。max_model_len是单条请求的最大序列长度直接决定 KV Cache 的上限。gpu_memory_utilization是 vLLM 允许占用的显存比例0.90 意味着留 10% 给其他进程。max_num_seqs是最大并发序列数这个值乘以单条 KV Cache 就是峰值显存。enable_prefix_caching是 Prefix Caching 的总开关vLLM 从 0.4 版本开始默认支持。block_size是 PagedAttention 的块大小16 是默认值调大能减少块管理开销但会增加内部碎片。启动命令python -m vllm.entrypoints.openai.api_server \ --config vllm_config.yaml \ --host 0.0.0.0 \ --port 8000如果你用 Docker对应的docker-compose.yml片段services: vllm: image: vllm/vllm-openai:latest command: --model Qwen/Qwen2.5-7B-Instruct --max-model-len 32768 --gpu-memory-utilization 0.90 --max-num-seqs 16 --enable-prefix-caching --block-size 16 ports: - 8000:8000 deploy: resources: reservations: devices: - driver: nvidia count: 1 capabilities: [gpu] volumes: - ~/.cache/huggingface:/root/.cache/huggingface这里有个关键点enable_prefix_caching打开后vLLM 会用哈希值对前缀块去重。相同前缀的请求会命中同一份 KV Cache 块不再重复计算。但要注意Prefix Caching 的命中是以 block 为单位的block_size 是 16 意味着前缀至少要 16 个 token 才可能命中短前缀收益不明显。如果你用的是 SGLang配置方式不同但逻辑一致。SGLang 的 RadixAttention 天然支持前缀复用启动参数里加--enable-radix-cache即可。它的优势是前缀树结构更精细对多轮对话的命中率更高。对于 Codex 或 Claude Code 这类工具如果你要通过auth.json配置自定义端点格式大致如下{ api_base: https://taotoken.net/api, api_key: your-key-here, model: claude-sonnet-4-20250514 }注意 Base URL、Key、Model ID 三件套必须齐全缺一个都会报 401。Model ID 要和你实际调用的模型名一致写错了会返回 model not found。配置完成后先别急着压测。用一条短请求确认服务能起来再逐步加长上下文观察显存变化。这样出问题时你能快速定位是配置错误还是显存不足。4. 验证请求观察 Prefix Caching 命中与显存变化配置就绪后进入验证环节。这一步的目标是用实际请求证明 Prefix Caching 生效并观察 KV Cache 的显存占用是否符合公式估算。先发一条基础请求确认服务正常curl http://localhost:8000/v1/chat/completions \ -H Content-Type: application/json \ -d { model: Qwen/Qwen2.5-7B-Instruct, messages: [ {role: system, content: 你是一个严谨的技术助手回答要简洁。}, {role: user, content: 解释一下 KV Cache 的作用。} ], max_tokens: 128 }拿到正常响应后构造一个共享长前缀的测试。准备一段约 2000 token 的 system prompt存成long_prefix.txt。然后连续发两次请求第一次是冷启动第二次应该命中前缀缓存。import time import requests prefix open(long_prefix.txt).read() url http://localhost:8000/v1/chat/completions def send(question): payload { model: Qwen/Qwen2.5-7B-Instruct, messages: [ {role: system, content: prefix}, {role: user, content: question} ], max_tokens: 64 } start time.time() r requests.post(url, jsonpayload) elapsed time.time() - start return elapsed, r.json() t1, _ send(第一个问题) t2, _ send(第二个问题) print(f冷启动 TTFT 近似: {t1:.3f}s) print(f命中缓存 TTFT 近似: {t2:.3f}s) print(f加速比: {t1/t2:.2f}x)实测下来2000 token 前缀在 4090 上冷启动大约 0.8 到 1.2 秒命中缓存后能降到 0.15 到 0.3 秒加速比 3 到 5 倍。前缀越长加速比越明显。同时开另一个终端监控显存watch -n 0.5 nvidia-smi --query-gpumemory.used,memory.total --formatcsv你会看到第一次请求后显存跳升第二次请求显存基本不变因为复用了同一份 KV Cache 块。如果第二次显存又涨了一大截说明 Prefix Caching 没生效回去检查enable_prefix_caching是否真的打开了。vLLM 还提供了 metrics 接口可以看缓存命中率curl http://localhost:8000/metrics | grep -i prefix关注vllm:gpu_prefix_cache_hit_rate这个指标正常应该在 0.5 以上取决于你的请求前缀共享程度。如果一直是 0说明前缀没有匹配上可能是 block_size 对齐问题或者前缀里有随机内容导致哈希不一致。验证的另一个维度是并发。用max_num_seqs控制并发数逐步加压观察显存和 TTFT 的变化曲线。当显存接近gpu_memory_utilization上限时vLLM 会开始排队TTFT 会陡增。这个拐点就是你当前配置下的容量上限。5. 常见报错排查401、local proxy failed 与 reading choices验证过程中最容易撞上几类报错我按出现频率排一下每个都给出定位思路。401 Unauthorized。这个最常见尤其是你通过自定义端点调用时。原因通常是三件套没配齐Base URL 写错、Key 失效、Model ID 不匹配。检查顺序是先确认 Base URL 是https://taotoken.net/api而不是首页地址再确认 Key 没有多余空格最后确认 Model ID 和实际模型名完全一致。如果用的是auth.json注意 JSON 格式不能有注释字段名大小写敏感。local proxy failed。这个报错通常出现在你配置了本地代理但代理没起来或者代理地址写错。排查方法是先确认本地服务端口是否监听curl http://localhost:8000/health。如果本地服务正常但客户端报 proxy failed检查客户端的代理配置是否指向了错误的端口。另一个可能是环境变量HTTP_PROXY或HTTPS_PROXY干扰了本地请求临时 unset 掉再试。Error reading choices / reading choices。这是 OpenAI 兼容接口返回格式解析失败。常见原因是服务端返回了非标准 JSON比如错误信息被包在了 HTML 里。先用 curl 直接打接口看原始返回curl -v http://localhost:8000/v1/chat/completions \ -H Content-Type: application/json \ -d {model:Qwen/Qwen2.5-7B-Instruct,messages:[{role:user,content:hi}]}如果返回的是 500 错误页而不是 JSON说明服务端崩了去看 vLLM 的日志。如果是 JSON 但结构不对检查客户端 SDK 版本是否和服务端 API 版本匹配。OAuth 相关报错。如果你用 Claude Code 接入可能会遇到 OAuth token 过期或 scope 不足。这类问题通常需要重新走一遍授权流程或者检查auth.json里的 token 是否还在有效期内。注意不要手动改 token 内容格式错了会直接 401。显存 OOM 但公式算下来够用。这种情况多半是碎片化或者gpu_memory_utilization设太高。vLLM 的 PagedAttention 虽然能减少碎片但 block 管理本身有开销。把gpu_memory_utilization从 0.95 降到 0.85 试试或者调小max_num_seqs。另外swap_space设太小也会导致 OOM因为它决定了 CPU 侧能换出多少 KV Cache。Prefix Caching 命中率始终为 0。检查三点前缀是否超过 block_size16 token前缀内容是否完全一致包括空格和换行是否每次请求都带了不同的 system prompt。如果前缀里有时间戳、随机 ID 这类动态内容哈希永远对不上缓存自然不命中。排查的核心思路是先确认服务本身健康再确认请求格式正确最后才怀疑缓存逻辑。大部分问题出在前两步。6. 从 KV Cache 到推理架构下一步怎么走把上面的步骤跑通后你对 KV Cache 的显存占用和 Prefix Caching 的复用逻辑应该有了实感。接下来可以往两个方向深入。第一个方向是量化 KV Cache。FP16 存 KV 是默认做法但 FP8 甚至 INT8 量化能把显存直接砍半。vLLM 支持--kv-cache-dtype fp8代价是轻微的质量损失。对于长上下文场景这个 trade-off 通常划算。你可以用同样的验证脚本对比 FP16 和 FP8 下的 TTFT 和输出质量找到适合自己业务的平衡点。第二个方向是分布式 KV Cache。单机显存总有上限Mooncake、TokenLake、FlexKV 这些方案的核心思路都是把 KV Cache 从 GPU 显存卸载到 CPU DRAM、SSD 甚至远端存储用存储换计算。如果你要做多轮对话或 RAG 服务前缀复用率很高分布式缓存的收益会非常明显。入门可以先看 vLLM 的--swap-space和--cpu-offload-gb参数感受一下卸载的效果再考虑更复杂的架构。如果你需要持续做编码或 Agent 任务建议把验证环境固定下来用 Coding Plan 做长期调用入口在 https://taotoken.net/coding-plan 。这样你不用每次重新搭环境也能积累自己的缓存命中数据。模型对话入口在 https://taotoken.net/api 适合快速对比不同模型的行为。API Key 管理在 https://taotoken.net/api-keys 接入文档在 https://taotoken.net/doc Claude Code 的配置参考 https://taotoken.net/claude-code-anthropic 。最后留一个实用技巧在压测时把max_model_len设成你实际需要的 1.2 倍不要直接拉满。留出的余量能吸收突发长请求避免因为单条超长请求把整个服务的 KV Cache 池挤爆。这个习惯能帮你省下很多半夜排查 OOM 的时间。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询