
做推理服务的人应该都有过这种体验模型权重好不容易加载进去一压并发就卡成PPT显存明明还有剩余但请求全在排队GPU利用率却上不去。从 vLLM 开始这类问题算是有了一个被大范围验证过的解法。你只需要完成安装、启动两步再根据显卡情况做一轮显存调优就能把开源大模型的推理吞吐量拉高一个量级。这篇文章是我自己从零上手 vLLM 的完整记录覆盖安装、启动、显存调优三块硬骨头适合第一次接触 vLLM、准备用它部署 DeepSeek、Qwen 等开源模型的同学也适合已经在用但整天被显存 OOM 折磨的人。1. 为什么是 vLLM大模型推理的“堵车病”有救了1.1 推理服务到底卡在哪大模型推理和传统深度学习推理最大的差别在于它是逐个 token 循环生成的。模型每生成一个字符都要把前面所有已生成的字符重新看一遍这个过程中产生的中间状态叫 KV Cache。请求一多KV Cache 就会疯狂吃显存而且每个请求的 KV Cache 大小还不一样像一堆形状不规则的行李把显存这个行李箱塞得乱七八糟。传统推理框架会为每个请求预分配一大块连续显存不管这个请求实际用多长空间都先占着。结果就是显存碎片化严重请求稍微多一点就 OOM但nvidia-smi一看显存明明还有不少空闲。更气人的是就算显存够用GPU 也没被充分利用——因为大家都在等上一个请求把 GPU 让出来。我用一个比较贴切的比喻传统推理像一条没有红绿灯的单车道每辆车请求都要从头到尾占着整条路后面的车只能排队。而 vLLM 干的事情是给这条路装上智能调度系统和动态车位管理让车流变得顺畅起来。1.2 vLLM 是怎么把显存和算力“盘活”的vLLM 的核心创新有两个PagedAttention和Continuous Batching。PagedAttention 的思路是把 KV Cache 切成固定大小的块像操作系统管理内存页一样去管理。请求需要多少就分配多少块用完了可以还给显存池。这样一来显存碎片化问题基本消失KV Cache 利用率能拉到很高同一张卡上就能塞下更多请求、更长的上下文。Continuous Batching 解决的则是 GPU 利用率问题。它不再傻等一个请求生成完才处理下一个而是每个 token 生成完就立刻把计算资源腾给其他请求不同请求可以在同一个 step 里交错推理。效果就是吞吐量成倍提升尤其是当请求长短不一、业务高峰明显的时候效果非常直观。这两个机制叠加让 vLLM 在实际压测中的吞吐量能比朴素推理高出数倍这也是它能在开源社区快速普及的根本原因。1.3 vLLM 适合哪些场景我自己的判断是vLLM 最适合这几类人一是想用开源模型做私有化部署的比如部署 DeepSeek、Qwen、Llama 等二是要在生产环境对外提供 OpenAI 兼容接口的vLLM 启动后天然支持/v1/chat/completions和/v1/embeddings业务代码几乎不用改三是需要在有限显存下把吞吐压到极限的比如单卡部署 7B/14B 模型、双卡跑 32B 量化模型这类场景。如果你只是本地临时跑个小 demo用 llama.cpp 或者 Ollama 可能更省事但如果你考虑的是一次配置、长期服务、可能要接很多调用方那 vLLM 更值得投入。接下来我按自己实际操作的顺序把整个流程完整过一遍。2. 安装 vLLM 之前先把硬件和软件环境对齐2.1 显卡驱动、CUDA、PyTorch 三者怎么配vLLM 是高度依赖 CUDA 生态的项目安装前有一件必须做的事看清楚自己的 CUDA 环境。先在终端跑一下nvidia-smi看右上角的 CUDA Version这个数字代表你的显卡驱动最高支持的 CUDA 版本。注意这不等于你当前 Python 环境里实际使用的 CUDA 运行时版本真正跑模型时用的是 PyTorch 自带的 CUDA 工具包两者经常不一样。但驱动版本太低后面什么都跑不起来所以一般建议驱动版本别太老NVIDIA 驱动至少保证支持 CUDA 12.x。vLLM 对不同 CUDA 版本有对应的安装渠道。比如最新的 vLLM 已经适配到 CUDA 12.8主要是为了支持 Blackwell 架构的新卡30 系、40 系用户用默认安装方式通常就够了。我踩过的一个坑是在 Blackwell 架构机器上装了默认编译版本启动直接报unsupported GPU后来按官方文档切换到 CUDA 12.8 对应的安装源才正常。具体到命令我的建议不是背参数而是先确定三件事检查项命令预期结果显卡型号nvidia-smi -L能看到具体型号和显存大小驱动版本nvidia-smi驱动版本不要太老建议 535PyTorch 环境python -c import torch; print(torch.__version__, torch.version.cuda)确认 torch 是 CUDA 版而非 CPU 版2.2 Python 环境与虚拟环境vLLM 依赖的 Python 包非常多尤其对torch、numpy、transformers的版本很挑剔。千万不要直接往系统 Python 里装否则后面项目依赖冲突会让你怀疑人生。我习惯用 conda 创建一个独立环境conda create -n vllm python3.11 -y conda activate vllmPython 版本推荐 3.10 或 3.11官方支持范围内且主流依赖都兼容。3.12 也能跑但有些编译依赖可能需要额外处理非必要不选。创建好环境后先不要手动装 PyTorch。直接装 vLLM让 pip 自己解析 torch 依赖这是最省心的方式。如果你先装了别的版本 torch再装 vLLM 时版本对不上运行阶段经常出现undefined symbol这类玄学错误排查起来很痛苦。2.3 模型文件怎么准备vLLM 启动时默认会从 Hugging Face 拉取模型权重模型会缓存到~/.cache/huggingface。如果你在服务器上不方便直接访问 HF我的习惯是用 ModelScope 先把模型下载到本地目录再让 vLLM 加载本地路径。ModelScope 的做法很简单pip install modelscope modelscope download --model Qwen/Qwen2.5-7B-Instruct --local_dir /models/qwen2.5-7b然后启动时直接把模型名换成路径vllm serve /models/qwen2.5-7b这一步看似不起眼但能省掉后面很多麻烦。线上环境我基本都建议预先把模型文件准备到内网机器上既是稳定性考虑也避免了每次启动都去外网拉权重的尴尬。3. 动手安装pip 与 Docker 两条路都走一遍3.1 最快的方式pip install vllm进入虚拟环境后直接执行pip install -U vllm国内服务器如果 pip 下载慢可以临时用清华源加速pip install -U vllm -i https://pypi.tuna.tsinghua.edu.cn/simple安装完成后验证一下python -c import vllm; print(vllm.__version__)能正常输出版本号说明核心库已经就位。这里再强调一次安装过程中如果 pip 提示要重装或升级 torch让它做就行不要手动干预。vLLM 和 torch 的版本是绑定测试过的自动解析出来的组合通常是最稳的。cuda 版本这事再补充一点如果你确认当前环境是 CUDA 12.8 且需要对应的 vLLM wheel去官方安装文档里找 cu128 对应的安装命令复制执行即可。命令每年都在变没必要背。3.2 最省心的方式Docker 镜像 vllm/vllm-openai如果你不想折腾驱动和 Python 依赖Docker 是最佳选择。官方镜像vllm/vllm-openai把 vLLM 和运行环境全部打包好了你只需要保证宿主机有 NVIDIA 驱动和 NVIDIA Container Toolkit。启动一个容器来加载模型命令大概长这样docker run --runtime nvidia --gpus all \ -p 8000:8000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --ipchost \ vllm/vllm-openai:v0.27.1 \ --model Qwen/Qwen3-Embedding-0.6B \ --task embedding这里我用v0.27.1这个 tag 举例。镜像 tag 通常和 vLLM 版本绑定实际使用时建议以官方 Docker Hub 标注的 latest 或你验证过的版本号为准。两个细节值得注意一是-v挂载了 Hugging Face 缓存目录这样模型下载一次后下次启动就不用重新拉。二是--ipchost这个参数经常被忽略。vLLM 在张量并行或多进程时会用到共享内存默认的/dev/shm太小会导致启动报错或崩溃加上它最保险。3.3 Windows 用户怎么办WSL2 与社区版vLLM 官方主线一直以 Linux 为第一优先级Windows 原生支持不是官方推荐路径。但 Windows 用户不是没得玩主流做法是 WSL2。在 Windows 上装好 WSL2 和 Ubuntu 22.04 后Windows 的 NVIDIA 驱动会自动透传给 WSL2 里的 CUDA。你在 WSL 终端里跑一下nvidia-smi能看到显卡信息就说明环境通了。接下来所有安装步骤都和 Linux 完全一致。至于网上说的vLLM Windows 社区版确实有爱好者编译的 Windows 版本原理是通过 DirectML 或者特殊适配绕过一些 CUDA 限制。我实际试下来小模型能跑但稳定性、兼容性和性能都不如 WSL2 方案。我的态度是Windows 社区版可以装在测试机上玩玩别用于生产环境。4. 启动模型一条命令把推理服务跑起来4.1 最小启动命令与参数速览vLLM 启动 OpenAI 兼容 API 服务新版本推荐直接用vllm serve子命令vllm serve Qwen/Qwen2.5-7B-Instruct \ --host 0.0.0.0 \ --port 8000 \ --gpu-memory-utilization 0.92 \ --max-model-len 8192老版本或部分文档里会写python -m vllm.entrypoints.openai.api_server --model ...效果是一样的。启动后你会看到模型加载日志、KV Cache 分配信息最后出现类似Starting vLLM API server的提示说明服务已经起来了。几个最常用的参数我直接列成表参数作用我的推荐--model模型名或模型目录Hugging Face 名称或本地路径--host监听地址仅本机访问用 127.0.0.1对外开放用 0.0.0.0--portAPI 端口默认 8000冲突就改--gpu-memory-utilization控制 vLLM 可用显存比例0.9 起调显存紧张可到 0.95--max-model-len最大上下文长度不设满按业务实际需求设--tensor-parallel-size多卡张量并行1 表示单卡多卡按实际卡数设--served-model-name对外暴露的模型名用于隐藏真实模型路径4.2 部署 DeepSeek 系列模型的实际命令如果你用的是 DeepSeek 模型命令结构和 Qwen 完全一样。比如在单张 24GB 显卡上部署 7B 蒸馏版vllm serve deepseek-ai/DeepSeek-R1-Distill-Qwen-7B \ --gpu-memory-utilization 0.93 \ --max-model-len 8192如果是 32B 蒸馏版单卡基本放不下需要两张卡一起扛vllm serve deepseek-ai/DeepSeek-R1-Distill-Qwen-32B-AWQ \ --tensor-parallel-size 2 \ --max-model-len 8192注意我特意选了带AWQ的量化版本否则 32B FP16 权重就要 64GB 左右两张 24GB 卡也悬。量化的事后面单独讲你先记住大模型就用量化版这条经验。4.3 怎么验证服务是否正常curl 自测服务启动后先看模型列表curl http://localhost:8000/v1/models正常会返回一个包含模型名的 JSON 数组。接着发一个对话测试curl http://localhost:8000/v1/chat/completions \ -H Content-Type: application/json \ -d { model: Qwen/Qwen2.5-7B-Instruct, messages: [{role: user, content: 你好请简单介绍一下自己}], max_tokens: 100 }能拿到正常回答说明这条链路已经通了。你的业务代码只需要把 OpenAI SDK 的base_url改成http://你的服务器IP:8000理论上就能直接接入 vLLM。4.4 顺带说一句vLLM 也能跑 embedding 模型很多人以为 vLLM 只能跑生成式大语言模型其实它现在也支持 embedding 任务。比如加载 Qwen3-Embedding-0.6Bvllm serve Qwen/Qwen3-Embedding-0.6B --task embedding关键就在--task embedding。如果不加这个参数vLLM 默认按生成式模型加载行为会完全不对。启动后用/v1/embeddings接口测试curl http://localhost:8000/v1/embeddings \ -H Content-Type: application/json \ -d { model: Qwen/Qwen3-Embedding-0.6B, input: [hello world] }返回里能看到一个维度很长的向量数组。把这个接口接进 RAG 的向量检索链路一个服务就同时搞定了生成和 embedding省去维护两套推理引擎的成本。5. 显存调优从 OOM 到吃得满满的实战套路5.1 先算明白显存都花在哪里调优之前得先搞清楚 vLLM 的显存都花在哪些地方。三个大头模型权重、KV Cache、运行时开销。模型权重很好估算参数量乘以每个参数占用的字节数。FP16 格式每个参数占 2 字节7B 模型权重就是 7×1e9×2 ≈ 14GB。INT4 量化后变成 7×1e9×0.5 ≈ 3.5GB差距立刻出来。KV Cache 的估算公式是这样的KV Cache 大小 ≈ 2 × 层数 × KV头数 × 头维度 × 批大小 × 序列长度 × 每个元素字节数。拿 Qwen2.5-7B-Instruct 举例它 28 层、4 个 KV 头、头维度 128。FP16 下单 token 的 KV Cache 占用是 2 × 28 × 4 × 128 × 2 ≈ 57KB。如果并发 16、上下文 8192KV Cache 总量就是 57KB × 16 × 8192 ≈ 7GB。再加上 CUDA graph 和激活值等运行时占用 1-2GB一个 7B 模型在 24GB 显卡上基本就是 14 7 2 23GB非常极限。所以很多时候你以为的 OOM 不是权重装不下而是 KV Cache 预分配太多。5.2 调优第一招控制 gpu-memory-utilization--gpu-memory-utilization是 vLLM 所有显存参数里最关键的一个。它指定的是 vLLM 能占用的显存占整卡比例默认 0.9。我个人的实操经验是专门跑模型的机器可以大胆调到 0.92-0.95留一点余量给显示服务和驱动就行。但如果这张卡上还跑了别的进程、或者你要同时起多个 vLLM 实例就必须降下来。当年我踩过一个坑为了压榨显存直接把 utilization 调到 0.98结果机器上桌面环境本身就占了几百 MB 显存vLLM 启动到一半直接报 CUDA OOM日志里还看不出具体原因。后来把桌面关了再启动才通过。这个参数不是越高越好0.95 基本是实战极限。5.3 调优第二招管住上下文长度与并发数--max-model-len直接影响 KV Cache 的预分配大小。vLLM 不是按实际请求动态扩容 KV Cache 的而是按你设定的最大值一次性预分配。假设你设了 128K 上下文就算业务里没人用那么长显存也已经被占走了。所以我建议--max-model-len永远不要设满模型支持的极限按你的业务实际需求来。普通对话场景 8192 够用处理长文档再调到 16384 或 32768够用就行省下来的显存可以留给并发。同理--max-num-seqs限制最大并发请求数它也直接影响 KV Cache 上限。如果业务并发不高把这个值调小同样能省显存。我常用的组合是24GB 单卡跑 7B--max-model-len 8192 --max-num-seqs 16稳定运行。5.4 调优第三招量化让显存减半量化是解决显存问题的终极手段之一。FP16 权重换成 INT4模型权重直接从 14GB 降到 3.5GB省下来的显存全部可以给 KV Cache 和并发用。vLLM 对量化模型的支持很成熟常见的有 AWQ、GPTQ、FP8。我实际用得最多的是 AWQ部署命令没什么额外负担vllm serve deepseek-ai/DeepSeek-R1-Distill-Qwen-32B-AWQ \ --tensor-parallel-size 2 \ --max-model-len 8192vLLM 会自动识别模型配置里的quant_method不需要手动指定。如果遇到个别模型没被自动识别再用--quantization awq显式指定。量化的代价是精度有一点损失但对日常对话和绝大多数业务场景主观感受差别不大。我的原则是显存不够优先量化量化还不够再考虑多卡。5.5 调优第四招多卡张量并行与 CPU 卸载一张卡实在装不下就上多卡。--tensor-parallel-size 2会把模型权重和 KV Cache 切到两张卡上并行计算。前提是卡之间有直连通道NVLink 最佳PCIe 也能跑但通信慢一些。多卡启动前建议先用nvidia-smi topo -m看看卡之间的拓扑。另一个思路是 CPU 卸载--cpu-offload-gb 20可以把一部分权重放到内存里显存压力大减但推理速度明显下降。我只有在机器内存富余、显存实在不够时才用它纯属兜底方案。另外--enforce-eager可以关闭 CUDA graph能省 1GB 左右显存并加快启动速度但推理性能会下降适合显存极限状况下的应急。5.6 一张 24GB 显卡下的完整调优记录我拿一次真实部署来复盘。目标在单张 RTX 4090 上跑 Qwen2.5-7B-Instruct要求稳定支撑 16 并发和 8K 上下文。第一次启动直接用默认参数结果日志里出现CUDA out of memory。我按前面的公式算了一下权重 14GB KV Cache 7GB 运行时约 2GB24GB 确实很极限。于是做了三个调整vllm serve Qwen/Qwen2.5-7B-Instruct \ --gpu-memory-utilization 0.93 \ --max-model-len 8192 \ --max-num-seqs 16再次启动日志显示显存占用约 22.5GB / 24GB服务正常起来。压测时 GPU 利用率能稳定在 80% 以上吞吐比之前用普通推理框架高了将近三倍。之后我又试了换 AWQ 量化版权重降到 4GB 左右同样参数下显存只占 13GB 左右剩下的空间甚至可以再开一个实例。所以如果你机器显存紧张我的优先级建议是先量化再调上下文长度最后才考虑多卡。6. 常见问题与排查实录6.1 CUDA out of memory 到底怎么解CUDA OOM 是 vLLM 部署里最常见的报错但它的原因有几种处理方式完全不同。第一种是权重本身就放不下。解法是换量化模型或加卡。第二种是 KV Cache 预分配超了。看日志里Maximum concurrency for ... tokens这类信息对照 KV Cache 估算调小--max-model-len或--max-num-seqs。第三种是总显存被其他进程占了先nvidia-smi看清楚把无关进程清理掉再稍微调低--gpu-memory-utilization。我自己还有一个习惯遇到 OOM第一件事不是改参数而是把 vLLM 启动日志完整看一遍。日志里其实已经写了当前 GPU 总显存、模型权重占用、KV Cache 分配的目标值对照着一算就知道瓶颈在哪。6.2 模型序列长度报错启动时如果报类似The models max seq len is xxx的错误意思是模型配置里的最大序列长度超过了当前环境能支持的范围。常见于原模型支持 128K但你显存不够。解法就是显式设置--max-model-len比如强制 8192 或 16384。注意 vLLM 的这个值是指上下文的总长度也就是 prompt 加生成 token 的总和不是单纯生成多少字。6.3 模型下载慢或失败直接从 Hugging Face 下载经常不稳定。我的做法前面提过用 ModelScope 先把模型下到本地再加载本地目录。modelscope download --model Qwen/Qwen2.5-7B-Instruct --local_dir /models/qwen2.5-7b这个过程相当于你有一个稳定的本地源后面启动、重启都不会依赖外网。下载完记得检查目录完整性至少要有config.json、模型权重文件、tokenizer相关文件。缺文件时 vLLM 的报错信息有时很含糊先怀疑文件不完整。6.4 端口被占用与多实例默认 8000 端口被占改--port 8001就行。如果一台机器要同时跑多个模型每个实例用不同端口同时必须把每个实例的--gpu-memory-utilization调低比如两张卡跑两个模型就各设 0.45 左右给彼此留余地。多实例还有一个坑共享显存的卡上如果两个实例加起来超了显存第二个实例启动时会直接报 OOM。先算清楚总容量再分配比例。6.5 WSL2 与容器环境常见问题在 Windows WSL2 里跑 vLLM最常见的问题是nvidia-smi找不到。这个一般不是没装驱动而是 WSL2 没有正确启用 GPU 透传去确认 Windows 端 NVIDIA 驱动是 WSL 版本重启 WSL 一般能解决。Docker 环境里如果报 NCCL 通信错误检查容器有没有加--ipchost以及--gpus all是否正确传入了 GPU。张量并行模式下 NCCL 对共享内存和网络配置都很敏感我建议先用单卡把流程跑通再加多卡。6.6 疑难杂症速查表现象大概率原因解决动作启动即 CUDA OOM权重或 KV Cache 超限量化模型、调低 max-model-len、关 CUDA graph指定张量并行后启动极慢卡间通信异常查 NVLink 拓扑容器加 --ipchost请求时报序列长度超限max-model-len 小于请求长度调大 max-model-len或截断输入推理速度远低于预期CPU 卸载生效或未用 CUDA graph检查日志中 offload 情况关掉不必要参数API 返回乱码或不完整量化模型精度问题或温度参数异常换回 FP16 对比测试多实例互相 OOM显存总分配超限每实例单独核算 utilization7. 我实际部署中的几个习惯写了这么多最后说几个我自己长期用下来的习惯。一是生产环境一定用 Docker 镜像并锁定版本号不要把宿主机里的 Python 环境当生产环境出问题的恢复成本太高。二是任何一次参数调整只动一个变量改完启动、测一轮、记录结果再动下一个。三是启动前先跑nvidia-smi确认机器状态我至少有两次是被残留进程占了显存白白排查了半天。还有一个小技巧如果你要在同一张卡上反复试不同参数别来回重启 vLLM直接加--enable-prefix-caching相同的 prompt 前缀会被缓存实测在 RAG 场景和多轮对话里效果很明显。我自己部署的经验是vLLM 的上手成本主要集中在前半天——环境、参数、显存概念理清楚之后后面基本就是复制粘贴的事。希望这篇记录能帮你少踩几个坑。