首页/新闻资讯/正文详情

从 Q/K/V 到 KV Cache 与缓存命中:大模型推理缓存机制详解

发布时间:2026/9/24 8:38:28 来源:云帆数科 栏目:资讯中心
从 Q/K/V 到 KV Cache 与缓存命中:大模型推理缓存机制详解
本文以主流 decoder-only 自回归 Transformer 为例梳理 Q/K/V 的计算方式、KV Cache 的作用以及服务指标中“缓存命中”的确切含义。不同模型在位置编码、注意力变体、KV Cache 布局上可能有所差异但主干逻辑一致。一、结论先行在展开细节之前先给出几个关键结论模型参数是预定义的(W_Q、W_K、W_V)、FFN、LayerNorm 等权重在训练完成后固定不变。Q/K/V 是运行时计算的每个 token 在每一层、每个注意力头中都会根据当前隐藏状态和该层权重动态算出 Q、K、V。Q 用于查询K 用于被查询V 用于被加权取内容。每个输入 token 在每一层都要计算输出而非只计算最后一个 token。层与层之间传递的是隐藏状态序列。下一层拿到上一层所有位置的输出后用自己的权重重新计算下一层的 Q/K/V。Q 用完即弃K/V 被缓存。未来新 token 的 Q 会反复查询历史 K并加权历史 V。预测下一个 token 只用最后一层最后一个位置的输出经过 LM Head 映射到词表。单次生成中的 KV Cache 不叫缓存命中。服务指标中的缓存命中通常指跨请求复用相同前缀的每层 K/V。下面逐层展开。二、Q/K/V 是什么如何计算输入文本先被 tokenizer 切分为 token。每个 token 先经过 embedding 层变成一个向量。进入 Transformer 后每一层都会进行线性投影[Q H W_Q][K H W_K][V H W_V]其中(H) 是当前层的输入隐藏状态(W_Q、W_K、W_V) 是该层、该注意力头训练好的权重(Q、K、V) 是运行时根据 (H) 算出的。因此预定义的是权重矩阵不是 Q/K/V 本身。不同输入、不同请求、不同层、不同头算出的 Q/K/V 都不同。注意力计算可简写为[\text{Attention}(Q,K,V)\text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}M\right)V]其中 (M) 是因果 mask保证当前位置只能看到自己及之前的 token。直观理解Q当前 token 想查询什么K历史 token 能被什么查询到V历史 token 实际提供的内容。Q 与 K 匹配出权重权重再用来加权 V。三、每个输入 token 都要计算输出这是最容易产生困惑的地方。在 Transformer 中并非只计算最后一个 token。每一层都会对所有位置并行计算得到一组输出向量输入今天 天气 很 好 第 1 层输出h1_今天, h1_天气, h1_很, h1_好 第 2 层输出h2_今天, h2_天气, h2_很, h2_好 ... 第 N 层输出hN_今天, hN_天气, hN_很, hN_好这些输出不是文字也不是 token而是高维向量。它们代表每个 token 在当前层、当前上下文下的表示。为什么每个位置都要计算因为下一层需要上一层所有位置的输出作为输入。下一层拿到这些输出后会用它自己的 (W_Q、W_K、W_V) 重新计算下一层的 Q/K/V[Q^l H^{l-1} W_Q^l][K^l H^{l-1} W_K^l][V^l H^{l-1} W_V^l]也就是说下一层不是直接使用上一层的 K/V而是根据上一层每个 token 的输出重新计算下一层自己的 K/V。如果上一层只输出了最后一个位置下一层就没有其他位置的输入无法计算它们的 K/V最后一个位置的 Q 也无法与它们做注意力。因此每一层都必须把所有位置算完。四、层是什么一层通常指一个 Transformer Block常见结构为输入 ↓ LayerNorm ↓ 多头自注意力 ↓ 残差连接 ↓ LayerNorm ↓ 前馈网络 FFN ↓ 残差连接 ↓ 输出大模型会堆叠很多这样的层。每一层都有自己独立的参数自己的 (W_Q、W_K、W_V)、自己的 FFN、自己的 LayerNorm。因此一个 token 在每一层都会产生一组新的 Q/K/V。KV Cache 缓存的也是每一层自己的历史 K/V层与层之间不共享。五、Prefill 与 DecodeKV Cache 的产生自回归生成分为两个阶段。5.1 Prefill 阶段用户输入 prompt例如今天 天气 很 好模型一次性处理整个输入。每一层中每个 token 根据当前隐藏状态算出 Q/K/V每个位置的 Q 查询同层因果可见范围内的 K用注意力权重加权对应的 V得到该位置在当前层的输出把该层所有 token 的 K/V 存入 KV CacheQ 用完即弃不长期保存。最后一层最后一个位置的输出经过 LM Head得到词表上的概率分布采样出第一个新 token。5.2 Decode 阶段生成第一个新 token 后例如“”“”作为新 token 进入模型在每一层它根据自己的输入算出自己的 Q/K/V它的 Q 查询该层 KV Cache 中所有历史 K用注意力权重加权所有历史 V得到该层输出传给下一层最后一层输出经过 LM Head预测再下一个 token把“”在该层的 K/V 追加到 KV Cache。然后循环。因此旧 token 的 Q 用完就丢旧 token 的 K/V 被缓存新 token 会自己算新的 Q。KV Cache 里只有 K 和 V没有 Q。六、KV Cache 缓存了什么KV Cache 缓存的是每一层、每个历史 token 的 Key 和 Value。以 32 层模型为例第 1 层到第 32 层各自维护自己的历史 K/V。生成新 token 时它会在每一层用自己的 Q 查询该层的历史 K并加权该层的历史 V。KV Cache 的显存占用通常与层数、注意力头数、序列长度、每个头的维度、精度等因素有关。序列越长KV Cache 越大这也是长上下文推理昂贵的重要原因之一。七、缓存命中是什么在 LLM 服务中“缓存命中”通常不是指单次生成中的 KV Cache 使用而是指跨请求复用相同前缀的 KV Cache也称为 Prefix Caching 或 Prompt Caching。例如请求 A系统提示 S 用户问题 U1请求 B同一个系统提示 S 用户问题 U2。如果 S 完全相同请求 A 在 prefill 阶段已经把 S 在每一层的 K/V 算出来并缓存。请求 B 就可以直接复用 S 的每层 K/V只计算 U2 新增部分的 Q/K/V。命中后不需要重新 prefill S不需要重新计算 S 的 Q/K/V首 token 延迟 TTFT 明显降低吞吐提升重复前缀的 prefill 算力被节省。但要注意缓存命中复用的是前缀的每层 K/V不是 Q不是回答文本也不是隐藏状态本身。对 decode 阶段的 TPOT 帮助有限因为每步仍然要读取全部 KV。Prefix cache 通常要求从第一个 token 开始连续匹配常见条件包括tokenizer 相同、模型权重和版本相同、chat template 相同、位置编码与精度一致、前缀 token ID 完全一致、缓存分块对齐、缓存未过期等。工程上建议将固定内容放在前面动态内容放在后面保持模板和工具顺序稳定以提高命中率。八、综合实例假设一个简化模型只有 2 层。有两个请求请求 A系统提示 S 用户问题 U1请求 B同一个系统提示 S 用户问题 U2。其中S “你是严谨的助手” U1 “什么是 KV Cache” U2 “什么是注意力”8.1 请求 A第一次 prefill输入 token 序列你是 严谨 的 助手 什么 是 KV Cache 第 1 层对每个 token用 embedding 得到初始隐藏状态 (h^0)用第 1 层的 (W_Q1、W_K1、W_V^1) 算出每个位置的 (q1、k1、v^1)在因果注意力下每个位置的 Q 只能查询自己及之前的 K用注意力权重加权对应的 V得到第 1 层每个位置的输出 (h^1)把第 1 层所有 token 的 (k1、v1) 存入 KV Cache丢弃 (q^1)。第 2 层把第 1 层所有位置的输出 (h^1) 作为输入。第 2 层不直接使用第 1 层的 K/V而是用自己的 (W_Q2、W_K2、W_V^2)根据 (h^1) 重新计算 (q2、k2、v^2)再做注意力得到第 2 层每个位置的输出 (h^2)。把第 2 层所有 token 的 (k2、v2) 存入 KV Cache丢弃 (q^2)。预测第一个新 token取最后一层、最后一个位置的输出 (h^2_{\text{}})经过 LM Head[\text{logits} h^2_{\text{}} W_{LM}]再 softmax得到词表概率分布采样出第一个回答 token。Decode 循环新 token 进入模型第 1 层算自己的 (q1、k1、v1)(q1) 查第 1 层缓存中的历史 K加权历史 V输出 (h^1)把新 (k1、v1) 追加到第 1 层缓存。第 2 层拿第 1 层输出 (h^1)算自己的 (q2、k2、v2)(q2) 查第 2 层缓存中的历史 K加权历史 V输出 (h^2)把新 (k2、v2) 追加到第 2 层缓存。最后一层输出经过 LM Head预测下一个 token。8.2 请求 B缓存命中请求 B 的输入是 S U2。如果 S 的 token 序列与请求 A 完全一致并且满足 tokenizer、模型、模板、分块对齐等条件那么 Prefix Cache 可以命中。命中后直接复用请求 A 中 S 在第 1 层的 (k1、v1)以及在第 2 层的 (k2、v2)。不需要重新 prefill S不需要重新计算 S 的 Q。只需要计算 U2 新增 token 在每一层的 Q/K/V。U2 的 Q 会查询 S 的缓存 K 以及 U2 内部的历史 K。最后一层最后一个位置输出经过 LM Head预测回答。命中的是 S 在每一层的 K/V不是 S 的 Q不是隐藏状态也不是回答文本。8.3 实例中的关键点回顾通过这个例子可以清晰地看到输入 token 的 K/V 对同一模型和输入是确定的但它们是运行时算出的不是预定义的。Q 用于查询这些 K/V没有 Q 就无法决定从哪些历史 token 取多少信息。输入 token 的 Q 不是用来直接预测下一个 token而是用来计算该 token 在当前层的上下文表示。每个位置都要更新自己的表示下一层才能继续处理。每一层都需要所有位置的输出因为下一层要根据这些输出重新计算自己的 Q/K/V。如果只算最后一个位置下一层就缺少其他位置的输入。层间传递的是隐藏状态下一层用自己的权重重新计算 Q/K/V而不是直接使用上一层的 K/V。第一个新 token 来自最后一层最后一个位置的输出经过 LM Head 和采样得到。旧 Q 丢弃不影响新 token 进入模型后会自己计算新的 Q/K/V。缓存命中复用相同前缀在每一层的 K/V跳过的是重复前缀的 prefill 计算。九、常见误解误解KV 是系统提前定义好的。纠正提前定义的是模型权重KV 是运行时根据输入动态计算的。误解每个输入 token 只算最后一个。纠正每一层所有位置都要算输出最后一层最后位置才用于预测下一个 token。误解下一层直接使用上一层的 K/V。纠正下一层拿到上一层所有位置的输出用自己的权重重新计算下一层的 Q/K/V。误解Q 也需要缓存。纠正Q 只用于当前层当前 token 的输出用完即弃。未来 token 只查询历史 K/V。误解缓存命中命中 Q 或回答。纠正Prefix cache 命中通常指复用前缀在每一层的 K/V。误解输入 token 的 Q 用来预测下一个 token。纠正预测下一个 token 只用最后一层最后位置的输出输入 token 的 Q 用于计算它自己在该层的上下文表示。十、总结模型参数是提前训练好的Q/K/V 是运行时根据输入和已生成 token 动态算出的。每一层都计算所有位置的输出层间传递隐藏状态下一层重新计算自己的 Q/K/V。Q 用完即弃K/V 被缓存供未来新 token 的 Q 查询。预测下一个 token 只用最后一层最后位置的输出。缓存命中指的是跨请求复用相同前缀在每一层的 K/V从而跳过重复 prefill降低首 token 延迟并提升吞吐。

