前言

很多人接触大模型应用时,关注点通常放在 Prompt、RAG、Agent 或微调上。但当系统真正上线后,一个非常现实的问题会迅速暴露出来:

为什么模型回答这么慢?
为什么 GPU 利用率很低但请求还是排队?
为什么并发一上来,显存立刻爆掉?
为什么同样是 7B 模型,别人 QPS 比我高几倍?

这些问题背后对应的是一个非常具体的 AI 细分方向:大语言模型推理优化(LLM Inference Optimization)。

本文不讨论大模型训练,而聚焦于推理阶段,尤其是在线服务场景下的核心优化技术:KV Cache、PagedAttention、Continuous Batching、Prefill/Decode 分离、量化推理。这些技术是 vLLM、TensorRT-LLM、TGI 等推理框架的底层关键,也是企业部署大模型服务时必须理解的硬核内容。


一、大模型推理为什么慢?

大语言模型的生成过程和普通分类模型不同。分类模型通常是一次前向传播得到结果,而大模型生成文本是一个 自回归过程:

text

输入 Prompt -> 预测第 1 个 tokenPrompt + 第 1 个 token -> 预测第 2 个 tokenPrompt + 第 1、2 个 token -> 预测第 3 个 token...

也就是说,模型每生成一个 token,都要执行一次推理。

假设用户输入 1000 个 token,模型生成 500 个 token,那么整个请求可以拆成两个阶段:

  1. Prefill 阶段:处理输入 Prompt,计算所有输入 token 的上下文表示
  2. Decode 阶段:逐 token 生成,每次只生成一个 token

在实际服务中,Prefill 通常计算量大,Decode 通常访存压力大,并且 Decode 会持续占用 GPU 资源。很多线上推理瓶颈不是单纯的算力不足,而是计算、显存、访存和调度之间没有协调好。


二、KV Cache:避免重复计算注意力

Transformer 的核心是 Self-Attention。对于每一层,每个 token 都会生成 Query、Key、Value:

text

Q = XWqK = XWkV = XWv

在自回归生成中,新 token 只需要和历史 token 做注意力计算。问题是,如果每一步都重新计算历史 token 的 K/V,成本会非常高。

因此推理框架会使用 KV Cache:

把历史 token 在每一层的 Key 和 Value 缓存下来,后续生成时直接复用。

没有 KV Cache 时,生成第 t 个 token 需要重新计算前面所有 token 的 K/V;有了 KV Cache 后,只需要计算当前 token 的 K/V,然后和缓存中的历史 K/V 做 attention。

KV Cache 可以显著降低重复计算,但它也带来了新的问题:显存占用巨大。


三、KV Cache 显存到底有多大?

KV Cache 的显存消耗可以粗略估算:

text

KV Cache大小 ≈ batch_size × seq_len × num_layers × hidden_size × 2 × bytes

其中:

  • 2 表示 Key 和 Value
  • bytes 表示数据类型大小,例如 FP16 是 2 字节
  • seq_len 包含输入 token 和已生成 token
  • num_layers 是模型层数

以一个 7B 模型为例,假设:

  • 32 层
  • hidden size 4096
  • FP16
  • batch size 16
  • 每个请求上下文长度 4096

KV Cache 大小大约是:

text

16 × 4096 × 32 × 4096 × 2 × 2 bytes≈ 34GB

这还只是 KV Cache,不包括模型权重、激活、临时 buffer 等。

因此在大模型推理服务中,显存不是只被权重占满,KV Cache 往往才是并发能力的关键瓶颈。


四、传统 Batch 推理的问题

为了提高 GPU 利用率,推理服务通常会把多个请求合并成 batch。

普通 batch 的问题在于:不同请求长度不一样。

例如:

text

请求A:输入 100 token,生成 50 token请求B:输入 3000 token,生成 800 token请求C:输入 500 token,生成 100 token

如果简单 batch 到一起,会出现严重的 padding 浪费。短请求要等长请求,GPU 计算很多无效 token。

更严重的是,大模型 Decode 是逐 token 生成。一个 batch 中只要有请求还没生成完,batch 调度就会被拖住,导致吞吐下降、延迟上升。


五、Continuous Batching:动态批处理

为了解决传统 batch 的低效问题,现代推理框架引入了 Continuous Batching,也叫动态批处理或迭代级批处理。

它的核心思想是:

每一个 decode step 都可以动态加入新请求、移除已完成请求。

传统 batching 更像这样:

text

凑一批请求 -> 一起跑完 -> 再处理下一批

Continuous Batching 则是:

text

每一步 decode:    移除已完成请求    加入新等待请求    对当前活跃请求执行一次生成

这样做的优势非常明显:

  1. GPU 不会因为短请求结束而空转
  2. 新请求不用等整批老请求全部结束
  3. 吞吐量显著提升
  4. 请求延迟更加稳定

vLLM、TGI 等框架都大量使用了类似机制。


六、PagedAttention:像操作系统一样管理 KV Cache

KV Cache 最大的问题是连续显存分配困难。

传统方式通常为每个请求预留一整段连续 KV Cache 空间。但用户实际生成长度不可控,如果预留太少会不够,预留太多会浪费。

vLLM 提出的 PagedAttention 借鉴了操作系统虚拟内存分页思想:

  • 把 KV Cache 切成固定大小的 block
  • 每个请求不需要连续显存
  • 通过 block table 维护逻辑 token 到物理 block 的映射
  • 需要多少分配多少,释放也更灵活

