大模型真正进入生产环境以后,最容易被低估的问题往往不是“模型能不能跑起来”,而是“每生成一个 Token 到底要花多少钱”。
在实验环境中,单次请求跑得快、显存占得满,并不意味着线上服务具有良好的经济性。生产环境面对的是持续到来的并发请求、长度差异巨大的 Prompt、不断增长的 KV Cache,以及 TTFT(Time To First Token)、TPOT(Time Per Output Token)、吞吐量和显存利用率之间复杂的权衡。
尤其对于长上下文和高并发场景,模型权重本身反而不一定是第一瓶颈。随着请求数量和上下文长度增长,KV Cache 会迅速占据大量 GPU 显存,并进一步限制 batch size、并发数和整体吞吐。
因此,大模型推理成本优化不能简单理解为“把模型从 FP16 换成 INT4”。
真正有效的优化通常来自一个完整的推理栈:
模型量化 + PagedAttention + KV Cache 管理 + Continuous Batching + Prefix Caching + Kernel 优化 + 并发调度 + 硬件利用率优化
vLLM 正是围绕这一类问题设计的高性能 LLM 推理框架。当前官方文档已经将 PagedAttention、Continuous Batching、Chunked Prefill、Prefix Caching、量化、FlashAttention/FlashInfer、CUDA Graph、Speculative Decoding 等能力集成到统一推理框架中。(vLLM)
本文从 Transformer 推理原理出发,重点分析 KV Cache 为什么会成为成本瓶颈,以及如何使用 vLLM 对推理服务进行系统性优化。
一、先理解一个事实:LLM 推理为什么昂贵
Transformer 的自回归生成过程可以简单理解为:
输入 Prompt
│
▼
Tokenizer
│
▼
Prefill
│
├── 计算整个 Prompt
├── 生成 K/V
└── 保存到 KV Cache
│
▼
Decode
│
├── 读取历史 KV
├── 计算下一个 Token
├── 生成新的 K/V
└── 写入 KV Cache
│
▼
下一个 Token
其中可以把推理过程分成两个阶段:
1. Prefill
Prefill 负责处理用户提交的 Prompt。
例如:
System Prompt 200 tokens
User Context 5000 tokens
Question 200 tokens
--------------------------------
Total 5400 tokens
模型需要一次性处理这 5400 个 Token。
Prefill 通常具有较高的计算并行度,因此更容易表现为计算密集型任务。
2. Decode
生成阶段则完全不同。
假设模型需要生成 500 Token:
Token 1
↓
Token 2
↓
Token 3
↓
...
Token 500
每一步生成下一个 Token 都依赖之前已经生成的内容。
因此 Decode 是典型的自回归过程。
如果每次都重新计算完整上下文,计算量会非常巨大。
KV Cache 的核心价值就在这里:
已经计算过的 Key 和 Value 不需要每个 Decode Step 重新计算。
这也是为什么 KV Cache 是现代 LLM 推理系统的核心资源之一。
二、KV Cache 到底缓存了什么
Transformer Attention 的核心计算可以简化为:
Attention(Q, K, V)
=
softmax(QKᵀ / √d)V
其中:
- Q:Query
- K:Key
- V:Value
在自回归生成过程中,新 Token 会产生新的 Q、K、V。
但是历史 Token 的 K、V 已经计算过。
例如:
Token 1 → K1 V1
Token 2 → K2 V2
Token 3 → K3 V3
Token 4 → K4 V4
生成 Token 5 时:
Q5
│
├── K1
├── K2
├── K3
└── K4
V1
V2
V3
V4
因此系统可以直接读取:
[K1,K2,K3,K4]
[V1,V2,V3,V4]
而不需要重新计算历史 Token。
这就是 KV Cache。
2.1 KV Cache 为什么特别吃显存
假设一个模型具有:
Layers = 32
KV Heads = 8
Head Dimension = 128
Datatype = FP16
那么每个 Token 的 KV Cache 大小近似为:
KV bytes/token
=
Layers
× KV Heads
× Head Dimension
× 2(K,V)
× bytes_per_element
代入:
32 × 8 × 128 × 2 × 2
=
131072 bytes
也就是:
128 KB / token
如果一个请求上下文达到 8192 Token:
8192 × 128 KB
≈ 1 GB
注意,这只是一个请求的数量级估算。
如果同时存在:
16 requests
理论上就可能需要接近:
16 GB
的 KV Cache。
所以在长上下文、高并发服务中,真正限制并发能力的往往不是模型权重,而是 KV Cache。
三、为什么传统 KV Cache 管理效率并不高
最早的推理实现通常会为每个请求分配连续显存:
Request A
┌───────────────────────────────┐
│ K/V Token 0 ... Token 4095 │
└───────────────────────────────┘
Request B
┌───────────────────────────────┐
│ K/V Token 0 ... Token 2047 │
└───────────────────────────────┘
问题在于请求长度并不固定。
例如:
Request A = 4096 tokens
Request B = 900 tokens
Request C = 12000 tokens
Request D = 2300 tokens
如果系统按照最大长度预分配,就会产生大量浪费。
如果动态扩容,又容易产生显存碎片。
这和传统操作系统内存分配非常类似:
连续内存
↓
动态增长
↓
碎片
↓
分配困难
这正是 vLLM PagedAttention 要解决的问题。
四、PagedAttention:把 KV Cache 像虚拟内存一样管理
vLLM 的 PagedAttention 借鉴了操作系统虚拟内存和分页机制。
它不再要求一个请求的 KV Cache 必须连续存储,而是把 KV Cache 切成多个固定大小的 Block。
逻辑上:
Request A
Logical KV Cache
[Block 0][Block 1][Block 2][Block 3]
实际 GPU 显存可能是:
Physical GPU Memory
[Block 7]
[Block 2]
[Block 19]
[Block 4]
然后通过 Block Table 建立映射:
Logical Block Physical Block
Block 0 ───→ Block 7
Block 1 ───→ Block 2
Block 2 ───→ Block 19
Block 3 ───→ Block 4
于是:
逻辑连续
↓
物理离散
这就是 PagedAttention 最核心的思想。
4.1 PagedAttention 带来的收益
首先是显存碎片显著降低。
传统模式:
连续分配
AAAAAAAAAAAA
BBBBBB
CCCCCCCC
AAAAAA
容易出现:
Free
Used
Free
Used
Free
而分页方式:
Block Pool
[Free]
[Used]
[Used]
[Free]
[Used]
[Used]
[Free]
请求需要多少 Block 就分配多少。
当请求结束:
Request A
↓
释放 Block
↓
Block Pool
↓
其他 Request 复用
因此 GPU 显存可以更加充分地服务于真实 Token。
PagedAttention 正是 vLLM 的核心内存管理机制之一。(vLLM)
五、Continuous Batching:不要等待整个 Batch 结束
传统静态 Batch 的逻辑通常是:
Batch
├── Request A
├── Request B
├── Request C
└── Request D
全部完成
↓
Batch 结束
↓
下一批
最大的问题是:
Request A → 100 tokens
Request B → 2000 tokens
Request C → 300 tokens
Request D → 5000 tokens
如果按照最长请求同步执行:
A ──────────┐
B ─────────────────────
C ───────────
D ────────────────────────────────
短请求会被迫等待。
GPU 的计算资源也会因此出现大量浪费。
5.1 Continuous Batching 的思想
Continuous Batching 则把请求生命周期拆开:
Time →
A █████████
B █████████████████
C ██████
D █████████████
E ███████
某个请求完成后:
Request A
↓
立即退出 Batch
↓
Request E
↓
立即进入
因此 GPU 在每一个 iteration 中都可以尽可能装载更多可执行请求。
vLLM 官方当前版本将 Continuous Batching、Chunked Prefill、Prefix Caching 等作为核心服务能力。(vLLM)
六、vLLM 的完整推理架构
生产环境中的 vLLM 可以理解为:
Client
│
▼
┌───────────────┐
│ API Gateway │
└───────┬───────┘
│
▼
┌───────────────┐
│ vLLM Server │
└───────┬───────┘
│
┌───────────┴───────────┐
▼ ▼
Request Scheduler KV Cache Manager
│ │
▼ ▼
Continuous Batching Paged KV Blocks
│ │
└───────────┬───────────┘
▼
Attention Kernel
│
┌───────────┴───────────┐
▼ ▼
FlashAttention GEMM Kernel
│ │
└───────────┬───────────┘
▼
GPU
如果把整个优化过程抽象成一条链:
请求调度
↓
Batching
↓
KV Cache 分配
↓
Attention Kernel
↓
GEMM
↓
GPU
其中任何一个环节成为瓶颈,整体吞吐都会下降。
七、第一步优化:不要盲目追求最大 Batch
这是生产环境非常容易犯的错误。
很多人看到 GPU 显存还有空间,就认为:
Batch 越大越好。
实际上并不是。
Batch 增大通常意味着:
吞吐 ↑
显存占用 ↑
排队延迟 ↑
TTFT 可能 ↑
调度复杂度 ↑
尤其是长 Prompt 场景。
例如:
Batch = 8
Average Input = 2K
和:
Batch = 8
Average Input = 32K
虽然 Batch 一样,但第二种情况的 KV Cache 压力完全不是一个数量级。
因此真正应该关注的是:
tokens / batch
而不是简单的:
requests / batch
八、max-num-batched-tokens 是关键参数
vLLM 的生产调优不应该只盯着:
max_num_seqs
更重要的是控制每个 iteration 中处理的 Token 数量。
典型启动方式:
vllm serve Qwen/Qwen3-8B \
--host 0.0.0.0 \
--port 8000 \
--gpu-memory-utilization 0.90 \
--max-num-seqs 128 \
--max-num-batched-tokens 16384
这里的思路是:
max-num-seqs
↓
限制并发请求数量
max-num-batched-tokens
↓
限制单次调度 Token 工作量
两者应该联合调节。
九、GPU Memory Utilization 不是越高越好
vLLM 可以利用 GPU 显存的一定比例作为推理资源。
例如:
--gpu-memory-utilization 0.90
很多生产环境喜欢直接:
0.95
0.98
但这样做风险较高。
GPU 显存并不只有模型权重:
GPU Memory
├── Model Weights
├── KV Cache
├── CUDA Runtime
├── Temporary Buffers
├── Activation
├── Kernel Workspace
└── Other Runtime Memory
如果把显存压得过满,可能出现:
OOM
甚至:
偶发 OOM
这种问题比启动时直接 OOM 更难排查。
更合理的方法是:
0.85
↓
0.90
↓
0.92
逐级压测。
十、KV Cache 优化的核心公式
对于标准 MHA,可以近似表示 KV Cache:
KV Cache Memory
≈
2 × Layers × KV Heads × Head Dim
× Sequence Length
× Batch Size
× Bytes
这里最值得关注的是:
KV Heads
现代模型大量使用 GQA(Grouped Query Attention)或者 MQA(Multi-Query Attention)。
例如:
Query Heads = 32
KV Heads = 8
那么 KV Cache 的 Head 数量不是 32,而是 8。
理论上,相比:
32 KV Heads
可以把 KV Cache 的这一部分降低到:
8 / 32 = 25%
这也是 GQA 对推理系统非常重要的原因。
TensorRT-LLM 的 KV Cache 文档同样明确利用 MHA、MQA 和 GQA 的不同 KV Head 结构来优化 KV Cache 内存。(NVIDIA GitHub)
十一、Prefix Caching:重复 Prompt 不要重复计算
很多企业应用存在高度重复的 Prompt。
例如:
System Prompt
+
企业知识库规则
+
工具定义
+
Agent Instructions
+
用户问题
其中前面几千 Token 可能完全相同。
如果每次请求都重新 Prefill:
Request 1
System Prompt → Compute
Request 2
System Prompt → Compute
Request 3
System Prompt → Compute
Request 4
System Prompt → Compute
这是明显的浪费。
Prefix Caching 的思想就是:
第一次请求
Prefix
↓
Compute
↓
KV Cache
↓
保存
后续请求
Prefix
↓
匹配
↓
直接复用 KV
↓
只计算新增内容
因此:
TTFT ↓
GPU Compute ↓
成本 ↓
对于以下场景尤其有效:
- Chatbot
- Agent
- RAG
- 企业知识库
- 固定 System Prompt
- 大量工具定义
- 多轮对话
十二、Chunked Prefill:解决长 Prompt 阻塞 Decode
一个非常典型的问题:
当前有 100 个 Decode 请求
突然来了:
一个 100K Token Prompt
如果直接进行完整 Prefill:
100K Token Prefill
↓
GPU 被长时间占用
↓
Decode 请求等待
↓
用户感知延迟暴涨
Chunked Prefill 可以把长 Prompt 拆成多个 Chunk:
100K Prompt
[Chunk 1]
[Chunk 2]
[Chunk 3]
[Chunk 4]
...
然后让 Prefill 和 Decode 更合理地共享 GPU 计算资源。
例如:
Iteration 1
Decode + Prefill Chunk
Iteration 2
Decode + Prefill Chunk
Iteration 3
Decode + Prefill Chunk
这实际上是在解决:
吞吐与交互延迟之间的调度问题。
所以生产系统不能只看 tokens/s,还必须同时观察:
TTFT
ITL / TPOT
P99 Latency
Queue Time
Throughput
十三、量化:降低模型权重成本
如果模型采用 BF16:
2 bytes / parameter
那么一个 70B 模型,仅权重理论存储量大约:
70B × 2
≈ 140 GB
还没有计算:
KV Cache
Runtime Memory
Temporary Buffer
如果使用 INT4:
70B × 0.5
≈ 35 GB
这意味着同样的 GPU 集群可能运行更大的模型,或者运行更多副本。
常见量化方案包括:
FP8
INT8
INT4
GPTQ
AWQ
当前 vLLM 官方文档已经支持包括 FP8、MXFP8/MXFP4、NVFP4、INT8、INT4、GPTQ、AWQ、GGUF 等多种量化方式。(vLLM)
十四、为什么不能简单认为 INT4 一定比 FP8 快
这是推理优化中非常重要的一点。
量化影响的不只是显存。
还涉及:
Memory Bandwidth
Compute Throughput
Kernel Efficiency
Dequantization
Tensor Core Utilization
Accuracy
例如:
FP8
在现代 NVIDIA GPU 上往往具有非常成熟的硬件支持。
而某些 INT4 格式虽然理论上更省显存:
4 bit
但是如果对应 Kernel 不够高效:
Memory ↓
但
Kernel efficiency ↓
最终吞吐不一定更好。
所以量化选择应该通过 Benchmark 决定,而不是根据 Bit 数字大小决定。
十五、KV Cache 本身也可以量化
这是很多部署团队容易忽略的一层。
传统情况下:
Model Weight → Quantized
KV Cache → FP16 / BF16
实际上 KV Cache 也可以进行低精度存储。
例如:
FP16 KV Cache
↓
FP8 KV Cache
理论上:
2 bytes
↓
1 byte
KV Cache 存储量约减少一半。
对于长上下文、高并发场景,这个收益非常直接。
NVIDIA TensorRT-LLM 当前文档明确支持 FP8 KV Cache,并给出了量化 KV Cache 后吞吐提升的 benchmark 示例;但官方也特别指出,KV Cache 量化需要关注输出质量退化风险。(NVIDIA GitHub)
因此:
权重量化解决“模型装不下”的问题,KV Cache 量化解决“并发撑不住”的问题。
两者不是一回事。
十六、vLLM 中如何做 KV Cache 调优
实际部署时,可以先从一个相对保守的配置开始:
vllm serve Qwen/Qwen3-8B \
--host 0.0.0.0 \
--port 8000 \
--dtype bfloat16 \
--gpu-memory-utilization 0.90 \
--max-num-seqs 64 \
--max-num-batched-tokens 8192
然后根据压测结果调整。
典型调优路径:
Step 1
固定模型
↓
Step 2
固定 Prompt
↓
Step 3
固定输出长度
↓
Step 4
测试并发
↓
Step 5
观察 TTFT / TPOT
↓
Step 6
调整 max-num-seqs
↓
Step 7
调整 max-num-batched-tokens
↓
Step 8
调整 GPU Memory
↓
Step 9
启用 Prefix Cache
↓
Step 10
测试量化
不要一次修改十个参数。
否则最后根本无法判断:
到底是哪一个参数带来了提升?
十七、生产环境推荐的服务架构
如果是企业级 RAG / Agent 服务,不建议直接把 vLLM 暴露给公网。
更合理的架构是:
Internet
│
▼
┌───────────────┐
│ API Gateway │
└───────┬───────┘
│
┌──────────┴──────────┐
▼ ▼
Rate Limiter Auth / Billing
│ │
└──────────┬──────────┘
▼
┌─────────────┐
│ LoadBalance │
└──────┬──────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
vLLM-1 vLLM-2 vLLM-3
│ │ │
▼ ▼ ▼
GPU GPU GPU
进一步可以把:
Prefill
Decode
进行资源隔离。
高级架构可以设计为:
API Gateway
│
▼
Request Router
│
┌──────────┴──────────┐
▼ ▼
Prefill Cluster Decode Cluster
│ │
GPU Pool GPU Pool
vLLM 当前也已经提供 Prefill、Decode、Encode 等阶段解耦相关能力,为这类架构提供了基础。(vLLM)
十八、RAG 场景下,真正应该优化的是 Token
RAG 系统经常存在一个误区:
检索更多文档,回答一定更准确。
实际上:
TopK = 20
并不一定比:
TopK = 5
更好。
假设:
每个 Chunk = 700 tokens
TopK = 20
700 × 20
=
14000 tokens
再加:
System Prompt
Conversation History
Question
Instructions
很容易达到:
16K ~ 20K tokens
如果每天:
100万请求
那么输入 Token 成本会非常可观。
因此 RAG 优化应该首先从:
Retrieval
↓
Rerank
↓
Compression
↓
Context
开始。
例如:
召回 20
↓
Rerank
↓
保留 6
↓
Context Compression
↓
最终 3K tokens
这往往比单纯优化 GPU 更便宜。
十九、Agent 场景更加依赖 Prefix Cache
Agent 的 Prompt 通常具有高度重复结构:
System Prompt
+
Tools
+
Rules
+
Memory
+
Previous Messages
+
Current Task
其中:
System Prompt
Tools
Rules
通常长期稳定。
可以将 Prompt 设计成:
[Stable Prefix]
System
Tools
Rules
Policies
[Dynamic Suffix]
Memory
User Input
Current State
这样 Prefix Cache 才更容易命中。
这是一个很重要的工程原则:
缓存优化不仅是推理框架问题,也是 Prompt Architecture 问题。
如果每一次请求都改变 Prompt 的前半部分,那么 Prefix Cache 的收益自然有限。
二十、不要忽略输出 Token
很多团队优化时只盯着输入。
实际上:
总 Token
=
Input Tokens
+
Output Tokens
如果一个 Agent:
Input = 5K
Output = 5K
那么输出长度已经占到一半。
如果模型每次都生成:
大量解释
JSON
中间推理
工具描述
成本会明显增加。
因此应该设置合理的:
max_tokens
同时从 Prompt 层面减少不必要输出。
例如:
返回 JSON
不要解释
字段固定
相比:
请详细分析这个问题,并从多个角度进行解释……
更容易控制输出长度。
二十一、Speculative Decoding:进一步降低 Decode 延迟
当 Decode 成为主要瓶颈时,可以考虑 Speculative Decoding。
基本思想:
Small Draft Model
│
▼
生成多个候选 Token
│
▼
Large Target Model
│
▼
并行验证
例如:
Draft Model
A B C D E
─────────►
Target Model
验证 A B C D E
──────────────►
如果候选 Token 大量被接受:
一次 Target Forward
=
多个 Token
那么有效 Decode 速度就可以提高。
vLLM 当前官方能力列表已经包含多种 Speculative Decoding 方法,包括 n-gram、EAGLE、DFlash 等。(vLLM)
不过 Speculative Decoding 并不是所有模型、所有工作负载都有效。
如果:
Draft Acceptance Rate 很低
那么额外的 Draft 计算反而可能浪费资源。
所以依然应该 Benchmark。
二十二、真正有效的 Benchmark 怎么做
不要使用:
单请求
短 Prompt
短输出
测试出来的结果作为生产性能。
应该至少建立四类测试。
Case A:短上下文
Input = 512
Output = 256
Concurrency = 1 / 8 / 32 / 64
Case B:中等上下文
Input = 4K
Output = 512
Concurrency = 8 / 32 / 64
Case C:长上下文
Input = 16K
Output = 1K
Concurrency = 8 / 16 / 32
Case D:真实业务
RAG
Agent
Tool Calling
Multi-turn Chat
最终比较:
| 指标 | 基线 | 优化后 |
|---|---|---|
| TTFT P50 | ||
| TTFT P95 | ||
| TPOT | ||
| P95 Latency | ||
| Output tok/s | ||
| Total tok/s | ||
| GPU Utilization | ||
| KV Cache Usage | ||
| Requests/s | ||
| Cost / 1M tokens |
二十三、成本应该按照 Token 计算,而不是只看 GPU 租金
假设一张 GPU:
$2 / hour
平均吞吐:
1000 tokens/s
那么:
3600 × 1000
=
3.6M tokens/hour
理论 GPU 成本:
$2 / 3.6M
≈ $0.56 / 1M tokens
如果通过优化:
1000 tok/s
↓
2000 tok/s
那么:
$0.56
↓
$0.28 / 1M tokens
GPU 数量没有减少,但单位 Token 成本下降了约 50%。
这就是推理优化真正的经济价值。
因此:
吞吐量提升本质上就是单位 Token 成本下降。
二十四、一个完整的成本优化路线
如果现在有一个成本较高的 LLM 服务,不建议一上来就换模型。
可以按照下面顺序处理。
第一阶段
业务 Token 优化
│
├── Prompt Compression
├── RAG TopK
├── Output Limit
└── Conversation Trimming
第二阶段
推理框架优化
│
├── vLLM
├── Continuous Batching
├── PagedAttention
└── Chunked Prefill
第三阶段
KV Cache 优化
│
├── Prefix Caching
├── GQA / MQA
└── KV Cache Quantization
第四阶段
模型量化
│
├── FP8
├── INT8
├── AWQ
└── GPTQ
第五阶段
Kernel / GPU 优化
│
├── FlashAttention
├── CUDA Graph
├── Tensor Parallel
└── Speculative Decoding
这个顺序非常重要。
因为如果:
Prompt 本来就有 20K tokens
你却首先花大量时间优化 CUDA Kernel,收益可能远低于:
20K
↓
8K
这样的上下文优化。
二十五、50%以上成本下降应该如何实现
“成本降低 50%”不能作为一个无条件承诺。
具体收益高度依赖:
模型
GPU
上下文长度
并发
输入/输出 Token 比例
量化方案
Prefix Cache 命中率
业务请求分布
但是在合适的生产场景中,实现 50% 甚至更高的单位 Token 成本下降并非不现实。
一个典型的优化过程可能是:
Baseline
FP16
+
低并发
+
无 Prefix Cache
+
静态 Batch
+
冗余 Context
↓
Step 1
Prompt Compression
成本 ↓ 20%
↓
Step 2
vLLM + Continuous Batching
吞吐 ↑ 50%
↓
Step 3
Prefix Cache
Prefill ↓
↓
Step 4
FP8 / INT4
显存 ↓
吞吐 ↑
↓
Step 5
KV Cache Optimization
并发 ↑
↓
最终
单位 Token 成本
下降 50%+
这里必须强调:
50%并不是某一个参数带来的结果,而是整个推理栈共同优化的结果。
二十六、生产环境推荐的监控指标
推理服务必须建立完整的可观测性。
至少应该监控:
Request Metrics
request_count
request_success
request_error
queue_time
TTFT
TPOT
E2E latency
P50/P95/P99
Token Metrics:
input_tokens
output_tokens
total_tokens
tokens/sec
GPU Metrics:
GPU utilization
GPU memory
SM utilization
Tensor Core utilization
Power
Temperature
KV Cache:
KV Cache Usage
KV Cache Hit Rate
Prefix Cache Hit Rate
Block Allocation
Block Reuse
Eviction
最终形成:
业务指标
│
▼
Token 指标
│
▼
Scheduler 指标
│
▼
KV Cache
│
▼
GPU
只有这样才能定位:
到底是业务 Token 太多?
还是调度效率低?
还是 KV Cache 不够?
还是 GPU Kernel 没吃满?
二十七、一个推荐的生产参数基线
对于一个中等规模的 GPU 推理服务,可以从如下思路开始:
vllm serve /models/Qwen \
--host 0.0.0.0 \
--port 8000 \
--dtype bfloat16 \
--gpu-memory-utilization 0.90 \
--max-num-seqs 64 \
--max-num-batched-tokens 16384
然后逐项压测:
max-num-seqs
32
64
128
以及:
max-num-batched-tokens
4096
8192
16384
32768
建立矩阵:
Throughput
↑
┌─────────────┐
│ │
│ Optimal │
│ Region │
│ │
└─────────────┘
│
└────────→ Latency
目标不是寻找:
最大吞吐
而是寻找:
满足 P95/P99 延迟 SLA 前提下的最高有效吞吐。
二十八、不要把显存利用率等同于计算效率
这是生产部署中非常常见的误判。
例如:
GPU Memory = 90%
GPU Utilization = 35%
说明显存占得很多,但 GPU 计算单元没有充分利用。
可能原因包括:
KV Cache 太大
Batch 太小
Memory Bandwidth 瓶颈
Kernel 不匹配
请求长度差异太大
Decode 占比过高
反过来:
GPU Utilization = 95%
GPU Memory = 70%
也不代表一定需要继续增加 Batch。
可能已经存在:
P99 latency
↑
所以必须同时观察:
Memory
Compute
Latency
Throughput
二十九、vLLM 之外:什么时候考虑 TensorRT-LLM
vLLM 并不是唯一选择。
在 NVIDIA GPU 深度优化场景中,TensorRT-LLM 同样非常重要。
尤其是:
FP8
FP4
KV Cache Quantization
Paged KV Cache
CUDA Kernel
NVIDIA Tensor Core
等场景。
TensorRT-LLM 当前 KV Cache 系统支持 Block 管理、跨请求复用、优先级驱逐以及 MHA/MQA/GQA 等优化;其文档也提供了 KV Cache 容量和复用相关接口。(NVIDIA GitHub)
因此实际选型可以考虑:
通用 LLM Serving
↓
vLLM
NVIDIA 深度定制
↓
TensorRT-LLM
PyTorch 原生研究
↓
PyTorch
高性能推理
↓
vLLM / TRT-LLM Benchmark
最终仍然应该以真实模型和真实业务负载测试结果为准。
三十、一个可落地的优化决策树
面对一个已经上线的 LLM 服务,可以直接按照下面的顺序排查:
GPU 成本高
│
▼
Token 是否过多?
│
├── 是 → Prompt/RAG/Output 优化
│
└── 否
│
▼
GPU 是否吃满?
│
├── 否 → Batch / Scheduler / Kernel
│
└── 是
│
▼
KV Cache 是否成为瓶颈?
│
├── 是 → PagedAttention / Prefix Cache /
│ KV Quantization / GQA
│
└── 否
│
▼
模型量化
│
▼
FP8 / INT8 / INT4
│
▼
Speculative Decoding
│
▼
多 GPU 并行
这比“换一张更贵的 GPU”通常更值得先做。
三十一、最终的生产实践原则
大模型推理优化最终可以归纳成八条原则。
第一,先减少 Token,再优化 GPU
少生成 1 Token
永远比:
花更多钱去生成 1 Token
更直接。
第二,KV Cache 是长上下文服务的核心资源
尤其是:
Long Context
+
High Concurrency
场景。
需要重点关注:
KV Memory
Block Allocation
Cache Hit
Eviction
第三,PagedAttention 解决的是内存管理问题
它不是一个简单的 Attention Kernel。
真正价值在于:
KV Cache
↓
Block
↓
Dynamic Allocation
↓
Reuse
第四,Continuous Batching 决定 GPU 是否高效
GPU 最怕:
Batch 太小
请求到达不均匀
长短请求混杂
Continuous Batching 的核心目标就是让 GPU 尽可能持续工作。
第五,Prefix Cache 是 Agent/RAG 的重要优化点
如果:
System Prompt
+
Tools
+
Rules
高度重复,那么 Prefix Cache 往往值得优先测试。
第六,量化必须看真实吞吐
不要简单认为:
INT4 > INT8 > FP8 > FP16
真实结果取决于:
GPU
Kernel
Model
Batch
Context
第七,优化目标不是最大吞吐
真正的目标是:
SLA
+
吞吐
+
成本
+
质量
四者之间取得平衡。
第八,Benchmark 必须使用真实流量模型
最终应该使用:
真实 Prompt 长度
真实输出长度
真实并发
真实 RAG
真实 Agent
真实 Cache Hit Rate
而不是一个简单的:
Hello World
测试。
三十二、总结
vLLM 的价值并不只是“让模型跑得更快”。
它真正解决的是 LLM 推理服务中几个最昂贵的问题:
KV Cache 管理
+
Continuous Batching
+
PagedAttention
+
Prefix Caching
+
Chunked Prefill
+
量化
+
高性能 Kernel
其中,PagedAttention 解决 KV Cache 的碎片和动态分配问题;Continuous Batching 提高 GPU 的持续利用率;Prefix Caching 减少重复 Prompt 的 Prefill 计算;量化降低模型权重和部分运行时数据的存储压力;KV Cache 量化则进一步提高长上下文场景下的并发能力。
从成本角度看,最值得建立的认知是:
LLM 推理成本
│
├── Input Token
├── Output Token
├── GPU 时间
├── KV Cache
└── 系统利用率
因此,真正成熟的推理优化不是单点优化,而是:
业务层
↓
Token 优化
↓
模型层
↓
量化
↓
推理框架
↓
vLLM
↓
KV Cache
↓
Batch Scheduler
↓
Kernel
↓
GPU
如果一个生产系统能够同时做到:
减少无效 Context
+
提高 Prefix Cache 命中率
+
PagedAttention
+
Continuous Batching
+
合理量化
+
KV Cache 优化
+
真实负载调度
那么在相同硬件下获得显著的吞吐提升、降低单位 Token 成本是完全有可能的。
但“成本降低 50%”不应该被理解成某个 vLLM 参数能够直接带来的固定收益。它取决于具体模型、GPU、上下文长度、并发结构和业务流量。真正可靠的做法,是建立 Baseline,然后逐项 Benchmark,最终以 $/1M tokens、P95 TTFT、TPOT、GPU 利用率和质量指标 来衡量优化是否真正产生了商业价值。
对于 RAG、企业知识库和 AI Agent 来说,尤其应该把 Prompt 设计、Prefix Cache、KV Cache 和 Continuous Batching 放在同一个优化体系里考虑。只有把“模型怎么计算”和“业务到底让模型计算了多少东西”放在一起,推理成本优化才真正进入工程阶段。
参考资料
- vLLM 官方文档 —— vLLM 官方技术文档,涵盖 PagedAttention、Continuous Batching、Prefix Caching、量化、Speculative Decoding 等推理能力。(vLLM)
- Efficient Memory Management for Large Language Model Serving with PagedAttention —— vLLM PagedAttention 核心技术论文,系统讨论 LLM Serving 中 KV Cache 的内存管理问题。
- NVIDIA TensorRT-LLM KV Cache System —— NVIDIA 官方 TensorRT-LLM KV Cache 技术文档,介绍 Paged KV Cache、Cache Reuse、MHA/MQA/GQA 等机制。(NVIDIA GitHub)
- 网渡科技官方文档 https://www.wangdu.net.cn/announcements/61