相关推荐

convex-backend 自托管日志治理:REDACT_LOGS_TO_CLIENT 日志脱敏与 DISABLE_BEACON 遥测关闭指南
convex-backend 自托管日志治理:REDACT_LOGS_TO_CLIENT 日志脱敏与 DISABLE_BEACON 遥测关闭指南

数据库后端 【免费下载链接】convex-backend The open-source reactive database for app developers 项目地址: https://gitcode.com/gh_mirrors/co/convex-backend 点击查看 免费下载 自托管部署 convex-backend 时,默认行为与云托管产品存在差异&… · 2026/9/24 8:38:28

Spectrum Hyperion 服务端渲染(SSR)开发指南:从双进程本地开发到生产级渲染架构
Spectrum Hyperion 服务端渲染(SSR)开发指南:从双进程本地开发到生产级渲染架构

后端前端即时通讯社交 【免费下载链接】spectrum Simple, powerful online communities. 项目地址: https://gitcode.com/gh_mirrors/sp/spectrum 点击查看 免费下载 Hyperion 是 Spectrum 项目中负责服务端渲染(Server-Side Rendering,SSR&… · 2026/9/24 8:38:28

RUST图解 第 1 章:入门(Getting Started)
RUST图解 第 1 章:入门(Getting Started)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 8:37:57

