我最早接触 vLLM是发现手里的 4090 跑不动一个大参数的对话模型。照网上各种方案折腾半天不是显存溢出就是启动报错最后静下来把 vLLM 的安装、启动和显存参数从头捋了一遍才真正跑顺。这篇文章就是那一整套过程的沉淀想给正在被 vLLM 安装和显存问题折磨的人一个可以直接照做的参考。vLLM 是当前最主流的高性能大模型推理框架之一核心卖点是 PagedAttention 显存管理能显著降低 KV Cache 占用、提升吞吐量。这篇文章适合两类人一是刚接触 vLLM、准备把模型从“能加载”推进到“能稳定服务”的新手二是已经被 OOM 或者其他显存问题搞得头大、想搞懂这些参数到底在干什么的人。我会把安装选型、启动方式、显存调优这三块掰开讲配上实际的参数计算和踩坑记录尽量让你一次走通。1. 核心概念先理清vLLM 到底解决了什么问题很多人在上手 vLLM 之前先被“推理框架”“KV Cache”“PagedAttention”这些词吓住。我尽量用大白话把它讲清楚。大模型在推理时其实每生成一个 token都要把之前所有已生成 token 的“记忆”重新计算一遍注意力。为了避免重复计算框架会把之前算好的 Key 和 Value 缓存下来这份缓存就叫 KV Cache。问题来了传统推理框架给这段缓存预分配一块连续显存但模型实际生成的 token 数量是动态的导致要么分配多了浪费要么分配少了溢出。vLLM 的 PagedAttention 借鉴了操作系统的虚拟内存分页思路把缓存分成小块用的时候按需分配。相当于不再要求整块内存连续碎片空间也能利用上。这就是 vLLM 在显存利用率上能领先其他框架的核心原因。也有人拿 vLLM 和 Ollama、LM Studio 横向对比。Ollama 的优势是开箱即用一条命令搞定模型下载和运行LM Studio 适合本地图形化操作对非开发者非常友好。但如果你要追求高吞吐、要做并发服务、要压榨 GPU 显存vLLM 仍然是最值得投入时间的那一个。理解这一点后续做技术选型心里就有底了。2. 环境准备与安装坑都在版本匹配里2.1 先说结论能用 pip 装就别自己编译vLLM 的安装官方推荐是 pip 直接装只要系统和 CUDA 版本匹配绝大多数情况下不用走源码编译这条路。安装前先确认三件事操作系统、GPU 驱动支持的 CUDA 版本、Python 版本。我的建议是Python 用 3.10 到 3.12vLLM 官方对这几个版本支持得最好。CUDA 工具包本身不用单独装vLLM 依赖 PyTorch 的预编译包而 PyTorch 的预编译包自带 CUDA runtime。你要关注的是显卡驱动的 CUDA 版本用 nvidia-smi 就能看到。驱动 CUDA 版本只要不低于 PyTorch 编译时的 CUDA 版本就行这点很多人会搞混。驱动版本不够就升级驱动一般 NVIDIA 驱动更新到最新对 CUDA 12.x 的支持就没问题。2.2 一条命令装完实测最稳的方式如果显卡驱动和 Python 版本确认没问题直接用pip install vllm国内网络环境建议走国内镜像源pip install vllm -i https://mirrors.aliyun.com/pypi/simple/这条命令会把 vLLM、对应版本的 PyTorch、transformers、tokenizers 等依赖一起拉下来。装完验证python -c import vllm; print(vllm.__version__)能打印出版本号就说明基础安装成功了。装好后我还建议用下面这条命令做一次快速验证确保 torch 和 CUDA 是通的python -c import torch; print(torch.cuda.is_available(), torch.cuda.device_count())我之前犯过一个错vLLM 装好了但 torch.cuda.is_available() 返回 False结果一跑模型就提示 CUDA 不可用。后来发现是虚拟环境里装了一个 CPU 版的 PyTorch把它卸掉重新让 vLLM 拉依赖才解决。出现这种情况优先检查是不是环境里存在多个 PyTorch 版本互相污染。2.3 源码编译在什么情况下才需要如果 GPU 太新或者要改 vLLM 底层算子比如你想自己调 custom kernel那才需要源码编译。源码安装流程一般是git clone https://github.com/attentionmech/vllm.git cd vllm pip install -e .注意这里源码编译非常考验编译工具链。需要提前装好 CMake、GCC我实测在本地用 Windows 编 vLLM 会遇到一堆 MSVC 兼容问题官方文档也说明 Windows 不是首要支持环境。生产环境建议直接用 Linux 容器或 WSL2能省掉八成的烦恼。源码编译失败的常见表现在编译到某个 CUDA 算子时报错报错信息往往指向编译器版本不匹配比如 GCC 版本过高或过低。解决方案一般是切换 GCC 到 9 或 11 版本再重建。其实绝大多数人用不到源码编译别在这里浪费时间。2.4 CUDA 12.8 与新版 vLLM 的兼容性说明现在网上有关于 CUDA 12.8、新版 vLLM 兼容性或编译失败之类的讨论核心其实还是版本对齐问题。如果你用的是较新的 GPU 架构而官方预编译 wheel 里包含的 CUDA runtime 版本较旧启动时会报“找不到 cuBLAS”或者直接提示不支持的 GPU 架构之类的错误。处理思路有两个一是升级显卡驱动让系统 CUDA 版本覆盖到 12.8 或更高二是等官方发布包含新版 CUDA runtime 的预编译版本。尽量不要在源码编译时强行指定过高的 CUDA 架构版本除非你清楚自己在做什么。CUDA 版本不是越高越好关键是驱动和依赖链能兼容。从网上反馈看新版 vLLM 在 CUDA 12.8 环境下配合新卡跑得很稳已知的坑基本都在环境版本不对齐。3. 模型加载与启动离线推理和在线服务两条路3.1 离线推理脚本里直接调用vLLM 的使用场景可以分成两类离线推理和服务化部署。离线推理适合写脚本、批量处理数据、做评测。它的好处是不用起 HTTP 服务代码里直接指定模型和参数就能出结果。from vllm import LLM, SamplingParams llm LLM(model/path/to/model) params SamplingParams(temperature0.7, max_tokens512) prompts [你好介绍一下你自己, Python 和 Java 的区别是什么] outputs llm.generate(prompts, params) for output in outputs: print(output.outputs[0].text)注意 model 参数可以传 HuggingFace 模型路径也可以传本地目录。我在生产环境几乎不用自动下载而是先把模型下载到本地磁盘再直接指本地路径。这样避免每次启动都去检查远端仓库也避免网络抖动导致启动失败。离线推理的好处是逻辑简单适合把生成逻辑集成进自己的数据处理管道。缺点是没有并发保护如果同一时刻多个请求打到这个进程你就得自己管理排队和缓存。3.2 在线服务一条命令拉起 OpenAI 兼容接口在线服务是 vLLM 的主场。vLLM 提供了 OpenAI 兼容的 API意味着你原来写的 OpenAI SDK 调用代码只需要改一下 base_url就能无缝切换到本地模型上。vllm serve /path/to/model \ --port 8000 \ --gpu-memory-utilization 0.9 \ --max-model-len 8192启动成功之后日志里会看到类似“Starting vLLM API server on http://0.0.0.0:8000”的字样。然后你用任何 OpenAI SDK 客户端都能访问from openai import OpenAI client OpenAI(api_keyEMPTY, base_urlhttp://localhost:8000/v1) resp client.chat.completions.create( model/path/to/model, messages[{role: user, content: 你好}] ) print(resp.choices[0].message.content)这里有个容易踩的坑如果你用了自定义模型路径client 端的 model 参数也要填路径而不是填模型名称。我第一次就是这么翻车的总是 404 not found。要么在启动命令里加 --served-model-name 起个别名要么 model 参数老老实实填完整路径。3.3 启动参数逐个拆解--gpu-memory-utilization、--max-model-len、--max-num-seqs启动 vLLM 时控制显存和吞吐的核心参数有三个。第一个是--gpu-memory-utilization这是显存利用率上限。默认值 0.9意思是给 KV Cache 最多用到 90% 显存。模型权重本身也要占显存剩下的空间才是缓存区。你设成 0.95可能遇到显存不足因为加载完权重后还要预留前向计算中间缓冲。我建议从 0.85 开始稳定后再慢慢调高。第二个是--max-model-len这是模型能处理的最大序列长度输入 输出总长。调大这个参数KV Cache 预留量也会跟着变大显存占用立即上升。VLLM 会按这个值估算缓存空间并按 chunk 预分配。如果你的实际场景根本不需要长上下文比如只做短对话那设成 2048 或 4096 就够用能省下大量显存。第三个是--max-num-seqs代表并发序列数。这个值越大能同时处理的请求越多但 KV Cache 占用也随之增长。4GB 显存的小卡设成 64 可能直接 OOM我一般先从 16 起步测试。还有两个并行参数值得提--tensor-parallel-size和--pipeline-parallel-size。前者把模型切分到多张卡上适合单卡装不下的模型后者按层切分适合多机。单卡场景不用动这些参数别为了“试试多卡”就乱加并行参数设置不当会导致性能不升反降还白白增加通信开销。3.4 模型下载与路径检查技巧如果你没有提前下载模型vLLM 默认会从 HuggingFace Hub 拉取这时候需要先设置镜像或者提前手动下载。更稳妥的方式是直接用 Git LFS 把模型拉到本地git lfs install git clone https://huggingface.co/Qwen/Qwen2.5-7B-Instruct然后启动时把 model 参数指到这个目录。用本地路径有另一个好处排查问题方便比如某个 safetensors 文件下载不完整错误日志会明确指向对应路径。如果启动时出现“Some weights are not tied”之类的警告多半是模型文件格式和 transformers 版本不兼容可以试试升级 transformers。4. 显存调优KV Cache 的估算公式与参数平衡4.1 KV Cache 显存占用怎么算调显存之前至少要会估算 KV Cache 占多大。公式不复杂KV Cache 显存 2 * 层数 * 每层 KV 维度 * 序列长度 * 批次大小 * 精度字节数其中乘以 2是因为 Key 和 Value 各一份。层数指的是模型隐藏层的数量。每层 KV 维度一般是 hidden_size 乘以注意力头数相关的值不同模型不一致。精度字节数里FP16 和 BF16 都是 2 字节FP8 是 1 字节INT8 也差不多。用 Qwen2.5-7B-Instruct 举例假设隐藏层维度 3584层数 28GQA 分组查询让 KV 维度比 MHA 小最终估算出来 1K token 的 KV Cache 大约占用 0.5 到 1GB 左右。也就是说如果你要处理 8K 上下文的并发请求单条请求的 KV Cache 就要几个 GB多条并发时量变很可观。4.2 参数组合的取舍先定 max-model-len再定并发我的调优顺序一般是这样先确认业务最长需要多少上下文确定 max-model-len。再根据显存总量和模型权重占用反推能接受的 KV Cache 上限。最后再定 max-num-seqs。千万别一开始就把三个参数都往大调显存爆了都分不清是哪个参数的问题。举一个具体的例子。单张 24GB 显存的 4090跑一个 7B 模型。模型权重在 FP16 下约占 14GB。先设 --gpu-memory-utilization 0.9也就是给 KV Cache 和其他缓冲留 10% 的余量大约可用 6GB 左右给 KV Cache。如果设 max-model-len 4096按上面估算KV Cache 留给 4 到 8 路并发差不多正好。这时候 max-num-seqs 可以设 8。如果你硬把 max-num-seqs 设成 64显存直接爆。还有一种情况是模型只占 4GB比如量化后的 7B 模型KV Cache 空间就更充裕。这种情况下可以把 max-num-seqs 往上提换取更高的吞吐。4.3 量化显存不够时的第一选择如果模型权重占用太高KV Cache 怎么调都不够用那就考虑量化。vLLM 支持 AWQ、GPTQ 和 FP8 等多种量化格式。量化的意思是把模型参数从 FP16 压缩到 INT4、INT8 或 FP8显存占用直接减半甚至减到四分之一。代价是推理精度略有下降但在对话、代码生成等场景下质量损失通常可以接受。这里补充一个实操经验如果你已经准备量化KV Cache 也能跟着量化。vLLM 里的kv-cache-dtype参数可以设成 fp8KV Cache 显存占用直接再减半。但也别盲目追求极致压缩我实测某些量化格式在特定模型上会有明显输出质量劣化建议先在评测集上对比一下再上线。4.4 显存监控与实测记录调优过程中叶底监控显存不能只靠猜。开一个终端实时看nvidia-smi -l 22 秒刷新一次观察显存使用曲线。vLLM 启动时会一次性把权重加载进去然后显存占用逐步上升直到填满你设定的 gpu-memory-utilization 阈值这是正常现象。如果服务一启动显存就飙升到 99%然后报 CUDA out of memory要么是权重本身就超了要么是 gpu-memory-utilization 设太高权重加最小 KV Cache 都放不下。另一种常见情况是启动时报“No available memory for the cache distribution policy”意思是 KV Cache 连最小预留量都不够了这时候只能降低 max-model-len 或并发数或者换量化模型。还有一个容易被忽略的点多张卡时 nvidia-smi 看到的显存和 vLLM 认为的显存可能对不上。vLLM 是按 CUDA_VISIBLE_DEVICES 指定的卡来分配的。如果没设置这个环境变量它可能把任务分散到所有卡上让你误以为显存占用异常。固定到单卡集群操作时先确认一下export CUDA_VISIBLE_DEVICES05. 常见问题与排查技巧实录5.1 问题速查表现象原因解决方式安装 vLLM 后 import 报错缺少某个 .so 文件CUDA 版本与 PyTorch cuda runtime 不兼容升级显卡驱动或用带新 CUDA 的镜像重新安装环境torch.cuda.is_available() 返回 False装错 CPU 版 torch卸载 torch 后重装 vLLM让它自动拉对应 GPU 版 torch启动时显存直接 OOMgpu-memory-utilization 设太高或 max-model-len 太大调低参数逐步逼近最优值并发请求一多就开始报错max-num-seqs 超过了 KV Cache 容量降低并发数或降低 max-model-len 给缓存腾空间启动卡在 “Loading model weights” 很久模型文件在远端网络耗时先下载到本地再用本地路径启动请求返回 404 model not found客户端传的模型名和启动时不一致设置 --served-model-name或 client 端补齐完整模型路径第一次请求特别慢模型尚未 warmup图编译和缓存分配正在初始化启动后先打一个健康请求或部署时加 warmup 脚本模型能跑但速度极慢并行参数配置不当或没吃满 GPU确认 tensor-parallel-size 是否正确用 nvidia-smi 看利用率5.2 三件容易被忽略的事第一件事是 swap 和内存。vLLM 虽然主要吃显存但 CPU 内存也会被大量占用尤其在加载模型权重和做 tokenizer 处理时。如果服务器 RAM 很小可能出现进程直接被杀。建议至少留出和模型权重等量的空闲 RAM。第二件事是日志里的警告不一定都要处理。“Could not find a matching cuDNN version”之类的警告只要没导致功能报错可以先忽略。真正需要关注的是 ERROR 级日志和 CUDA out of memory 这类致命错误。第三件事是系统并发上限。vLLM serve 模式默认使用 asyncio 事件循环底层连接数可能撑不住高并发请求。这时候可以调 ulimit提高文件描述符上限。生产环境可以用--api-key参数给服务加上访问控制避免裸奔。5.3 一个实用的排查思路遇到启动失败先别看模型先看环境。我惯用的排查顺序是先看 CUDA 是否可用再看模型路径是否正确再看模型文件是否完整最后才怀疑参数。这样能把问题收敛得很快。比如模型文件下载一半导致启动失败就比调参难查得多不先确认文件完整性只会在参数上折腾半天。6. 最后的实操经验谈方向选对之后vLLM 这套东西其实不需要神乎其技的操作。把基础概念吃透按步调调参大多数问题都能自己解决。我现在搭建新模型服务时习惯把环境准备、启动命令和显存参数都写成一条脚本每次新环境部署就跑一遍能省下大量重复排查。另外建议新手先别急着深入调优。第一次跑通哪怕参数不是最优先把流程走完再去慢慢抠显存利用率和并发量。毕竟 vLLM 主要优势就是稳定的服务化能力让它稳定跑起来再谈性能优化顺序一定别反过来。之后可以基于这个稳定的服务去扩展模型热切换、流式输出、多卡切分这些都是后续顺理成章的事但前提是你的服务已经立住了。
阅读完成 · 觉得有帮助?