跳转至

vLLM:原理、部署与调优

vLLM 不是模型,也不是训练框架。它是一个大模型推理与服务引擎:负责把模型权重加载到 CPU/GPU,接收多个请求,管理 KV Cache 和批处理,再通过 HTTP API 返回生成结果。

面试中可以先这样概括:

vLLM 的价值不是让模型变聪明,而是让同一份模型在多人并发调用时更有效地使用 GPU。它用连续批处理动态调度请求,用分页方式管理 KV Cache,减少显存碎片和无效预留,并提供 OpenAI 兼容 API、多卡并行、量化和监控能力。

一、一次推理发生了什么

用户请求
  ↓ Tokenizer
Prompt Token
  ↓ Prefill:并行处理输入,计算首个 token,并建立 KV Cache
  ↓ Decode:根据 KV Cache 逐个生成后续 token
返回文本 / JSON / 工具调用

Prefill 和 Decode 的区别

阶段 做什么 主要特征 影响指标
Prefill 一次处理输入 Prompt,建立 KV Cache 计算密集;长 Prompt 更重 首 token 延迟 TTFT
Decode 读取 KV Cache,逐 token 生成 内存带宽和调度更敏感 token 间延迟 ITL、输出 tokens/s

如果业务的 RAG 上下文很长,Prefill 会变重;如果回答很长或并发很多,Decode 和 KV Cache 压力会更明显。

二、vLLM 为什么吞吐高

Continuous Batching:请求动态进入批次

固定批处理必须等一批请求全部完成。不同用户的输出长度不一样,短请求结束后留下的计算位置会浪费。

连续批处理会在每次调度时重新组合仍在生成的请求和新请求:某个请求结束后,新请求可以进入,不必等待整批结束。因此高并发时 GPU 更不容易空转。

Paged KV Cache:像分页内存一样管理上下文缓存

KV Cache 保存每个请求已经计算过的注意力 Key/Value,避免每生成一个 token 都重新计算整个历史。它的代价是显存会随并发数 × 上下文长度增长。

vLLM 将 KV Cache 划分成块,按需要分配,而不是为每条请求预留一整块连续空间。可以把它理解为操作系统分页:

传统方式:为每个请求预留连续大块 → 内部浪费、外部碎片
vLLM:    按 block 分配和回收       → 更容易容纳更多并发序列

PagedAttention 是在这种分块 KV Cache 上执行注意力计算的机制。它优化的是显存管理和服务吞吐,不改变模型权重本身。

Prefix Caching:复用相同前缀

当多个请求共享相同系统提示、长文档前缀或固定模板时,前缀缓存可以复用已经计算的 KV Cache,减少重复 Prefill。它对完全不同的 Prompt 没有明显收益,还需要占用缓存空间。

Chunked Prefill:长输入分块调度

长 Prompt 的 Prefill 可能阻塞正在 Decode 的短请求。Chunked Prefill 将长输入拆成多段,与 Decode 请求共同调度,用 max-num-batched-tokens 控制每轮 token 预算。vLLM V1 会在模型支持时默认启用;仍应通过真实负载观察 TTFT 与 ITL,而不是照抄固定数值。官方调优说明

三、最小部署

下面示例只表示参数关系,模型名称、精度和上下文长度必须结合实际 GPU 验证:

vllm serve Qwen/Qwen2.5-7B-Instruct \
  --host 0.0.0.0 \
  --port 8000 \
  --served-model-name qwen-7b \
  --dtype auto \
  --gpu-memory-utilization 0.90 \
  --max-model-len 8192 \
  --max-num-seqs 64 \
  --enable-prefix-caching

检查模型和接口:

curl http://127.0.0.1:8000/v1/models

curl http://127.0.0.1:8000/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "qwen-7b",
    "messages": [{"role": "user", "content": "解释什么是 KV Cache"}],
    "temperature": 0.2,
    "max_tokens": 300
  }'

--api-key 不能代替完整的边界防护。官方文档明确说明,它只保护部分路径;生产服务仍应放在反向代理或 API Gateway 后,统一处理 TLS、认证、限流、审计和网络访问控制。OpenAI 兼容服务文档

四、核心参数怎么理解

1. 模型、长度与精度

参数 控制什么 调大/调整后的影响
vllm serve <模型名或目录> 加载模型;本页采用位置参数写法 模型规模决定基础能力、权重显存和硬件要求
--served-model-name API 对外显示的模型名 便于应用使用稳定别名,不改变模型能力
--max-model-len 单请求允许的最大总长度 越大,单请求可用上下文越长,但 KV Cache 容量压力越高,可并发数通常下降
--dtype 权重与计算使用的数值类型 auto 通常遵循模型配置;FP32 更占显存,FP16/BF16 更适合 GPU 推理
--quantization 使用 AWQ、GPTQ、FP8 等量化实现 权重更小、模型更容易放入显存;速度和质量取决于格式、模型与硬件
--kv-cache-dtype KV Cache 的数值类型 FP8 Cache 可减少上下文缓存显存,但需要做长上下文和任务质量回归

