vLLM模型部署
vLLM是什么
vLLM 是一个高性能、内存高效的 LLM(大语言模型)推理引擎,由 UC Berkeley 开发。它解决了大模型部署中最核心的问题:显存不够、推理太慢。
与其他推理引擎对比
| 特性 | vLLM | Transformers | llama.cpp | TGI |
|---|---|---|---|---|
| 显存效率 | ⭐ 极高(PagedAttention) | ❌ 低(静态 KV Cache) | ✅ 高(GGUF) | ✅ 高 |
| 吞吐量 | ⭐ 极高(连续批处理) | ❌ 低 | ⚠️ 中等 | ✅ 高 |
| GPU 加速 | ✅ 原生 CUDA | ✅ | ⚠️ 通过 llama.cpp | ✅ |
| 量化支持 | AWQ/GPTQ/FP8/INT4 | bitsandbytes | GGUF 量化 | AWQ/GPTQ |
| OpenAI API | ✅ 内置 | ❌ | ⚠️ server 模式 | ✅ |
| 多 GPU | ✅ Tensor Parallel | ⚠️ device_map | ❌ | ✅ |
| MoE 支持 | ✅ 原生 | ⚠️ | ✅ | ✅ |
什么时候选 vLLM?
• 需要高吞吐的生产环境(API 服务)✅
• 多 GPU 部署大模型(70B+)✅
• 需要 OpenAI 兼容接口 ✅
• 单卡部署量化模型 ✅
• 实验性研究/单次推理 → 选 Transformers
• 个人电脑/无 GPU → 选 llama.cpp
内存占用精确计算
模型权重占用缓存
| 模型 | 参数量 | FP16 | INT8 | INT4 (AWQ/GPTQ) |
|---|---|---|---|---|
| Qwen2.5-1.5B | 1.5B | 3 GB | 1.5 GB | 0.75 GB |
| Qwen2.5-7B | 7B | 14 GB | 7 GB | 3.5 GB |
| Llama-3.1-8B | 8B | 16 GB | 8 GB | 4 GB |
| Qwen2.5-14B | 14B | 28 GB | 14 GB | 7 GB |
| Qwen2.5-32B | 32B | 64 GB | 32 GB | 16 GB |
| Llama-3.1-70B | 70B | 140 GB | 70 GB | 35 GB |
| Qwen2.5-72B | 72B | 144 GB | 72 GB | 36 GB |
| Mixtral 8×7B (MoE) | 47B | 94 GB | 47 GB | 24 GB |
| DeepSeek-V3 (MoE) | 671B | ~400 GB | ~200 GB | ~110 GB |
KV Cache 占用的显存
| 模型 | 层数 | 头数 | 2K | 4K | 8K | 32K | 128K |
|---|---|---|---|---|---|---|---|
| Llama-3.1-8B | 32 | 32 | 0.75 GB | 1.5 GB | 3 GB | 12 GB | 48 GB |
| Qwen2.5-7B | 28 | 28 | 0.6 GB | 1.2 GB | 2.4 GB | 9.6 GB | 38 GB |
| Qwen2.5-72B (GQA) | 80 | 8 (KV) | 0.5 GB | 1 GB | 2 GB | 8 GB | 32 GB |
| DeepSeek-V3 (MLA) | 67 | — | ~0.1 GB | ~0.2 GB | ~0.4 GB | ~1.6 GB | ~6.4 GB |
💡 关键发现:
• GQA(分组查询注意力)能大幅减少 KV Cache——KV 头数 = 注意力头数 / 组数
• MLA(多头潜在注意力,DeepSeek 用)把 KV Cache 压缩到几乎可忽略
• 上下文越长,KV Cache 占比越大——8K 以上 KV Cache 可能超过权重本身
总显存计算示例
显存诊断命令
常见 OOM 原因:
1. max-model-len 太高——上下文越长,KV Cache 越大。从 4096 开始尝试
2. gpu-memory-utilization 太高——设 0.85 留出余量
3. batch 太大——降低 max-num-seqs 或 max-num-batched-tokens
4. CUDA Graph 额外占显存——显存快满时加 --enforce-eager 禁用
5. 量化格式与加载方式不匹配——AWQ 模型没加 --quantization awq 会按 FP16 加载
安装与环境准备
版本兼容性:
• vLLM 0.4.x → CUDA 11.8 / 12.1, PyTorch 2.1+
• vLLM 0.5.x → CUDA 12.1+, PyTorch 2.2+
• vLLM 0.6.x → CUDA 12.1+, PyTorch 2.3+, FlashAttention 2
• vLLM 0.8.x → CUDA 12.4+, PyTorch 2.6+, 支持 Hopper( H100 ) 架构
• 低版本 CUDA 请使用 Docker 镜像(自带 CUDA 环境)
环境检查
vLLM核心技术
PagedAttention — vLLM 的灵魂
传统推理中,KV Cache 是一整块连续内存,预先分配最大可能大小。这导致:
- 内部碎片:分配的比实际需要的多,浪费 60%~80%
- 外部碎片:不同请求的 KV Cache 大小不一,内存无法复用
PagedAttention 借鉴操作系统分页内存管理的思想:
- KV Cache 分成固定大小的"块"(Block),每块 16 或 32 个 token
- 不需要连续的内存空间——物理上可以是零散的页面
- 通过"页表"(Block Table)将逻辑地址映射到物理地址
- 结果:显存利用率从 ~30% 提升到 ~95%
连续批处理(Continuous Batching)
传统批处理:
- 收集一批请求 → 同时推理 → 等所有请求完成 → 返回结果
- 短板效应:最慢的请求拖慢整批,短的请求在干等
vLLM 的连续批处理:
- 每个请求独立管理,按 token 粒度调度
- 每推理一步(一个 token)后重新调度
- 完成的请求立即移出,新请求随时加入
- GPU 始终在处理"有效计算",不浪费在等待上
- 结果:吞吐量提升 2~4 倍
推理引擎 vs 训练框架
| 维度 | 推理(Inference) | 训练(Training) |
|---|---|---|
| 目标 | 快速生成文本 | 更新模型权重 |
| 显存需求 | 权重 + KV Cache | 权重 + 梯度 + 优化器状态 |
| 批量大小 | 动态小批量 | 大批量 |
| KV Cache | 需要缓存(逐 token 生成) | 不需要(训练时一次性计算) |
| 典型框架 | vLLM, TGI, llama.cpp | DeepSpeed, Megatron, FSDP |
Prefill 与 Decode 阶段
LLM 推理分两个阶段:
- Prefill(预填充):一次性处理用户输入的 prompt,计算第一个输出 token。计算密集型,GPU 利用率高
- Decode(解码):逐个生成后续 token,每次只算一个 token。内存访问密集型,GPU 利用率低
vLLM 的优化重点就在 Decode 阶段——通过批处理把多个请求的 Decode 合并计算,提高 GPU 利用率。
投机解码(Speculative Decoding)
投机解码的核心思想:用小模型"猜"几个 token,再用大模型一次性验证。因为验证是并行的(大模型可以同时检查多个 token),而逐 token 生成是串行的,所以总速度更快。
投机解码流程:
1. Draft Model(草稿模型):一个小模型(~0.5B),快速生成 K 个候选 token
2. Target Model(目标模型):vLLM 部署的大模型,一次性验证这 K 个 token
3. 从第一个不匹配的 token 处截断,接受前面的匹配 token
4. 每步实际产出 1~K 个 token(取决于猜对的长度)
为什么能加速?
· 大模型的 Prefill 是并行的 → 验证 K 个 token ≈ 生成 1 个 token 的时间
· 小模型生成 K 个 token 的时间 ≈ 大模型生成 1 个 token 的时间
· 如果平均每次猜对 3 个 → 吞吐提升 ~3×
· 最关键:数学上无损失——验证通过的 token 和大模型自己逐 token 生成的结果完全一致
vLLM 支持 Eagle(一种高效 draft model)和 Medusa 两种投机解码方案。配置方式:--speculative-model <draft_model> --num-speculative-tokens 5。
MTP — 多 Token 预测(Multi-Token Prediction)
MTP 是 DeepSeek-V3/R1 提出的一种训练阶段技术,让模型在训练时就学会"一次预测多个未来 token",而非传统的"只预测下一个 token"。推理时,每个 Decode 步骤可以同时产出多个 token。
| 维度 | 投机解码 | MTP |
|---|---|---|
| 原理 | 小模型猜 + 大模型验证(两个模型协作) | 训练时就在模型内部加了多个预测头(单一模型) |
| 需要额外模型 | ✅ 需要 draft model | ❌ 不需要(MTP 头是模型的一部分) |
| 每步产出 | 1~K 个 token(取决于猜对率) | 固定 K 个 token(通常 K=2~4) |
| 精度 | 无损失(验证保证) | 可能有微小损失(MTP 头的预测不如主头准) |
| 代表 | Eagle, Medusa | DeepSeek-V3, DeepSeek-R1 |
| vLLM 支持 | ✅ 原生支持 | ⚠️ 需模型本身支持 MTP(如 DeepSeek-V3) |
vLLM 对于 DeepSeek-V3 等原生支持 MTP 的模型,可以直接利用其 MTP 头实现多 token 同时生成,无需额外配置 draft model。
前缀缓存(Automatic Prefix Caching / APC)
很多请求共享相同的系统提示词(System Prompt)。例如:"你是一个有用的助手……" 这段文字每次请求都一样。如果没有缓存,每个请求都要重新计算这段前缀的 KV Cache。
APC 的工作原理:
· 将 prompt 的 token 序列按固定大小分块(如每 16 个 token 一块)
· 对每个块计算哈希值作为"指纹"
· 新请求到来时,查找是否有相同哈希的块 → 命中则直接复用 KV Cache
· 结果:共享长 System Prompt 的场景下,TTFT(首 token 延迟)可降低 50%~90%
vLLM 默认开启 APC,无需额外配置。通过 --enable-prefix-caching 显式开启(新版已默认)。
分块预填充(Chunked Prefill)
长 prompt(如 32K token)的 Prefill 阶段计算量巨大,一次处理会长时间占用 GPU,阻塞其他请求的 Decode。Chunked Prefill 把长 prompt 切成多个小块,交错执行:
分块前(长 Prefill 阻塞):
[-------- 32K Prefill (独占 GPU, 200ms) --------] → [Decode] → [Decode] → ...
中途其他请求的 Decode 无法插队
分块后(交错执行):
[4K Prefill] → [Decode 请求A] → [4K Prefill] → [Decode 请求B] → [4K Prefill] → ...
每个 Prefill 小块只占 ~25ms,其他请求可以在间隙中插入 Decode
配置方式:--max-num-batched-tokens 8192(限制单次 Prefill 最多处理的 token 数)和 --enable-chunked-prefill。
张量并行(Tensor Parallelism)— 多卡推理
当模型太大单卡放不下时,vLLM 使用张量并行把模型切到多张 GPU 上。不同于训练中的 DP/TP/PP 三维并行,推理并行更简单——因为不需要存梯度和优化器状态。
| 并行方式 | 原理 | 适用场景 | vLLM 配置 |
|---|---|---|---|
| 张量并行 (TP) | 把每层的权重矩阵切成 N 份放到 N 张卡上,每张卡算一部分再聚合 | 单卡放不下完整模型(如 70B→4×24GB) | --tensor-parallel-size 4 |
| 流水线并行 (PP) | 前一半层放 GPU-0,后一半放 GPU-1,流水式传递 | 层数极多(如 DeepSeek-V3 的 60+ 层) | --pipeline-parallel-size 2 |
TP 是推理中最常用的多卡策略。例如 70B 模型 FP16 需要 ~140GB 显存,4×A100-40G 通过 TP=4 刚好装下。
量化推理 — 更小的模型,更多的吞吐
vLLM 支持多种权重量化格式,在几乎不损失精度的前提下大幅降低显存占用:
| 量化方式 | 精度 | 显存节省 (vs FP16) | 速度 | vLLM 配置 |
|---|---|---|---|---|
| AWQ | INT4(每通道缩放) | ~75%(14GB→3.5GB) | 接近 FP16 | 下载 AWQ 格式模型即可 |
| GPTQ | INT4(分组量化) | ~75%(14GB→3.5GB) | 接近 FP16 | 下载 GPTQ 格式模型即可 |
| FP8 | 8-bit 浮点 | ~50%(14GB→7GB) | ⭐ 比 FP16 更快(H100 原生支持 FP8) | --quantization fp8 |
| INT8 | 8-bit 整数 | ~50%(14GB→7GB) | 略慢于 FP16 | --quantization int8 |
| BitsAndBytes | INT4/INT8 | ~50%~75% | 较慢 | --quantization bitsandbytes --load-format bitsandbytes |
推荐:H100/H200 用户优先选 FP8(原生硬件加速,比 FP16 更快且显存减半);DGX Spark(Blackwell, 128GB 统一内存)同样优先选 FP8,而且 128GB 显存跑 70B 模型直接用 BF16 也绰绰有余;消费级显卡(RTX 3090/4090)优先选 AWQ(INT4 量化,24GB 可跑 70B 模型)。
调度策略(Scheduling Policy)
vLLM 支持多种请求调度策略,决定"先处理哪个请求、分配多少资源":
| 策略 | 行为 | 适用场景 |
|---|---|---|
| FCFS(先到先服务) | 默认策略,按请求到达顺序处理 | 通用场景 |
| Priority(优先级) | 高优先级请求优先获得 GPU 时间片 | 在线服务(VIP 用户优先) |
| Preemption(抢占) | 高优先级请求可以"踢掉"正在处理的低优先级请求(被踢的请求 swap 到 CPU 内存) | 需要严格 SLA 的场景 |
vLLM 的调度器会综合考虑每个请求的 prompt 长度、已生成 token 数、优先级等因素动态分配资源。Swap 机制允许把被抢占请求的 KV Cache 暂存到 CPU 内存,恢复时再搬回 GPU。
模型部署调用
OpenAI 兼容 API 服务方式
启动API服务
参数详解
| 参数 | 默认值 | 详细说明 |
|---|---|---|
--port |
8000 | API 服务监听端口。客户端通过 http://IP:8000/v1 调用 |
--host |
127.0.0.1 | 绑定 IP。0.0.0.0 = 允许外部访问;127.0.0.1 = 仅本机 |
--served-model-name |
(同 model) | 对外暴露的模型名称。设成 gpt-4 后客户端用 model="gpt-4" 即可,隐藏真实模型名 |
--dtype |
auto | 模型精度。auto=自动检测模型配置;bfloat16/float16=半精度;float32=全精度 |
| --max-model-len | 模型默认值 | 最重要的参数之一。上下文窗口大小。可以超过模型原始训练长度(如 Llama-3-8B 原生 8K,设 32K 也可以推理,但精度可能下降) |
| --gpu-memory-utilization | 0.90 | 最重要的参数之一。vLLM 可以使用的 GPU 显存比例。设太低浪费显存,设太高(0.98+)可能 OOM。建议 0.85~0.95 |
--quantization |
None | 量化方式。awq/gptq/fp8/squeezellm。H100/DGX Spark 用 fp8,消费级显卡用 awq |
--tensor-parallel-size |
1 | GPU 数量。单卡=1。70B 模型 FP16 需要 ~140GB,2×A100-80G 设 2 |
--max-num-seqs |
256 | 最大同时处理的请求数。增大 = 更高吞吐但更多显存给 KV Cache。显存紧张时减小此值 |
--enable-prefix-caching |
False | 开启 APC(自动前缀缓存)。共享 System Prompt 场景下 TTFT 大幅降低 |
--api-key |
(无) | 设置 API 访问密钥。不设则任何能访问端口的客户端都可以调用 |
--trust-remote-code |
False | 允许执行模型仓库中的自定义 Python 代码。Qwen/DeepSeek/ChatGLM/Phi 等必须加 |
日常最需要调的三个参数:
① --max-model-len — 决定上下文窗口多大(开销大头在 KV Cache,8192→32768 显存翻几倍)
② --gpu-memory-utilization — 决定 vLLM 能用多少显存(设太高 OOM,设太低吞吐上不去)
③ --max-num-seqs — 决定最多同时处理多少请求(越大 = KV Cache 预留越多 = 单请求可用显存越少)
调用API服务
流式输出 — 逐字显示
生成参数速查表
| 参数 | 类型/范围 | 默认值 | 什么时候调 |
|---|---|---|---|
| temperature | float, 0~2 | 1.0 | 越低越确定(代码/数学用 0.1~0.3),越高越有创意(写作/头脑风暴用 0.8~1.2) |
| top_p | float, 0~1 | 1.0 | 核采样。设为 0.9 表示只考虑累积概率前 90% 的 token。通常和 temperature 二选一 |
| top_k | int, 1~N | -1(不限制) | 只从概率最高的 K 个 token 中选。设 40~50 是常见值。vLLM 特有参数 |
| max_tokens | int | 16 | 限制生成长度。设太小回答被截断,设太大浪费资源。建议 512~4096 |
| seed | int | 随机 | 固定随机种子 = 相同输出。调试、评测、复现实验时必须设 |
| frequency_penalty | float, -2~2 | 0 | 正值惩罚已出现的 token(按频率)。模型老重复同一句话时调到 0.3~0.5 |
| presence_penalty | float, -2~2 | 0 | 正值惩罚已出现的 token(不论频率)。想让模型聊新话题时调到 0.3~0.5 |
| repetition_penalty | float, >1.0 | 1.0 | vLLM 特有。1.1 = 轻微惩罚重复,1.2 = 明显惩罚。>1.3 可能影响语法 |
| stop | str 或 list | 无 | 遇到这些词立即停止生成。常用: ["\n\n", "Human:", "###"] |
| stream | bool | False | 开启后逐 token 返回(Server-Sent Events)。Web 端必开 |
| n | int | 1 | 一次生成几个候选回答。>1 时 response.choices 有多个元素 |
| logprobs | bool | False | 返回每个 token 的对数概率。调试、置信度评估时开启 |
💡 常见场景的参数组合:
• 代码生成: temperature=0.1, top_p=0.95, max_tokens=4096(确定性高,输出长)
• 创意写作: temperature=0.9, top_p=0.95, frequency_penalty=0.3(有创意但不重复)
• 翻译: temperature=0.3, top_p=0.9, seed=42(确定性强,可复现)
• 对话聊天: temperature=0.7, top_p=0.9, presence_penalty=0.3(自然但不跑题)
Python API 方式
量化方法
量化(Quantization) 是把模型权重从高精度(FP16/BF16)压缩到低精度(INT4/INT8/FP8)的技术。目的是:
- 减少显存占用:FP16→INT4,显存降到 1/4
- 加速推理:低精度计算更快
- 降低功耗:更少的数据搬运
vLLM 支持的量化格式
| 格式 | 精度 | 显存节省 | 精度损失 | 适用场景 |
|---|---|---|---|---|
| FP16 / BF16 | 16-bit | 1×(基准) | 无 | 显存充足、追求最佳质量 |
| FP8 | 8-bit | ~2× | 极微 | H100/Hopper 原生支持,速度最快 |
| INT8 (W8A8) | 8-bit | ~2× | 微 | 需要平衡速度和质量的场景 |
| AWQ | 4-bit | ~4× | 小 | 最推荐:精度好、速度快、生态广 |
| GPTQ | 4-bit | ~4× | 小 | 早期格式,生态成熟但加载较慢 |
| INT4 (GGUF) | 4-bit | ~4× | 中 | llama.cpp 生态,vLLM 0.8+ 支持 |
| NF4 (bitsandbytes) | 4-bit | ~4× | 中 | QLoRA 训练用的格式,推理也能用 |
量化精度对比
| 模型 | FP16 | AWQ 4-bit | GPTQ 4-bit | FP8 |
|---|---|---|---|---|
| Llama-3.1-8B | 16 GB | ~5 GB | ~5 GB | ~8 GB |
| Qwen2.5-7B | 14 GB | ~4.5 GB | ~4.5 GB | ~7 GB |
| Llama-3.1-70B | 140 GB | ~40 GB | ~40 GB | ~70 GB |
| Qwen2.5-72B | 144 GB | ~41 GB | ~41 GB | ~72 GB |
| DeepSeek-V3 (671B MoE) | ~400 GB | ~110 GB | ~110 GB | ~200 GB |
⚠️ 量化注意事项:
• 不是所有模型都有量化版——优先在 HF 搜 "模型名 + AWQ"
• 量化模型用 --quantization 指定格式,否则 vLLM 可能按 FP16 加载导致 OOM
• AWQ 推荐优先于 GPTQ——AWQ 加载更快,精度略好
• INT4 量化后质量下降——7B AWQ ≈ 6.5B FP16 的水平,大多数场景可接受
• 代码/数学任务对量化更敏感——这些场景建议用 8-bit 或保持 FP16
多 GPU 与分布式部署
张量并行(Tensor Parallelism)
将模型的一层切成多份,每张 GPU 算一份,通过通信同步结果。
| 模型 | 单卡 24G | 2×24G | 4×24G | 8×24G |
|---|---|---|---|---|
| 7B (FP16) | ✅ 勉强 | ✅ | ✅ | ✅ |
| 7B (AWQ) | ✅ 流畅 | ✅ | ✅ | ✅ |
| 14B (FP16) | ❌ | ✅ | ✅ | ✅ |
| 32B (AWQ) | ✅ | ✅ | ✅ | ✅ |
| 70B (FP16) | ❌ | ❌ | ⚠️ 勉强 | ✅ |
| 70B (AWQ) | ❌ | ✅ | ✅ | ✅ |
| 72B (FP16) | ❌ | ❌ | ⚠️ | ✅ |
| 72B (AWQ) | ❌ | ✅ 勉强 | ✅ | ✅ |
流水线并行(Pipeline Parallelism)
将模型的不同层分配到不同 GPU,层间串行计算。
⚠️ TP vs PP:
• TP(张量并行):每步计算都需要 GPU 间通信(NVLink 最佳),通信量大
• PP(流水线并行):只需在层边界传输中间结果,通信量小
• 推荐:同一台机器用 TP(NVLink 快),多台机器用 PP(网络慢)
• 也可以组合使用:--tensor-parallel-size 2 --pipeline-parallel-size 2
多节点部署
当模型大到单台机器装不下时(如 70B 模型 FP16 需要 ~140GB,而单机只有 4×A100-40G = 160GB 但实际可用 ~140GB),需要跨多台机器做张量并行。vLLM 通过 Ray 实现跨节点分布式推理。
关键理解:工作节点不运行 vllm serve,只运行 Ray。vLLM 通过 Ray 自动把 tensor-parallel worker 分布到集群中的 GPU 上:
跨节点 TP 的架构:
节点 1(Head):启动 Ray Head + vllm serve
→ vLLM 通过 Ray 分发 TP worker 到节点1的GPU + 节点2的GPU
→ 对外暴露 API(只有 Head 有 API)
节点 2(Worker):只启动 Ray Worker,加入集群
→ 不运行 vllm serve!Ray 自动把 Head 分配的计算任务调度过来
💡 实践建议:
• 4 张卡以内 → 单机 TP 就够了,不需要 Ray
• 4~8 张卡 → 单机 TP + PP 组合
• 8 张卡以上 → 多节点 + TP + PP(需要 Ray 做跨节点分布式)
• 跨节点需要高速网络(InfiniBand/RoCE),普通千兆会成瓶颈
• Worker 节点绝对不要跑 vllm serve!只跑 ray start!

浙公网安备 33010602011771号