最近一两年做大模型推理,绕不开 vLLM 这个名字。它最开始是 LMSYS 内部做聊天评测时被显存逼出来的产物,后来开源成了目前工业界部署 LLM 的主流框架之一。很多人从 Ollama、LM Studio 开始接触本地模型,跑通一两个小模型后,一旦想把模型规模提到 7B、14B,甚至部署 DeepSeek 这种动不动几十上百 G 权重的模型,很快就会发现显存完全不够用,并发稍微一起来就 OOM,速度也拉胯。这时候换到 vLLM,往往能明显感觉到两个变化:同样一张卡能装下的模型更大了,而且同时回答多个请求的时候不再“排队到天荒地老”。
这篇东西不是官方文档的复述,是我自己从“装个 Python 包”到“在服务环境里稳定跑起多路并发”的完整记录。内容包括 vLLM 的安装(涵盖 pip、Docker、源码编译三条路)、模型服务的启动参数怎么填、以及最让人头疼的显存到底是怎么分配和调优的。适用对象很明确:已经用 Ollama 跑过小模型、想进一步做真正并发推理服务的人;或者刚开始接触 vLLM、被一堆版本号和 CUDA 匹配问题绕晕的新手。
1. 先搞懂 vLLM 凭什么能省显存:PagedAttention 和连续批处理
1.1 传统推理框架的显存浪费在哪里
在动手安装之前,我建议先花十分钟理解 vLLM 的底层思路,否则后面调参完全靠试错。传统 transformer 推理服务(包括很多早期的 API 封装),给每个请求分配显存是按“最大可能长度”一次性劈出去的。比如一个会话窗口限制 4096 token,那么前面哪怕只生成 100 个 token,系统也已经把 4096 token 对应的 KV Cache(键值缓存)空间预留出来了。结果就是内存中大片区域是空的但不允许别人用,请求多的时候每个都晃荡着大片的预留空间,显存很快就被无效占满。
vLLM 第一个关键创新是 PagedAttention,思路和操作系统的分页内存管理一致。KV Cache 不再连续占一大块内存,而是拆成固定大小的 block 来管理,按需分配。一个请求的生成过程里,前面的 token 计算完,它对应的 KV 只占一小个 block;后面需要更多空间,再从全局空闲块列表里取新的 block。这样不同请求的 KV Cache 可以在物理上交错排列在一起,显存碎片和“为未来预留导致的空洞”大幅减少。
1.2 连续批处理:为什么并发一上去,别人家卡死而你还能动
另一个核心机制是连续批处理(continuous batching)。早期 LLM 服务的批处理逻辑很粗糙:攒够 N 个请求,组成一个 batch,等这批全部生成完,再统一返回,然后开始下一批。只要 batch 里有一个请求上下文特别长,整批人都要陪着等。
vLLM 的调度粒度不是“请求”而是“iteration”,也就是每次只前进一步(生成一个 token)。每轮迭代开始前,调度器会把当前仍在生成中、并且显存足够容纳下一步计算的请求组合成 batch;某个请求结束了就释放它的 KV block,下一轮新请求立刻补进来。因此不会出现“尾请求拖垮整批”的情况,吞吐量高很多。
1.3 知道这些原理,后面调优才有方向
记住这一点非常关键:vLLM 的显存分配策略是“预先圈地,动态出租”。启动时它会尽可能把所有可见 GPU 显存都算进自己的池子里,按 block 划分,再根据你的并发和上下文设置动态分配。所以你会看到 vLLM 一启动,nvidia-smi里显存占用立刻冲上去,不用慌,它是在把地圈好,不是全被模型权重占了。显存调优的思路,本质上就是决定“圈多少地给 KV Cache、每个请求最多能租多少地(上下文长度)、同时多少个请求能进来”。
2. 开工之前:显卡、驱动、CUDA、Python 一次性对齐
2.1 环境要求先心里有数
先说结论:Linux + NVIDIA 显卡 + 显存足够,是最省心的组合。vLLM 官方最优先支持的是 CUDA 的 Linux 环境,Windows 属于“社区支持”(下面我单独说 Windows 用户怎么办)。如果你手里是 AMD 显卡,vLLM 也有 ROCm 版本支持,但踩坑概率明显更高;纯 CPU 环境运行 vLLM 存在但不推荐服务化,推理速度很难看。
具体版本要求我就不给死板表格了,因为 vLLM 迭代很快,不同版本对应的 Python、PyTorch、CUDA 要求一直在变。我自己现在的固定搭配是:
- Python 3.10 或 3.11(目前最稳,3.12 在个别版本会遇到依赖编译的问题)
- CUDA 12.x 优先,版本不要太老
- NVIDIA 驱动:选择足够新的版本,因为驱动向后兼容 CUDA runtime,但驱动版本太老会直接加载不了新 CUDA 库
- GCC/make:源码编译时用,版本别太老就行
我踩过的最大一个坑是只看 PyPI 上的版本号,没留意本地驱动所支持的 CUDA 版本上限。驱动版本不够时,vLLM 未必会在安装时报错,而是等你启动模型时才提示 CUDA driver 版本不匹配,排查起来特别费时间。你可以用nvidia-smi右上角查看驱动支持的 CUDA 版本,比如显示 “CUDA Version: 12.4”,那你的环境最多按 CUDA 12.4 左右去匹配,没必要强行上 12.8 的工具链。
2.2 用 conda 隔离环境,别把系统 Python 搞乱
vLLM 的依赖比较深,它会拉取特定版本的 PyTorch、transformers、tokenizers、safetensors 等一堆东西。如果直接装进系统 Python,过两个月你会发现其他项目也被带着升级了。我现在的固定操作:
conda create -n vllm python=3.11 -y conda activate vllm pip install --upgrade pip没有 conda 的,用python -m venv也行,但 conda 在切换 CUDA 相关环境时更省心。
2.3 Windows 用户的选择:WSL2 优先
热词里能看到“vllm windows 社区版”这种说法,确实 Windows 不是 vLLM 的一等公民,但也不是不能用。我的建议分三种情况:
- 只是想在 Windows 上快速体验:优先装 WSL2,然后在 Ubuntu 里按 Linux 流程走。网络、显存透传都很好用,唯一的代价是多耗一点内存,但比在 Windows 原生环境里跟编译器和链接库搏斗舒服得多。
- 就想在 Windows 原生环境跑:可以找社区构建的 wheel,比如某些第三方维护的
vllm-windows包,但版本往往落后于官方,且部分算子走的是 CPU fallback 路径,性能打折扣。 - 用 Docker Desktop + WSL2 backend:这种其实也是对多数人最平滑的方案,下面安装环节我会展开。
如果你是一些较老显卡,先确认是否支持 bf16、FlashAttention 要求的算力。最直接的办法是装好后直接跑一个 7B 模型,若启动日志里出现算子不支持、flash_attn报错优先从 Windows 原生环境的兼容性方向排查。
3. 安装 vLLM:三条路线,按场景自选
3.1 路线一:pip 直装,最快,但不一定适配你的 CUDA
新版本 vLLM 在 PyPI 上已经有了针对不同 CUDA 版本的包。默认情况下pip install vllm装到的包,会对应某个默认 CUDA 版本(例如 CUDA 12.6)。如果你本地就是 12.6,那直接用:
pip install vllm装完验证一下:
python -c "import vllm; print(vllm.__version__)"如果你的 CUDA 是 12.8 或更新,或者 vLLM 新版本拆出了类似vllm-cu128这样的专用包,直接按对应名字装即可。命令大概是:
pip install vllm-cu128怎么判断自己到底该装哪个?我的建议是:先看nvidia-smi支持的 CUDA 版本,再看你要用的模型对运算符的要求。比如某些最新的模型或量化算子要依赖 CUDA 12.8 才被官方测试覆盖,那就选 cu128 包。如果只是普通推理,默认包即可,没必要追求版本号最新。
3.2 路线二:Docker 镜像,服务器部署最省心
如果你的目标是把 vLLM 跑在公司服务器或者自己长期用的机器上,我非常推荐 Docker 方式。官方镜像vllm/vllm-openai已经把 CUDA runtime、PyTorch、vLLM 都打包好了,你只需要保证宿主机有 NVIDIA 驱动和 NVIDIA Container Toolkit。启动一个 OpenAI 兼容服务的命令长这样:
docker run --gpus all \ -p 8000:8000 \ --ipc=host \ --shm-size=8g \ vllm/vllm-openai:最新标签 \ --model Qwen/Qwen2.5-7B-Instruct热词里出现的vllm/vllm-openai:v0.27.1就是这类镜像的版本标签之一。做镜像选型时,最好结合模型发布时间的先后:新模型如果依赖新版本 tokenizer 或算子,直接拉最新镜像。--shm-size这个参数容易被忽略,vLLM 在加载模型和数据并行时会用共享内存做进程间通信,默认的 64MB 大概率不够,会报 shared memory 相关的异常。
安装 NVIDIA Container Toolkit 后,可以用docker run --gpus all nvidia/cuda:12.4.0-base-ubuntu22.04 nvidia-smi来验证容器里能否看到显卡。这个测试镜像跑通了,再跑 vLLM 镜像。
3.3 路线三:源码编译,什么时候才需要这么做
如果 pip 包不满足你需要的 commit 版本,或者你要改 vLLM 源码做二次开发,才需要源码编译。日常使用我不建议这条路,因为编译时间很长,还会遇到编译器和 CUDA 库版本匹配的问题。
git clone https://github.com/vllm-project/vllm.git cd vllm pip install -e . --no-build-isolation编译前确认三件事:nvcc --version能输出正确的 CUDA 版本;gcc --version版本足够新;Python 虚拟环境已激活。我第一次源码编译时就是漏了--no-build-isolation,导致 pip 重新拉取隔离环境的依赖,跟当前虚拟环境里的 PyTorch 不是一套,最后链接阶段报一堆 undefined symbol,浪费了一下午。
如果只是需要 GPU 算子层面的优化或调试,建议仍然用镜像或 pip 包跑主体,再用单独开发环境编译测试,别把部署机器搞成编译机。
3.4 安装完必须做的验证
装完不急着启动大模型,先跑一个极小的模型验证链路:
python -c "from vllm import LLM; llm = LLM(model='Qwen/Qwen2.5-1.5B-Instruct'); print(llm.generate(['你好']))"这一步能快速暴露大部分环境问题:CUDA 不可用、libnccl缺失、flash_attn编译失败等。1.5B 权重大概 3GB,显存不是问题的机器都能跑过。
4. 启动模型:从最小命令到多卡并行
4.1 用 OpenAI 兼容接口启动
vLLM 最适合的用法是启动一个 OpenAI 兼容接口服务,这样 OpenAI SDK、LangChain、Dify、Chatbox 之类都能直接接。最基本的启动命令:
python -m vllm.entrypoints.openai.api_server \ --model Qwen/Qwen2.5-7B-Instruct \ --host 0.0.0.0 \ --port 8000 \ --max-model-len 8192看到日志里出现类似Uvicorn running on http://0.0.0.0:8000就说明起来了。然后可以用 curl 测试:
curl -X POST http://127.0.0.1:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "Qwen/Qwen2.5-7B-Instruct", "messages": [{"role": "user", "content": "介绍一下 vLLM"}] }'4.2 启动常见模型的参数心得
部署 DeepSeek 系列模型是现在的热点。如果你是部署 DeepSeek-R1 蒸馏版(比如deepseek-ai/DeepSeek-R1-Distill-Qwen-7B),命令和普通模型差别不大:
python -m vllm.entrypoints.openai.api_server \ --model deepseek-ai/DeepSeek-R1-Distill-Qwen-7B \ --reasoning-parser deepseek_r1 \ --max-model-len 8192--reasoning-parser deepseek_r1是让 vLLM 正确解析 R1 的思考标签,如果用不到思考内容可以不加。如果你的显存不足以支撑 7B 蒸馏版,可以换 1.5B 蒸馏版,大多数普通问答场景也都够用了。R1 参数较大的版本动辄几百 GB 权重,不是单卡能跑的,别硬上。
4.3 多卡并行:tensor-parallel-size 用法
显存不够但有不止一块显卡时,可以用张量并行把模型权重和 KV Cache 拆分到多张卡:
python -m vllm.entrypoints.openai.api_server \ --model Qwen/Qwen2.5-14B-Instruct \ --tensor-parallel-size 2 \ --max-model-len 8192这块我要多说两句。张量并行不是“免费的显存扩容”,通信开销很大,两张卡之间的 NVLink/PCIe 带宽决定扩展效率。两张卡跑 14B 通常能接近线性收益,但四张卡跑一个很小的模型反而可能比单卡还慢。另外,--tensor-parallel-size必须能整除模型的注意力头数。如果报The number of attention heads相关的错误,就说明该模型不支持你指定的并行度。
如果你用的是 Docker 方式,多卡启动需要显式传设备。比如宿主机有 4 张卡,只让容器用第 2、3 张:
docker run --gpus '"device=1,2"' \ -p 8000:8000 \ --ipc=host --shm-size=8g \ vllm/vllm-openai:latest \ --model Qwen/Qwen2.5-14B-Instruct \ --tensor-parallel-size 24.4 启动报错的通用排查顺序
启动失败时,我先按这个顺序排查,省掉很多无效尝试:
- 看日志里第一段异常是什么。绝大多数是缺少依赖或算子不匹配,而不是模型本身问题。
- 确认模型路径写对了。
--model可以填 HuggingFace 模型 ID,也可以填本地目录,本地目录建议绝对路径。 - 看显存是否足够加载权重。权重显存约为参数量 × 字节数。例如 7B 模型用 BF16(2 字节)加载,权重约 14GB;12GB 显存直接加载都会爆,先考虑量化版本。
- 看是否是并发导致启动时
max-model-len过大。上下文长度设太高时,vLLM 会根据剩余显存计算 KV Cache,能容纳的并发数会非常低,甚至为 0,日志会给出显眼提示。
5. 显存调优:从 OOM 到高并发的完整思路
5.1 先明白显存账单是怎么算的
一张卡上的显存被 vLLM 分成几块:模型权重、激活值(activation)、KV Cache、以及各种算子临时缓冲区。其中权重大小基本是固定的,激活值在 batch 大的时候会涨,KV Cache 是动态的,也是优化空间最大的。
举个例子,Qwen2.5-7B-Instruct 的结构参数大致是 28 层注意力层、4 个 KV head、每个 head 的维度是 128,KV Cache 用 BF16(每元素 2 字节)。那么每个 token 每层需要的 KV 显存大约是 2(key 和 value 两份) × 4 × 128 × 2 字节 = 2048 字节,28 层就是 57344 字节,约 56KB。如果你的 GPU 能拿出 10GB 给 KV Cache,理论上能容纳的上下文总时长约为 10GB / 56KB ≈ 18 万个 token 左右。但注意,这 18 万不是单个请求的长度,而是所有并发请求填满时的总和上限。所以max-model-len越大,vLLM 就会把一部分 KV 空间预留出来,对应并发就会下降。
这个计算不用背,关键是理解三个变量之间的关系:模型结构(KV per token)、KV Cache 总预算、上下文长度。
5.2 显存调优的第一参数:gpu-memory-utilization
--gpu-memory-utilization控制 vLLM 将多少比例的 GPU 显存纳入自己的分配池,默认是 0.9。也就是说,一张 24GB 的卡,vLLM 会预分配约 21.6GB 用来放权重和 KV Cache,剩下的留给 CUDA context 和运行时。
调优建议:
- 如果机器只跑 vLLM 一个服务,0.9 是合理值,甚至 0.95 都行。但不要把 0.95 当成默认,因为 PyTorch 和 CUDA 本身还会占一点显存,留太少容易出现“服务起来但某个算子在 batch 增大时临时申请显存失败”的问题。
- 如果要和别的服务共享显卡,比如同时跑一个 embedder 服务或不方便停掉的训练进程,把
--gpu-memory-utilization调到 0.6 甚至更低,确保其他进程也有空间。 - 如果出现启动时直接 CUDA OOM,检查是不是权重本身 + 上下文预留空间已经超过了卡的总显存,此时调低
max-model-len比调低 utilization 更有效。
具体启动命令示例:
python -m vllm.entrypoints.openai.api_server \ --model Qwen/Qwen2.5-7B-Instruct \ --gpu-memory-utilization 0.85 \ --max-model-len 4096 \ --max-num-seqs 645.3 几个不那么直观但很实用的开关
--enforce-eager:这个参数默认不开启,vLLM 会用 CUDA Graph 优化小算子执行,但 CUDA Graph 也会占一部分显存。显存非常紧时开启--enforce-eager,可以省掉 Graph 缓冲区的开销,代价是解码速度略降。如果模型启动时离 OOM 就差临门一脚,试它。
--kv-cache-dtype fp8:把 KV Cache 的精度从 BF16/FP16 降到 FP8,KV 占用直接减半。这个参数对部分新显卡效果显著,但要注意算子是否有 FP8 支持,日志里如果显示 fallback 到 FP16,那实际省不了多少。我的经验是:Hopper/Ada 架构以及更新显卡优先尝试,老架构不要抱太大期望。
--max-num-seqs:控制同时处理的序列数。默认值已经不小,但如果你的显存并不宽裕,把最大并发限制住,反而能避免突发流量把显存冲爆。调大它不一定会提高吞吐,因为 vLLM 会自动探测当前显存能容纳多少并发,它更像是一个“安全阀”。
--enable-prefix-caching:如果你的业务里大量请求共享相同的前缀(比如固定 system prompt、多轮对话的历史),开启前缀缓存能让这些重复计算直接命中,KV 空间也能复用。但是前缀比较杂乱、重复率不高的情况下收益有限,不要当默认开关无脑开。
5.4 常见 OOM 现象背后的原因分类
我把实际运行的 OOM 分成三类:
第一类,启动即 OOM。模型权重本身就超过了显存总量。比如 70B 模型 BF16 权重就要 140GB,单卡根本载不进去。此时要么换量化模型(AWQ/GPTQ 4bit 能降到 40GB 左右),要么上多卡张量并行,要么换小一号模型。
第二类,运行时 OOM,但启动日志正常。通常是 KV Cache 预分配没问题,但某个时刻并发上去后,序列长度总和超过了 KV 预算。日志里会出现类似Cannot schedule new requests或 CUDA OOM 的报错。解法并不是简单地降低gpu-memory-utilization,而是降低max-model-len或限制max-num-seqs。
第三类,偶发算子临时申请显存失败。发生在 batch size 增大、激活内存暴涨的时候。这是最隐蔽的一种,舒适区不容易复现,一测压力就暴露。我的做法是留至少 1-2GB 的余量(也就是 utilization 不要拉满到 0.98),同时把共享内存调大。
5.5 KV Cache 使用率怎么看
vLLM 的启动日志会给出一个比较清晰的概览,大意是:模型权重占了多少、KV Cache 总量是多少、最大可支持并发数是多少。运行过程中,服务日志会周期性输出当前使用的 token 数占 KV Cache 总量比例。结合你自己的业务来解读:如果kv_cache_usage长期接近 100%,说明显存够紧,可以考虑降低上下文长度或增加并发限制;如果长期低于 30%,说明显存资源溢出,可以放心调大并发或允许更长上下文。
还可以用nvidia-smi监控显存变化,但注意 vLLM 预分配的显存里,有一部分是“已分配未使用”的状态,所以在nvidia-smi里看到占用很高不一定代表 KV 已满。以 vLLM 日志里的使用率统计为准,不要光看监视器。
6. 热词里那些真实场景:Docker 加载 Embedding 模型、Windows 部署、镜像版本选择
6.1 Docker 加载 qwen3-embedding 这种小模型要注意什么
热词里提到docker vllm/vllm-openai:v0.27.1 加载 qwen3-embedding-0.6b,这个场景很典型。Embedding 模型体量小,但有人会觉得“这么小一个模型,随手就起来了”,结果反而踩坑。
启动命令类似:
docker run --gpus all -p 8000:8000 --ipc=host --shm-size=4g \ vllm/vllm-openai:v0.27.1 \ --model Qwen/Qwen3-Embedding-0.6B \ --task embedding \ --max-model-len 8192这里有几个细节:
- 必须通过
--task embedding告诉 vLLM 这是 embedding 服务,否则它会按文本生成模型启动,行为完全不对。 - 小模型加载很快,但 QA 三角色验证显存占用低时不要误以为服务没起来,等日志出现 embedding 相关的
model_executor加载完成再测试。 - 官方 API 是
/v1/embeddings,不是/v1/chat/completions,用 OpenAI SDK 时需要指定正确的 endpoint 路径。
如果你同时在跑 chat 模型和 embedding 模型,我的建议是分开两个服务进程、分开端口,不要试图让一个 vLLM 实例同时承载两种任务。
6.2 Windows 部署 vLLM 社区版的常见坑
如果你真的必须在 Windows 原生环境跑 vLLM,我从社区版实践里总结几个高频问题:
- Python 版本尽量用 3.11,Windows 上的预编译 wheel 基本只做这一版,3.10 和 3.12 要么找不到对应包,要么只能走源码编译。
- 需要手动装 Visual C++ Redistributable,否则运行
import vllm时可能报 DLL 加载失败。 - Windows 的路径分隔符和模型缓存目录要格外小心。HuggingFace 下载缓存里如果路径含中文和空格,加载经常出幺蛾子。
- 如果在 Windows 下频繁出现进程卡死,优先检查是不是 WDDM 驱动模式导致的显存回收问题。NVIDIA 在 Windows 上默认工作模式是 WDDM,对 CUDA 的显存管理不如 Linux 的 TCC 模式严格。有条件的话,在 BIOS 无所谓,而是要在驱动控制面板里看有没有 TCC 选项,显卡若是计算卡可直接切 TCC。
不过在 WSL2 那块,其实你的 NVIDIA 驱动在 Windows 宿主机上装好,WSL2 内部直接用nvidia-smi能看到卡,基本就是通的。这是 I 用下来最推荐的 Windows 玩法。
6.3 镜像版本别只看“最最新”
Docker 镜像标签的选法,我的习惯是:生产环境指定具体版本(如vllm/vllm-openai:v0.27.1),不要用latest,因为 vLLM 更新节奏很快,latest两天一变,你没法确定下次部署会拉到什么行为。小版本差异可能导致启动参数的弃用警告、默认 KV Cache 策略变化,这都会直接影响线上稳定。
每次部署新镜像前,把下面三件事做了:
- 读镜像对应版本的 Release Notes,看 CUDA 版本支持和 Python 要求。
- 在测试机用同样的镜像跑一遍你实际要用的模型,别只跑 tiny 模型,因为大模型加载路径更复杂。
- 记录下当前镜像跑出好效果的启动参数组合,形成自己的启动模板。
6.4 从 LM Studio / Ollama 迁移过来的配置习惯
不少人是先玩 Ollama/LM Studio 再迁到 vLLM,这两套东西最大的体验差异是:Ollama 默认给你包好一切、隐藏很多参数,vLLM 则把显存和调度参数暴露到你面前。迁移后最容易犯的错就是拿着 Ollama 里的做法(比如一次只服务一个模型、上下文填满)直接套到 vLLM。
在 Ollama 里你调--num_ctx只是影响单个会话;在 vLLM 里你在启动参数设定的--max-model-len是全局上限,所有并发请求共享这一份预算。所以同样的 8K 上下文,Ollama 下可以开一堆会话,vLLM 下则要精确控制并发。反过来想,正是这种“全局精确控制”,才让 vLLM 在真正高并发场景下能榨干显存。
从 Ollama 搬到 vLLM,我建议先把max-model-len从模型默认值往下调 1/4 到 1/2,观察并发能力和错误率,再逐步回调。这比一上来就拉满合理得多。
7. 集成到应用侧:OpenWebUI、Dify 和自定义调用
vLLM 本身不提供前端界面,它只提供 API 服务。很多人部署完一脸懵:“我模型起来了,但怎么在网页上聊天?”这时需要用到 OpenWebUI、Chatbox 或 Dify 这类前端/编排工具。
以 OpenWebUI 为例,在它的设置里把模型服务地址指向http://<你的服务器IP>:8000/v1,密钥随便填一个非空字符串(如果 vLLM 没开鉴权),就能在界面上看到你启动的模型并开始对话。如果你部署的是 DeepSeek 模型,建议在 OpenWebUI 的模型设置里把思维链的展示开启,否则 R1 系列模型的思考过程不会显示,输出可能显得“没头没尾”。
自定义调用就更简单了,OpenAI SDK 兼容一切都直接可用:
from openai import OpenAI client = OpenAI( base_url="http://127.0.0.1:8000/v1", api_key="sk-whatever", ) resp = client.chat.completions.create( model="Qwen/Qwen2.5-7B-Instruct", messages=[{"role": "user", "content": "用一句话解释什么是显存"}], max_tokens=200, ) print(resp.choices[0].message.content)7.1 开机自启和服务守护
如果你把这套服务当生产用,不要直接在前台跑python -m vllm...,退出终端服务就死了。Linux 下我用 systemd 管理,写一个最小服务单元文件,重点配置好Environment里的 CUDA 相关路径,启动命令里把日志重定向到独立文件,方便排查。关键是设置Restart=on-failure,遇到偶发 OOM 或进程崩溃,会自动拉起。
7.2 多服务部署顺序
如果是同一台机器跑 chat 模型、embedding 模型、前端界面,我建议按依赖顺序启动:先起 embedding,再起 chat,最后起前端。因为前端启动时会去探测后端模型列表,先起好了才不会报到空列表。同时也方便分清端口占用问题。
8. 一些从实操中沉淀下来的建议与避坑备忘
优先用 Docker 部署,pip 环境仅用于开发和快速验证。Docker 把 CUDA 版本、依赖库、算子编译结果都固化了,换机器不玄学。
任何大版本升级前,先备份当前能用的启动命令参数。尤其注意
--max-model-len、--gpu-memory-utilization这类核心参数,新版本对默认值可能有调整,直接沿用旧参数跑新版本经常出问题。模型权重优先下载到本地,不要每次启动都从 HuggingFace 在线拉。一是网络不稳定,二是启动时间拉长,三是 HUGGINGFACE 默认缓存目录在
/root/.cache/huggingface,磁盘空间不够时静默失败。建议显式设置:
export HF_HOME=/data/hf_home生产环境加
--served-model-name参数。这样前端/api 调用时用的模型名可以跟实际路径解耦,后续换模型版本不用改业务代码。别迷信“参数拉满”。很多人的显存调优是从“往死里开并发”开始的,结果换来 OOM,再抱怨 vLLM 不稳定。更合理的路径是:先用默认参数跑稳,用压测脚本逐步增加并发,监控 KV Cache 使用率,在接近瓶颈前停下来,留 10%-20% 的余量。
用
vllm serve代替老式的python -m vllm.entrypoints.openai.api_server。新版命令行更短,也好记,例如:
vllm serve Qwen/Qwen2.5-7B-Instruct \ --gpu-memory-utilization 0.85 \ --max-model-len 8192- 如果发现推理速度远低于预期,先查是不是落到了 CPU offload。某些显存不足的场景,vLLM 会自动启用 CPU offload(
--cpu-offload-gb),这种情况下速度会明显下降,但它救活了 OOM。我只是提醒你确认自己是否接受了这个隐性降级,别误判为“vLLM 太慢”。
最后聊点个人体会。vLLM 不是那种装上就能一劳永逸的工具,它更像一个把显存调度逻辑摊开给你看的管理器,你的水平有多高,它能榨出的性能就有多好。刚开始折腾时,我一度被 CUDA 版本、镜像标签还有一长串启动参数劝退过,但坚持把日志逐行看懂、把每个参数对应的显存账单想明白之后,后面部署任何模型都变得非常顺。如果你现在就卡在安装或者 OOM 上,别灰心,先照着文里的步骤跑通一个 1.5B 小模型,再慢慢加参数优化,整个链路通了,后面换大模型只是换权重而已。