Link入门全解:网页新标签打开、网络链路聚合与PLC通信协议
Link入门全解:网页新标签打开、网络链路聚合与PLC通信协议

做技术这行久了你会发现,很多基础概念翻来覆去就那么点东西,但每次重新回头去理解,又总能有新的收获。“Link”这个词就是典型,它算得上是我入行以来接触频率最高的词之一,但不同场景下它代表的东西完全不一样——前端… · 2026/9/24 18:45:38

Python气象时间序列预测实战:降雨量建模与工程化部署
Python气象时间序列预测实战:降雨量建模与工程化部署

简介:本资源是一个面向高校课程设计与Python后端开发初学者的降雨量预测实践项目,聚焦时间序列分析在气象预测中的落地应用,解决农业灌溉规划、气象预警等实际场景下的短期降雨趋势预判问题。压缩包为ZIP格式,大小42.49MB&#xf… · 2026/9/24 18:45:38

AI学术全流程实战:从文献综述到答辩PPT,提示词与部署排错指南
AI学术全流程实战:从文献综述到答辩PPT,提示词与部署排错指南

上周帮一个研三的学弟过开题材料,他跟我抱怨:AI工具他一直在用,翻译文献、润色语句、查语法,样样都试过,可真到了写综述、搭方案、做答辩PPT的时候,还是抓瞎。我问他怎么不用AI继续帮忙,他说“每… · 2026/9/24 18:45:38

