☰
LLM 推理部署优化:KV Cache、前缀缓存与推测解码的工程组合
2026/10/15 8:27:02 网站建设 项目流程

LLM 推理部署优化:KV Cache、前缀缓存与推测解码的工程组合

为什么"模型能跑"不等于"服务能用"

大模型真正进入生产环境以后,最容易被低估的问题不是"模型能不能跑起来",而是"每生成一个 Token 到底要花多少钱、要等多久"。实验环境中单次请求跑得快、显存占得满,并不意味着线上服务具有好的经济性。生产环境面对的是持续到来的并发请求、长度差异巨大的 Prompt、不断增长的 KV Cache,以及首字延迟(TTFT)、逐字延迟(TPOT)、吞吐量和显存利用率之间复杂的权衡。

尤其对于长上下文和高并发场景,模型权重本身反而不一定是第一瓶颈。随着请求数量和上下文长度增长,KV Cache 会迅速占据大量 GPU 显存,并进一步限制批大小、并发数和整体吞吐。因此,推理优化不能简单理解为"把模型从 FP16 换成 INT4",真正有效的优化来自一个完整推理栈的协同:量化、PagedAttention、KV Cache 管理、连续批处理、前缀缓存、内核优化、并发调度、硬件利用率优化。

先理解一个事实:LLM 推理为什么昂贵

Transformer 的自回归生成过程分为两个阶段。Prefill(预填充)负责处理用户提交的 Prompt——假设系统提示词 200 token、用户上下文 5000 token、问题 200 token,总共 5400 token 需要一次性并行计算,这个阶段是计算密集型的。Decode(解码)阶段则完全不同——假设要生成 500 token,每一步生成下一个 token 都依赖之前已经生成的内容,是典型的自回归过程。

KV Cache 的核心价值就在这里:已经计算过的 Key 和 Value 不需要每个 Decode 步骤重新计算。这正是 KV Cache 成为现代 LLM 推理系统核心资源的原因——但同时,它也是显存消耗的大户。

KV Cache 为什么特别吃显存

假设一个模型有 32 层、8 个 KV 头、每头维度 128、FP16 精度,那么每个 token 的 KV Cache 大约是 32×8×128×2(K 和 V)×2(字节数)≈ 128KB。一个请求上下文达到 8192 token,就需要约 1GB 的 KV Cache。如果同时有 16 个请求,理论上就需要接近 16GB——所以在长上下文、高并发服务中,真正限制并发能力的往往不是模型权重,而是 KV Cache。

现代模型大量使用 GQA(分组查询注意力)或 MQA(多查询注意力)来缓解这个问题。以 Query Heads = 32、KV Heads = 8 为例,KV Cache 的头数不是 32 而是 8,理论上可以把 KV Cache 的这部分降低到 25%。这也是 GQA 对推理系统非常重要的原因——选模型时,KV Head 数量是一个值得关注的推理成本指标。

PagedAttention:把 KV Cache 像虚拟内存一样管理

最早的推理实现为每个请求分配连续显存,问题是请求长度不固定——如果按最大长度预分配,产生大量浪费;动态扩容,又容易产生显存碎片。

vLLM 的 PagedAttention 借鉴操作系统虚拟内存的分页机制,把 KV Cache 切成多个固定大小的块(Block),通过块表(Block Table)建立逻辑块到物理块的映射。逻辑上连续、物理上离散,请求需要多少块就分配多少,请求结束立即释放供其他请求复用。这一机制把显存碎片显著降低,让 GPU 显存更充分地服务于真实 token。

Continuous Batching:不要等待整个 Batch 结束

传统静态批处理按最长请求同步执行,短请求被迫等待,GPU 计算资源大量浪费。连续批处理(Continuous Batching)把请求生命周期拆开:某个请求完成后立即退出 batch,新请求立即进入,GPU 在每一个迭代中都可以尽可能装载更多可执行请求。配合 PagedAttention 的抢占式调度,长请求可以被挂起并恢复,不会阻塞短请求。

