第4章 大模型推理机制详解:Prefill、Decode、Sampling、KV Cache 与 Reasoning Budget
LLM 推理不是简单的“跑一次模型”。对自回归模型来说,生成文本是一个循环:每次预测下一个 token,把它追加到上下文,再继续预测下一个 token。
本章先从宏观上理解推理流程,再看工业界如何优化 serving,最后看 KV cache、speculative decoding、paged memory、reasoning budget、量化和长上下文相关研究。
4.1 宏观理解:一次生成是怎么发生的
输入 prompt 后,模型并不是一次性吐出完整答案,而是一步步生成:
flowchart LR
A["Prompt"] --> B["Prefill"]
B --> C["Logits for next token"]
C --> D["Sampling / Decoding"]
D --> E["New token"]
E --> F["Append to context"]
F --> G["Decode next token"]
G --> C
每一步都会产生一个 logits 向量。logits 可以理解成“词表里每个 token 作为下一个 token 的未归一化分数”。经过 softmax 后,它变成概率分布。
4.2 Prefill 与 Decode
LLM 推理通常分为两个阶段。
4.2.1 Prefill
Prefill 是处理输入 prompt 的阶段。
假设用户输入了 4K token,模型会一次性处理这些 token,计算每层 attention 的 Key / Value,并得到最后一个位置的 next-token logits。
这个阶段通常并行度高,更像大矩阵计算。prompt 越长,prefill 越慢,TTFT(Time To First Token,首 token 延迟)越高。
4.2.2 Decode
Decode 是生成输出 token 的阶段。
每一步 decode 只生成一个 token。模型会读取历史上下文,计算当前 token 对历史 token 的注意力,然后采样出下一个 token。
decode 阶段经常是 memory-bound:瓶颈不一定是算力,而是读取模型权重和 KV cache 的显存带宽。
4.3 Sampling:模型如何选择下一个 token
模型输出的是概率分布,但最终必须选出一个 token。
常见策略包括:
- Greedy decoding:每次选概率最高的 token,稳定但容易机械。
- Temperature:调节分布尖锐程度。低温更保守,高温更多样。
- Top-k:只在概率最高的 k 个 token 中采样。
- Top-p / nucleus sampling:只在累计概率达到 p 的 token 集合里采样。
- Repetition penalty:降低重复 token 的概率。
- Stop sequence:遇到特定 token 或字符串时停止生成。
工程上,sampling 参数决定输出的稳定性、创造性和可复现性。代码生成、SQL、JSON、函数调用通常需要更低温度;创意写作可以使用更高温度。
对于 reasoning model,推理还要多一个维度:reasoning budget。系统需要决定是否允许模型生成更长的内部思考、是否启用 verifier、是否允许多轮工具调用,以及什么时候因为成本、延迟或证据不足而停止。普通问答关注“选哪个 token”,复杂 Agent 任务还要关注“允许模型花多少推理计算”。
4.4 KV Cache 里的 KV 是什么
KV cache 是理解推理性能的核心概念。这里的 KV 不是数据库里的 key-value,而是 Transformer Attention 里的 Key / Value 向量。
Self-Attention 的简化公式是:
Attention(Q, K, V) = softmax(QK^T / sqrt(d)) V
对当前新 token 来说:
Q:当前 token 的 query;K/V:历史所有 token 在每一层 attention 中产生的 key/value;KV cache:把历史 token 的 K 和 V 存下来,下次生成时直接复用。
没有 KV cache 时,每生成一个新 token,都要重新计算整段上下文的 K/V。
有 KV cache 时:
- prefill 阶段一次性处理 prompt,把所有历史 token 的 K/V 存起来;
- decode 阶段每生成一个新 token,只算这个新 token 的 K/V,然后追加到 cache。
所以 KV cache 的本质是:
用显存换速度。
4.5 KV Cache 的显存成本
KV cache 让 decode 快很多,但显存会线性增长:
KV cache size ≈ 2 × layers × batch × seq_len × kv_heads × head_dim × bytes
其中:
2是 Key 和 Value;layers是模型层数;batch是同时服务的序列数;seq_len是上下文长度,包括输入和已生成输出;kv_heads是 Key / Value head 数;head_dim是每个 head 的维度;bytes是每个元素的字节数,例如 FP16/BF16 通常是 2。
一个直觉例子:
假设模型有 32 层、32 个 KV heads、head_dim = 128,使用 FP16:
每个 token 的 KV cache ≈ 2 × 32 × 32 × 128 × 2 = 512 KB
那么:
- 4K context 约等于 2 GB;
- 32K context 约等于 16 GB。
这还只是一个请求。如果并发多个长上下文请求,KV cache 会迅速成为推理服务的主要显存瓶颈。
4.6 为什么长上下文会降低吞吐
长上下文有三个直接影响:
- prefill 更慢,首 token 延迟更高;
- decode 每一步都要读取更长的 KV cache;
- KV cache 占用显存,减少可同时服务的请求数。
在短 prompt、低并发场景里,模型权重可能是主要显存占用。在长上下文、高并发场景里,KV cache 往往更接近 serving capacity 的决定因素。
这就是为什么“支持 128K context”和“128K context 下高吞吐稳定服务”是两件事。
4.7 工业实践:Serving Engine 在优化什么
生产级 LLM serving 关注的是端到端指标:
- TTFT:首 token 延迟;
- TPOT:每个输出 token 的延迟;
- tokens/s:吞吐;
- QPS:请求吞吐;
- GPU memory watermark:显存水位;
- cache hit rate:prefix cache 命中率;
- queueing delay:排队延迟。
常见 serving engine 包括 vLLM、TensorRT-LLM、SGLang、Hugging Face TGI、llama.cpp、LMDeploy 等。它们的优化重点不完全相同,但都会围绕 batch、KV cache、kernel、quantization 和调度展开。
4.8 PagedAttention 与 Paged KV Cache
vLLM 的 PagedAttention 把每个请求的 KV cache 切成固定大小的 block/page,不要求连续显存,类似操作系统分页。
好处包括:
- 减少显存碎片;
- 支持 continuous batching;
- 支持 prefix sharing;
- 更容易处理不同长度序列;
- 支持 beam search 等场景下的 cache 共享。
这类设计把 KV cache 从“请求私有的大块连续内存”变成“由 serving engine 管理的 block 资源”。
4.9 Continuous Batching 与 In-flight Batching
传统 batching 会等一批请求一起开始、一起结束。LLM 生成长度差异很大,短请求会被长请求拖住。
Continuous batching / in-flight batching 允许新的请求在每个 decode step 加入 batch,也允许完成的请求离开 batch。
这提升 GPU 利用率,但要求调度器实时管理:
- 哪些请求处于 prefill;
- 哪些请求处于 decode;
- batch token 数是否超限;
- KV cache 空间是否足够;
- 长请求是否挤占短请求;
- 是否需要抢占、暂停或降级。
4.10 Prefix Reuse 与 Prompt Caching
很多请求共享相同前缀,例如:
- system prompt;
- 工具 schema;
- few-shot 示例;
- 项目规范;
- 长文档开头;
- 多轮对话中的稳定上下文。
Prefix caching 可以复用这部分前缀的 KV cache,减少重复 prefill。
但它有正确性风险:
- token 序列必须完全一致;
- 位置和 chat template 必须一致;
- 多租户、权限和安全边界不能混淆;
- 工具 schema 版本变化后不能复用旧 cache。
4.11 模型结构层面的优化:MQA、GQA、MLA
KV cache 大小和 kv_heads 成正比。
因此模型结构也会影响推理成本:
- MHA:每个 query head 有自己的 K/V head,表达力强但 KV cache 大。
- MQA:多个 query heads 共享一组 K/V head,KV cache 小但可能影响质量。
- GQA:多个 query heads 分组共享 K/V head,是现代模型常用折中。
- MLA:把 K/V 信息压缩到 latent 表示,进一步降低 KV cache 成本。
这类优化通常比单纯换 serving engine 更底层,因为它改变了模型本身的推理内存结构。
4.12 KV Cache 实现策略
Hugging Face Transformers 中有多种 cache 策略:
DynamicCache:动态增长,灵活;StaticCache:预分配,利于编译优化;QuantizedCache:降低 KV 精度以节省显存;- offloaded cache:把部分 cache 放到 CPU,降低 GPU 显存压力。
这些策略对应不同 trade-off:
- 灵活性;
- 编译友好性;
- 显存占用;
- PCIe / NVLink 带宽;
- 输出质量;
- tail latency。
4.13 Kernel 优化
FlashAttention、FlashInfer 等库会针对 prefill、decode、paged KV layout、ragged sequence 做专门 kernel。
核心目标是减少 HBM 读写和中间张量,提升 attention 的实际吞吐。
同一个模型、同一张 GPU、同样的上下文长度,在不同 kernel 和 serving engine 上可能有明显吞吐差异。
4.14 科研现状:KV Cache 与推理优化
截至 2026-05,推理优化研究主要集中在下面几类。
1. 更好的内存管理
PagedAttention 是主流路线。vAttention 则尝试利用虚拟内存机制保持 KV cache 虚拟连续、物理按需分配,降低对特殊 attention kernel 的依赖。
2. KV Cache 量化
KIVI、KVQuant、TurboQuant 等方法尝试把 K/V 从 FP16/BF16 压到 INT8、4-bit、2-bit 甚至更低。难点在于长上下文质量、outlier 处理和不同任务的稳定性。
3. KV Cache 剪枝与驱逐
H2O、SnapKV 等方法认为不是所有历史 token 都同等重要,可以保留 heavy hitter token、recent token 或 prompt 中的重要 token,驱逐低价值 KV。
风险是错误驱逐会造成不可恢复的信息损失,因此必须用目标任务 eval 验证。
4. Speculative Decoding
Speculative decoding 用小模型或 draft head 先生成候选 token,再由大模型验证。目标是在不显著损失质量的情况下减少大模型 forward 次数。
5. Disaggregated Prefill / Decode
一些 serving 系统开始把 prefill-heavy 和 decode-heavy workload 分开调度,甚至部署到不同 GPU 资源池。原因是 prefill 更偏 compute-bound,decode 更偏 memory-bound。
4.15 工程清单
设计推理服务时,可以检查:
- 是否区分 TTFT 和 TPOT?
- 是否统计输入长度、输出长度和并发分布?
- 是否估算了最大上下文下的 KV cache?
- 是否使用 GQA/MQA/MLA 等降低 KV heads?
- serving engine 是否支持 paged KV cache?
- 是否启用 continuous batching?
- 是否支持 prefix caching?
- 是否有超长 prompt 的 admission control?
- 是否有 cache eviction、offloading 或降级策略?
- sampling 参数是否按任务类型配置?
- JSON / tool calling 是否需要 constrained decoding?
4.16 设计评审表达
一句话版:
LLM 推理分为 prefill 和 decode。Prefill 处理输入并生成 KV cache,decode 一次生成一个 token 并复用历史 KV。KV cache 能显著加速生成,但显存随 batch size 和 context length 线性增长,所以工业界用 PagedAttention、continuous batching、prefix reuse、GQA/MQA/MLA、量化、offloading 和 cache-aware scheduling 优化。
展开版:
我会把推理性能拆成 prefill、decode 和 serving 调度三层。Prefill 决定首 token 延迟,decode 决定每 token 延迟,KV cache 决定长上下文和高并发下的显存容量。生产系统不会只优化单次 forward,而会用 paged KV cache 减少碎片,用 continuous batching 提高利用率,用 prefix caching 复用稳定前缀,用 GQA/MQA/MLA 降低 KV 大小,用量化和 offload 控制显存,并通过 eval 确认这些优化没有破坏质量。
4.17 深入理解:Prefill 和 Decode 的资源画像不同
Prefill 和 decode 不是同一种负载。
Prefill 会一次处理大量输入 token,矩阵乘法规模大,GPU 利用率通常较高。它的核心问题是首 token 延迟和长 prompt 带来的瞬时计算压力。
Decode 每次只生成一个 token,batch 中每个序列都要读取模型权重和自己的 KV cache。它的核心问题往往是显存带宽和 KV cache 管理,而不是纯 FLOPS。
这带来一个重要工程判断:
prefill-heavy workload 需要优化 prompt 处理和 chunked prefill
decode-heavy workload 需要优化 KV cache、batching 和 memory bandwidth
例如,文档问答通常 prefill-heavy,因为输入长、输出短。写长报告和 reasoning agent 通常 decode-heavy,因为输出和思考轨迹很长。代码 Agent 可能两者都重:上下文里有代码库片段,输出又可能包含长 patch 和多轮工具调用。
成熟 serving 系统会区分这两类负载,而不是把所有请求混进同一个 FIFO 队列。
4.18 深入理解:为什么 Decode 经常是 Memory-bound
在 decode 阶段,每生成一个 token 都要经过所有层。对于 batch size 不大的在线请求,矩阵乘法规模相对小,GPU 算力可能吃不满,但模型权重和 KV cache 仍要从显存读取。
因此瓶颈经常是:
- 模型权重读取;
- KV cache 读取;
- attention score 计算中的内存访问;
- batch shape 不规则导致 kernel 效率下降;
- 请求长度差异导致调度碎片。
这解释了为什么量化、GQA、KV cache 压缩、continuous batching 和 speculative decoding 都能提升推理性能。它们本质上都在减少每个输出 token 消耗的内存带宽、forward 次数或调度浪费。
也解释了为什么“换更强 GPU”不一定线性提升吞吐。如果 bottleneck 是显存容量、内存带宽或 batch 形状,单看 TFLOPS 会误判。
4.19 工业实践:调度器如何做取舍
LLM serving 的调度器要同时照顾吞吐和用户体验。它面对的不是统一长度的矩阵请求,而是一批动态增长的序列。
调度器通常要考虑:
- 一个 batch 中最多放多少 token;
- prefill 和 decode 是否分开调度;
- 超长请求是否限制并发;
- 是否允许抢占低优先级请求;
- KV cache 空间不足时如何处理;
- prefix cache 命中高的请求是否优先;
- streaming 响应如何避免尾延迟;
- 多租户如何做配额和隔离。
一个常见策略是把 prefill 以 chunk 的方式切开,避免单个超长 prompt 长时间占用 GPU;decode 则通过 continuous batching 尽量保持 GPU 忙碌。
但这也有代价:chunked prefill 会增加调度复杂度,过度追求吞吐可能拉高首 token 延迟,过度照顾短请求可能饿死长请求。
所以 serving 优化不是单指标问题,而是 SLA、成本和公平性的多目标优化。
4.20 深入理解:Prefix Cache 不是普通缓存
普通 Web 缓存通常以 URL 或 key 命中。Prefix cache 命中的是 token 前缀和对应的 KV block。
它有几个特殊点:
- cache 内容和模型版本绑定;
- cache 内容和 tokenizer / chat template 绑定;
- cache 内容和 position 绑定;
- cache 内容和 LoRA adapter 或 system prompt 版本绑定;
- cache 内容可能包含权限敏感信息。
因此 prefix cache 的设计不能只看命中率,还要看隔离和失效策略。
例如企业 Agent 的 system prompt 和工具 schema 可以缓存,但用户私有文档不一定能跨用户缓存。多租户场景下,即使 token 序列相同,如果权限域不同,也要谨慎复用。
4.21 研究补充:Reasoning 模型放大了 KV Cache 问题
reasoning 模型通常会生成更长的中间推理轨迹。这提升了复杂任务能力,但也放大了 decode 成本:
- 输出 token 更多;
- KV cache 持续增长;
- 长时间占用 batch slot;
- 请求之间长度差异更大;
- 并发下显存压力更强。
从系统角度看,test-time scaling 有两条路径:
- 纵向慢思考:模型在一次调用内部生成更长推理轨迹,用更多 token 搜索、验证和修正答案。
- 横向多轮环境交互:Agent 多次调用工具、读取观察、更新状态,再决定下一步。
两条路径都会消耗推理预算。前者主要放大 decode 和 KV cache 压力,后者还会放大工具延迟、状态管理、trace 记录、权限控制和失败恢复成本。
2026 年的 Zipage 这类工作把 compressed PagedAttention 和 token-wise KV eviction 结合起来,目标就是在 reasoning workload 下维持高并发。它反映了一个趋势:KV cache 优化正在从“单请求长上下文”走向“高并发长 reasoning”。
但这类方法落地必须问三个问题:
- 被压缩或驱逐的 KV 是否会影响最终答案?
- 压缩本身是否引入额外延迟?
- 是否兼容 prefix caching、paged memory 和现有 serving engine?
4.22 工程诊断:推理慢时怎么定位
线上推理慢,不要直接归因于模型太大。可以按下面路径诊断:
- 看 TTFT:高 TTFT 往往来自长 prompt、prefill 排队、chunked prefill 配置或冷启动。
- 看 TPOT:高 TPOT 往往来自 decode 带宽、batch 太小、KV cache 压力或 kernel 效率。
- 看 GPU 利用率:低利用率可能是 batch 不足、调度碎片或 CPU/tokenizer 瓶颈。
- 看显存水位:接近上限时,KV cache 可能限制并发。
- 看请求长度分布:少量超长请求可能拖垮 P99。
- 看 prefix cache 命中率:低命中说明 prompt 前缀不稳定或模板版本混乱。
- 看输出长度:reasoning 或 verbose prompt 可能让 decode 成本暴涨。
只有把这些指标拆开,才能判断该优化 prompt、换模型、改 sampling、加 batching、做量化,还是换 serving engine。
4.23 进阶设计推演:从单机推理到服务化推理
设计评审里如果只讲 KV cache 公式,答案还停留在模型层。更好的表达是:
单机推理关注一次 forward 怎么快;服务化推理关注多请求、多长度、多租户下如何稳定利用 GPU。KV cache 是连接模型层和系统层的关键状态,它既决定 decode 速度,也决定显存容量和调度策略。因此我会同时考虑模型结构、cache layout、batch scheduler、prefix reuse、admission control 和质量 eval。
这句话的好处是把你从“知道概念”提升到“知道系统怎么设计”。
4.24 常见误区:推理性能
误区 1:只看 tokens/s
tokens/s 是吞吐指标,但用户还关心 TTFT、TPOT、P95/P99 延迟、排队时间和失败率。一个系统平均 tokens/s 高,不代表交互体验好。
误区 2:以为 KV cache 是可选优化
对自回归 decode 来说,KV cache 是现代高效推理的基础。没有 KV cache,每步都重复计算历史上下文,长文本生成成本会不可接受。
误区 3:以为 prefix caching 会加速所有阶段
Prefix caching 主要减少重复 prefill。它不直接让后续 decode token 变快。长输出任务仍然会受 decode 和 KV cache 带宽限制。
误区 4:只靠量化解决 serving 问题
量化能降低权重或 KV cache 成本,但调度、batching、prefix cache、模型结构和 workload 分布同样重要。量化还可能带来质量退化。
4.25 专家问答
问:为什么有时 batch 变大,单请求延迟也变高?
batch 变大提升吞吐,但每个请求可能要等待同一批次或更多调度步骤。服务系统要在吞吐和延迟之间取舍,不能只追求 GPU 利用率。
问:为什么长 prompt 的首 token 慢?
因为 prefill 必须处理全部输入 token,并构建 KV cache。prompt 越长,首 token 之前要做的计算越多。
问:为什么 reasoning 模型更考验 serving?
它们输出更长,decode step 更多,KV cache 增长更久,占用 batch slot 时间更长。高并发下,reasoning token 会显著改变容量规划。
问:怎么快速估算是否会 OOM?
先估模型权重显存,再估目标 batch 和最大 seq_len 下的 KV cache,再加上激活、临时 buffer、CUDA graph、fragmentation 和 serving engine 预留。只看模型权重会严重低估长上下文成本。
4.26 容量规划案例:三种典型 Workload
1. 客服问答
特点:
- prompt 中等;
- 输出较短;
- 并发高;
- 对 TTFT 敏感;
- RAG 证据通常较短。
优化重点:
- prompt caching;
- hybrid retrieval 控制 evidence token;
- continuous batching;
- 小模型路由简单问题;
- 严格限制最大输出。
客服问答通常不需要特别长的 reasoning trace,过长输出反而降低用户体验。
2. 代码 Agent
特点:
- prompt 可能很长;
- 工具 schema 和项目上下文稳定;
- 多轮工具调用;
- 输出 patch 可能较长;
- 正确性比速度更重要。
优化重点:
- prefix cache 复用系统提示和工具说明;
- 项目上下文分层加载;
- 文件级检索;
- 长任务异步化;
- trace 和可恢复状态;
- 对 patch 做编译/测试验证。
代码 Agent 的成本不只在模型 token,还在工具执行、环境准备和失败恢复。
3. 长文档分析
特点:
- prefill-heavy;
- 输入长;
- 输出可能中等;
- 需要引用证据;
- 容易受中间位置遗忘影响。
优化重点:
- chunked prefill;
- map-reduce 或分层摘要;
- citation-aware context;
- 多阶段检索;
- 先抽取结构再综合;
- 控制单次上下文信息密度。
长文档分析不应该简单把全文塞进窗口,而应该先组织信息结构。
4.27 数字化估算:从模型配置到并发上限
假设一个 32 层模型,kv_heads=8,head_dim=128,FP16,单请求 16K context。
KV cache 约为:
2 × 32 × 1 × 16384 × 8 × 128 × 2 bytes
= 2 GB
如果 GPU 剩余可用显存 40 GB,理论上最多放 20 个这样的请求。但真实系统不能按理论值打满,因为还需要:
- 模型权重;
- 临时 buffer;
- CUDA graph;
- fragmentation;
- serving engine 预留;
- 不同请求长度差异;
- 输出继续增长后的 KV。
所以容量规划通常要保守,比如只按 60%-80% 可用 KV 空间做 admission control。
这个估算能力非常适合设计评审,因为它能把模型结构、显存和服务并发连起来。
4.28 专家实践:推理优化的优先级
当系统太慢或太贵时,可以按优先级尝试:
- 减少无效 token:压缩 system prompt、工具说明、RAG 噪声。
- 控制输出长度:限制 verbose 回答和无意义 reasoning。
- 启用 batching:提高 GPU 利用率。
- 启用 prefix cache:复用稳定前缀。
- 换模型结构:选择 GQA/MQA/MLA 更友好的模型。
- 量化权重:降低模型显存和带宽。
- 量化或压缩 KV cache:处理长上下文并发。
- speculative decoding:降低大模型 forward 次数。
- 分离 prefill/decode:处理大规模服务。
这个顺序的原则是先减少不必要工作,再优化必要工作。
4.29 参考资料
- Efficient Memory Management for Large Language Model Serving with PagedAttention
- vLLM Automatic Prefix Caching
- TensorRT-LLM KV Cache System
- TensorRT-LLM GPT Attention
- Hugging Face Transformers KV Cache Strategies
- FlashInfer Attention Kernels
- vAttention
- KIVI
- KVQuant
- H2O
- SnapKV
- TurboQuant
- Zipage: Maintain High Request Concurrency for LLM Reasoning through Compressed PagedAttention