2. 显存与并发

参数 控制什么 常见取舍
--gpu-memory-utilization 单实例用于权重、执行和 KV Cache 的目标显存比例 较高可留出更多 KV Cache,但过高会缺少峰值余量,或与其他进程争抢显存
--max-num-seqs 一轮调度可处理的最大序列数 较高可能提升并发吞吐,也会增加 KV Cache 和调度压力;不是实际用户数
--max-num-batched-tokens 一轮调度的 token 总预算 较大通常有利于 Prefill 吞吐/TTFT;较小更偏向保护 Decode 的 ITL
--enable-prefix-caching 是否复用相同 Prompt 前缀 固定系统提示、多轮公共前缀收益高;随机请求收益低

三者关系可以这样记:

max-model-len:一条请求最多能有多长
max-num-seqs:一轮最多同时照顾多少条序列
max-num-batched-tokens:这一轮最多处理多少 token

它们设得越大,不代表服务一定越快。超过 GPU 和真实负载需要后,常见结果是显存紧张、请求被抢占、P95 延迟升高甚至 OOM。

3. 多 GPU 和扩展

参数/方式 解决的问题 注意事项
--tensor-parallel-size N 把同一层计算拆到 N 张 GPU;单卡放不下模型 每层需要通信,优先使用节点内高速互联
--pipeline-parallel-size N 把模型层划分成 N 个流水阶段 可跨节点,但存在阶段等待和通信开销
多个独立实例 + 负载均衡 一份模型已能放入单卡/一组卡,但吞吐或可用性不够 每个副本都加载完整权重,需要网关和健康检查

对于普通 Dense 模型,扩容并发通常是启动多个独立 vLLM 实例,而不是盲目设置数据并行参数。TP/PP 主要解决一份模型如何跨卡放置;多副本解决更多请求。官方示例见 Parallelism and Scaling

五、“调整精度”到底调什么

面试中先反问或主动澄清:这里说的是数值精度、量化精度,还是回答准确率

数值精度:FP32、FP16、BF16

类型 大致特点 常见判断
FP32 每个权重占用更多内存,数值范围和精度高 推理通常没必要;显存和吞吐成本较高
FP16 显存约为 FP32 的一半,GPU 支持广 数值范围小于 BF16,少数模型更容易溢出
BF16 与 FP16 占用相近,指数范围接近 FP32 硬件支持时常作为现代大模型推理的稳妥选择

使用 --dtype auto 是合理起点。不要为了“更准”直接强制 FP32;多数模型的推理质量不会因此出现值得显存成本的提升,还必须看模型原始训练精度和硬件支持。

权重量化:FP8、INT8、INT4、AWQ、GPTQ

量化是用更少 bit 表示权重或激活。主要收益是减少显存,使更大的模型能够部署,部分硬件上也可能提高吞吐。代价可能是生成质量下降、量化/反量化开销增加,或某种格式没有适配当前 GPU 内核。

正确步骤是:

  1. 用 BF16/FP16 原模型建立质量和性能基线。
  2. 选择当前 GPU 明确支持的量化格式。
  3. 用同一套真实测试集比较回答正确率、格式遵循、长上下文、工具调用和 RAG。
  4. 同时记录显存、TTFT、ITL、吞吐和错误率。
  5. 质量和稳定性验收通过后再发布,并保留回滚版本。

vLLM 支持的量化实现及硬件兼容性会变化,应查部署版本的官方量化兼容表,不能只记“INT4 最省显存”。

KV Cache 量化

--kv-cache-dtype 调的是上下文缓存,不是模型权重。它更直接影响长上下文和高并发时的缓存容量。降低 KV Cache 精度后,应重点回归:长文档问答、长对话一致性、精确抽取和重复生成稳定性。

回答准确率:不是靠 dtype 参数解决

如果用户说“回答不准”,优先按下面顺序定位:

模型能力/版本是否适合任务
聊天模板、System Prompt 是否正确
输入是否超过长度限制,或被上游应用截断
RAG 是否召回正确证据
Temperature / Top-P 是否适合任务
最后再比较量化造成的质量差异

事实问答和结构化抽取可从较低 temperature 开始;创作任务可以更高。但采样参数只能改变输出随机性,无法补回被截断的上下文,也无法修复错误的 RAG 召回。