生产调优时要注意:不要盲目追求最大 batch。batch 增大通常意味着吞吐上升、显存占用上升、排队延迟上升、首字延迟可能上升。真正应该关注的是"每迭代处理的 token 数"(max-num-batched-tokens)而不是"并发请求数"(max-num-seqs),两者要联合调节。

Prefix Caching:重复 Prompt 不要重复计算

很多企业应用存在高度重复的 Prompt——系统提示词、知识库规则、工具定义、Agent 指令,前面几千 token 可能完全相同。如果每次请求都重新 Prefill,这是明显的浪费。

前缀缓存(Prefix Caching)的思想是:第一次请求计算前缀并保存 KV,后续请求匹配到相同前缀时直接复用 KV,只计算新增内容。效果是首字延迟下降、GPU 计算减少、成本下降。对聊天机器人、Agent、RAG、企业知识库这类固定系统提示词和大量工具定义的场景尤其有效。

落地时要注意缓存命中率:如果前缀里混了时间戳、用户 ID 这类每次变化的字段,缓存永远命中不了,等于没开。

Chunked Prefill:解决长 Prompt 阻塞 Decode

一个典型问题:当前有 100 个 Decode 请求,突然来了一个 10 万 token 的 Prompt。如果直接完整 Prefill,GPU 被长时间占用,Decode 请求全部等待,用户感知延迟暴涨。

Chunked Prefill 把长 Prompt 拆成多个块,让 Prefill 和 Decode 合理地共享 GPU 计算资源——每个迭代既处理部分 Decode,又处理一个 Prefill 块。这解决的是吞吐与交互延迟之间的调度问题。所以生产系统不能只看 tokens/s,还必须同时观察 TTFT、ITL/TPOT、P99 延迟、排队时间和吞吐量。

量化:降低模型权重成本

如果模型采用 BF16(每参数 2 字节),一个 70B 模型的权重理论存储约 140GB。用 INT4 量化后降到约 35GB——同样的 GPU 集群可以运行更大的模型,或者运行更多副本。常见量化方案包括 FP8、INT8、INT4、GPTQ、AWQ。

但一个反直觉的事实是:不能简单认为 INT4 一定比 FP8 快。量化影响的不只是显存,还涉及内存带宽、计算吞吐、内核效率、反量化开销、Tensor Core 利用率、精度。FP8 在现代 NVIDIA GPU 上有成熟的硬件支持,某些 INT4 格式虽然更省显存,但如果对应内核不够高效,最终吞吐不一定更好。量化选型应该通过实际 Benchmark 决定,而不是根据位宽数字大小决定。

推测解码:用小模型换大模型的延迟

推测解码(Speculative Decoding)采用 Draft-Target 范式:一个小模型(Draft)快速自回归生成 k 个候选 token,大模型(Target)一次前向并行验证这些候选——接受的 token 直接输出,被拒绝的从分歧点重新生成。由于大模型一次前向验证多个 token,而小模型生成速度快,整体解码速度可以提升 2~3 倍。

生产落地时要注意监控接受率(Acceptance Rate)——它决定推测解码的实际收益。接受率低(比如小模型和大模型风格差异大)时,推测解码可能不如直接解码。一般建议小模型选择与大模型同源或同族的较小版本,接受率会明显更高。

完整优化路径与监控

生产部署建议从一个保守配置开始,然后根据压测结果逐步调整。典型调优路径:固定模型、固定 Prompt、固定输出长度,然后测试不同并发,观察 TTFT/TPOT,再联合调整 max-num-seqs 和 max-num-batched-tokens。显存利用率不要一上来就顶到 0.98——GPU 显存里除了模型权重还有 KV Cache、CUDA 运行时、临时缓冲、激活值、内核工作区,压得过满会出现难以排查的偶发 OOM。更合理的方法是从 0.85 到 0.90 到 0.92 逐级压测。

监控层面,集成 Prometheus 记录 KV 缓存使用率、运行中请求数、批 token 数、吞吐等指标,便于自动扩缩容和预警。有一句话值得刻在监控面板上:生产系统不能只看单点指标,吞吐、延迟、成本三者必须放在一起看——牺牲任何一方换来的"优化",最终都要加倍还回去。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询