这带来两个关键收益:

1. 降低显存碎片

多个请求的 KV Cache 可以分散存储,不要求连续空间,显存利用率更高。

2. 支持更高并发

由于不再为每个请求过度预留空间,同样显存可以容纳更多活跃请求。

简单理解:

text

传统KV Cache:每个请求占一大块连续空间PagedAttention:每个请求由多个小block组成

这就是为什么 vLLM 在很多场景下吞吐比传统 HuggingFace Transformers 推理高很多。


七、Prefill 和 Decode 的性能特征不同

LLM 推理可以分为两个阶段:

1. Prefill 阶段

Prefill 处理完整输入 Prompt。它的特点是:

  • token 数较多
  • 矩阵计算密集
  • GPU 算力利用较高
  • 更像训练中的前向传播

2. Decode 阶段

Decode 每次只生成一个 token。它的特点是:

  • batch 中每个请求每步只算一个 token
  • 计算粒度小
  • 需要频繁读取 KV Cache
  • 更容易受显存带宽限制

因此优化策略也不同:

  • Prefill 要关注大矩阵计算效率
  • Decode 要关注 KV Cache 访问效率和调度效率

一些高性能推理系统会进一步做 Prefill/Decode 分离,让不同 GPU 或不同执行队列分别处理两类任务,以提高资源利用率。


八、量化推理:降低权重和 KV Cache 成本

量化是推理优化中最常用的手段之一。常见量化方式包括:

  • FP16 / BF16
  • INT8
  • INT4
  • GPTQ
  • AWQ
  • SmoothQuant
  • FP8

量化的核心目标是:

  1. 减少模型权重显存占用
  2. 提高推理吞吐
  3. 降低部署成本

例如一个 7B 模型:

  • FP16 权重大约 14GB
  • INT8 大约 7GB
  • INT4 大约 3.5GB

但要注意,量化不一定总是带来线性加速。原因包括:

  • GPU 对某些低比特算子支持不够好
  • 反量化开销可能抵消收益
  • 量化会影响模型精度
  • KV Cache 仍可能是瓶颈

在长上下文、高并发场景中,即使权重量化到 INT4,KV Cache 仍然可能占用大量显存。因此更高级的系统还会考虑 KV Cache 量化,例如把 KV Cache 从 FP16 降到 INT8 或 FP8。


九、吞吐和延迟:两个经常冲突的指标

部署大模型服务时,常见指标包括:

  • TTFT:Time To First Token,首 token 延迟
  • TPOT:Time Per Output Token,每个输出 token 的平均耗时
  • Throughput:吞吐量,tokens/s 或 requests/s
  • GPU Utilization:GPU 利用率
  • Max Concurrency:最大并发数

这里有个典型矛盾:

batch 越大,吞吐通常越高,但单请求延迟可能越高。

如果系统为了凑大 batch 等待太久,TTFT 会变差;如果 batch 太小,GPU 利用率又上不去。

所以线上服务通常需要设置:

text

max_batch_sizemax_num_batched_tokensmax_waiting_timemax_model_lengpu_memory_utilization

这些参数没有绝对最优值,必须结合业务场景压测。


十、一个实际部署建议

如果你要部署一个企业内部大模型推理服务,可以按如下路线:

1. 小规模验证

先用 vLLM 或 TGI 部署模型:

bash

python -m vllm.entrypoints.openai.api_server \  --model /models/Qwen2.5-7B-Instruct \  --tensor-parallel-size 1 \  --gpu-memory-utilization 0.9 \  --max-model-len 8192

2. 做压测

重点测试:

  • 并发 1、4、8、16、32 下的 TTFT
  • 平均输出速度 tokens/s
  • GPU 显存占用
  • 不同 prompt 长度下的吞吐
  • 不同生成长度下的稳定性

3. 优化参数

根据结果调整:

  • max_num_batched_tokens
  • max_num_seqs
  • max_model_len
  • 量化方式
  • tensor parallel
  • 是否启用 prefix cache

4. 上线监控

至少监控:

  • 请求排队时间
  • 首 token 延迟
  • 输出 token 速度
  • OOM 次数
  • GPU 显存利用率
  • 每分钟 tokens 数

十一、总结

大模型推理优化是 AI 工程化中非常硬核的细分领域。它不是简单地“把模型加载起来然后开接口”,而是涉及 Transformer 结构、显存管理、GPU 调度、batch 策略、量化算子和在线服务稳定性。

核心结论可以总结为:

  1. KV Cache 是大模型推理的关键优化,也是显存瓶颈来源
  2. Continuous Batching 可以显著提高在线服务吞吐
  3. PagedAttention 通过分页机制提升 KV Cache 管理效率
  4. Prefill 和 Decode 性能特征不同,需要区别优化
  5. 量化能降低部署成本,但不一定解决所有瓶颈
  6. 线上系统必须关注 TTFT、TPOT、吞吐、并发和显存稳定性

如果说 RAG 解决的是“模型如何接入知识”,那么推理优化解决的是“模型如何低成本、高并发、稳定地服务用户”。对于想深入 AI 基础设施方向的开发者来说,LLM 推理优化绝对是一个值得长期投入的硬核赛道。

Logo

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

更多推荐