max-model-len 是输入与输出合计的服务长度上限,通常超长请求会报错;不要把它理解成服务总会自动截断。还要检查应用是否主动截断历史、RAG 内容,以及请求的输出长度预算。

实际切换方式

下面是已有 vLLM 环境中的替代启动示例,各选项需匹配当前版本与 GPU。模型目录应提前准备好权重、配置和 Tokenizer;每次只启动其中一个进行对照。

# 基线:硬件支持 BF16,使用原始模型目录
vllm serve /data/models/base-model --dtype bfloat16 --max-model-len 4096

# 对照 FP16:仍使用同一原始模型
vllm serve /data/models/base-model --dtype half --max-model-len 4096

# AWQ:这里必须换成已经完成 AWQ 量化的兼容模型制品
vllm serve /data/models/model-awq --quantization awq --dtype half --max-model-len 4096

# FP8 KV Cache:保留权重精度,调整缓存精度;须确认后端与缩放因子支持
vllm serve /data/models/base-model --dtype bfloat16 --kv-cache-dtype fp8 --max-model-len 4096

--quantization awq 是加载方式,不能把任意原始权重即时变成 AWQ 制品;部分其他量化方法支持在线转换,需要按具体方法说明操作。FP8 Cache 的 scale 应按对应版本文档和模型制品配置,不能仅以“成功启动”判断精度正确。

FP32 每个权重约 4 字节,FP16/BF16 约 2 字节,INT8 约 1 字节,INT4 约半字节。以理想化 7B 参数模型计算,纯权重分别约为 28、14、7、3.5 GB(十进制)。实际还需量化元数据、KV Cache、激活和运行时工作区,所以 14 GB 权重不代表 16 GB GPU 就一定足够。

六、调优顺序

先定义指标

指标 说明
TTFT 从请求进入到第一个 token 返回;用户最直观的“开始回答速度”
ITL 相邻输出 token 的间隔;决定回答是否顺滑
吞吐 每秒处理的请求数或 token 数
P95/P99 高分位延迟;比平均值更能反映拥塞
KV Cache 使用率/抢占 判断上下文与并发是否超过缓存容量
质量通过率 固定测试集上回答、格式、工具调用和引用是否正确

推荐顺序

  1. 固定模型、GPU、数据集和请求长度分布,建立基线。
  2. max-model-len 收紧到业务真正需要的长度。
  3. 逐步增加并发压测,观察吞吐、TTFT、ITL 和 P95。
  4. 调整 max-num-seqs;再用 max-num-batched-tokens 平衡 Prefill 与 Decode。
  5. 有大量公共前缀时启用前缀缓存并观察命中率。
  6. 单卡放不下再做量化或 TP;吞吐不够则比较多副本和扩卡成本。
  7. 每次只改一类参数,同时做质量回归。

七、常见现象

现象 优先检查
启动时 OOM 模型大小和 dtype、量化格式、GPU 是否被占用、max-model-len、显存比例
能启动但并发很低 KV Cache 容量、上下文长度、max-num-seqs、模型权重占用
TTFT 很高 Prompt 太长、排队、Prefill token 预算、CPU Tokenizer、模型未预热
输出时断时续 Decode 排队、过大的 Prefill 批次、GPU 抢占、网络反向代理缓冲
GPU 利用率低 并发不足、输出过短、CPU/网络瓶颈、模型过小或批处理不足
量化后反而慢 当前 GPU/量化格式缺少高效内核,反量化开销抵消收益
回答质量下降 模型/量化版本、聊天模板、采样参数、上下文截断、RAG 召回
多卡性能不升反降 卡间互联、TP 通信、NUMA、容器 GPU 拓扑和批量不足

八、面试回答模板

vLLM 是面向在线大模型推理的服务引擎。一次生成分 Prefill 和 Decode:Prefill 处理输入并建立 KV Cache,Decode 根据缓存逐 token 生成。vLLM 通过 Continuous Batching 动态合并并发请求,用分页方式管理 KV Cache,减少显存碎片,所以重点优势是高并发吞吐。调参时我会先看 max-model-lengpu-memory-utilizationmax-num-seqsmax-num-batched-tokens,再根据模型是否放得下选择量化、Tensor Parallel 或多副本。所谓调整精度要区分 dtype、权重量化、KV Cache 精度和回答准确率;回答不准不能简单靠改 FP16/FP32 解决,必须同时检查模型、模板、上下文截断、RAG 和采样参数。

参数随 vLLM 版本变化,部署前应使用 vllm serve --help=<参数名> 核对当前版本;完整参考见 vLLM Serve CLI