无线网络仿真从入门到实战:信道建模与工具选型全解析
无线网络仿真从入门到实战:信道建模与工具选型全解析

1. 仿真思路拆解:为什么无线网络离不开仿真做无线网络这么多年,我越来越觉得网络仿真不是“锦上添花”的选修课,而是必修课。真实环境里你不可能为了验证一个组网方案,专门去买几十台AP、搭一整套AC、再拉几条专线做测试&#xff… · 2026/9/24 18:45:25

Spring Boot + Vue3 + MinIO 大文件分片上传实战:直传、断点续传与秒传
Spring Boot + Vue3 + MinIO 大文件分片上传实战:直传、断点续传与秒传

我接手过好几个类似需求的项目,从早期做后台管理系统开始就一直在跟文件上传打交道。以前用传统的MultipartFile整包上传,文件小的时候还行,一旦涉及到几百MB甚至几个GB的视频、压缩包、数据库备份文件,问题就全冒出来了&#xff… · 2026/9/24 18:45:25

Linux命令行删除全攻略:从输入纠错到卸载软件一次讲透
Linux命令行删除全攻略:从输入纠错到卸载软件一次讲透

说句实话,第一次在群里看到“在Linux中如何删除命令行?”这个问题的时候,我以为对方在开玩笑。毕竟命令行是Linux里最核心的交互入口,哪有人会想把它“删掉”?可后来聊了几句才明白,新手们说的“删除命令行… · 2026/9/24 18:45:25

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13

1D-CNN时间序列建模实战:从Conv1d原理到工业落地
1D-CNN时间序列建模实战:从Conv1d原理到工业落地

简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26

柔软的L:汉语语流中被忽视的舌肌张力控制
柔软的L:汉语语流中被忽视的舌肌张力控制

1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码