最近在整理大模型推理服务选型时,看到 vLLM 核心团队所在公司 Inferact 正在官网和 GitHub 上挂出招聘信息。对开源项目来说,团队扩招往往不是热闹的信号,而是项目进入快速迭代期、社区和商业服务都需要更多工程力量的标志。vLLM 在高吞吐大模型推理领域的地位,已经让它成为生产环境部署 LLM 服务时很难绕开的一个选项。今天这篇文章就结合一次完整的 vLLM 部署实践,把核心原理、环境安装、服务启动、Docker 部署、参数调优以及昇腾等国产加速卡场景下的坑位都梳理清楚。
1. 背景与核心概念
1.1 vLLM 是什么
vLLM 是一个开源的 LLM 推理与服务引擎,由加州大学伯克利分校的研究团队发起,目前由 Inferact 公司主导开发和商业化落地。它最核心的贡献是把操作系统虚拟内存分页的思想引入大模型推理的显存管理,配合连续的动态批处理策略,让 GPU 在服务 LLM 时能够同时容纳更多请求,从而显著提高吞吐。
很多开发者第一次接触 vLLM 是因为项目需要把 Qwen、Llama、DeepSeek 这类开源大模型部署成对外可用的 API 服务。vLLM 提供了 OpenAI 兼容接口,这意味着原本对接 OpenAI 的应用,只需要修改base_url和api_key,就能无缝切换到本地部署的开源模型。这也是 vLLM 能迅速普及的重要原因之一。
1.2 为什么大模型服务需要 vLLM
早期用 Transformers 库直接做文本生成,每次请求会重新分配 KV Cache,显存碎片化严重,而且多路并发时 GPU 利用率很低。传统方案往往需要频繁重启进程,或者在框架层自己维护批处理逻辑,工程复杂度非常高。
vLLM 解决的核心问题是:大模型推理时,显存里有大量历史 token 的 KV Cache 需要保留,但提前分配固定大小的空间会造成极大浪费。vLLM 通过分页机制按需分配,并且通过调度器把多个请求拼接成一个大 batch 执行,同等显存下能承受数倍于 Naive 方案的并发量。
这里需要区分一个概念:vLLM 不是用来训练大模型的,它只负责训练完成后的推理部署和在线服务。训练场景需要的是 Megatron、DeepSpeed 这类框架,而 vLLM 的目标是把训练好的模型高效地“跑起来”,并且以标准 HTTP 接口对外提供服务。
1.3 为什么需要关注 vLLM 的版本演进
大模型推理框架目前仍在快速演进,vLLM 几乎每个月都有新特性发布。看到官方团队招聘的消息,也意味着他们正在扩展对更多硬件平台、更多模型架构、更多推理算子的支持。这意味着我们在技术选型时,不能只根据几个月前的经验固定版本,而要关注当前版本对自家模型、自家 GPU 型号的兼容情况。
本文后续内容会以主流的 vLLM 版本为示例进行说明,如果官方版本号有更新,建议以 vLLM 官方 GitHub 仓库的 README 和 Release Notes 为准,不要盲目升级,也不要长期停留在存在已知兼容性问题的旧版本上。
2. 环境准备与版本说明
2.1 硬件与操作系统
vLLM 最早主要面向 NVIDIA GPU 的 CUDA 生态,现在也在逐步支持 AMD ROCm、华为昇腾等平台。不过不同平台的适配进度差异很大,如果你的生产环境是昇腾 910B 这类国产加速卡,需要特别注意安装包的来源和版本匹配。
操作系统方面,生产环境推荐 Linux,主流发行版包括 Ubuntu 20.04/22.04、Rocky Linux、CentOS 7/8 等。本文示例以 Ubuntu 22.04 为主,其他系统只需要把包管理命令对应替换。
硬件配置上,部署 7B 级别模型建议显存不低于 16GB,20B 以上模型建议 40GB 以上显存。实际显存占用和模型量化方式、上下文长度、并发序列数都有关系,下面的实战环节会具体演示参数如何影响显存。
2.2 Python 与虚拟环境准备
vLLM 是 Python 项目,安装时需要 Python 3.9 到 3.12 之间的版本。为了不污染系统环境,建议使用 conda 或 venv 创建独立环境。
conda create -n vllm-env python=3.10 conda activate vllm-env如果使用 venv,可以这样创建:
python3 -m venv vllm-env source vllm-env/bin/activate这里需要提醒一下,vLLM 安装时会自动安装 PyTorch、transformers、tokenizers 等依赖,不同版本对这些依赖的版本范围有严格限制。如果你在同一个环境里还跑着其他深度学习项目,最好单独创建虚拟环境,避免依赖冲突。
2.3 安装 vLLM 的三种方式
第一种方式是通过 pip 直接安装预编译版本,最简单:
pip install vllm这种方式适合大多数 NVIDIA GPU 环境。安装完成后可以检查版本:
python -c "import vllm; print(vllm.__version__)"第二种方式是源码编译安装,适合需要修改源码、定制算子或适配特定硬件平台的场景。源码安装需要先克隆仓库,然后安装依赖并编译:
git clone https://github.com/vllm-project/vllm.git cd vllm pip install -e .源码编译时间较长,而且对编译工具链有要求,不熟悉构建流程的读者建议先使用 pip 安装验证功能。
第三种方式是使用 Docker 镜像,后面第 5 节会专门演示。Docker 方式对生产环境最友好,可以隔离底层驱动依赖,也方便在 GPU 服务器之间迁移。
3. 核心原理拆解:vLLM 为什么快
3.1 PagedAttention 显存管理
大模型在生成每个 token 时,都需要读取之前所有 token 对应的 KV Cache。如果 KV Cache 用固定大小块存储,不同序列长度不同,浪费空间非常可观。
vLLM 的 PagedAttention 把 KV Cache 存储到固定大小的块中,每个块可以存放一定数量 token 的 KV 数据。这些块不要求物理连续,而是通过块表映射。这样显存碎片问题得到缓解,序列增长时按需增加新块,不必一次性预留整块空间。
这个机制带来的直接收益是:同样显存下,可以用更大的 batch size 处理更多并发请求,GPU 计算资源利用率明显提升。这也是 vLLM 在长文本、多并发场景下表现突出的根本原因。
3.2 Continuous Batching 动态调度
传统批处理方式中,一个 batch 内的请求必须等最长的那个生成完,整个 batch 才一起释放,其他请求即使已经生成完也必须等待,GPU 空转比较严重。
vLLM 采用 Continuous Batching,调度器在每个迭代步都会检查所有序列状态,已经完成的请求立即退出,新到达的请求可以插入到当前 batch 中继续下次迭代。这样 GPU 始终在处理有效请求,吞吐自然大幅提升。
理解这个机制后,再看 vLLM 的--max-num-seqs参数就很容易理解了。它限制了引擎在单个迭代步中最多处理多少个序列,这个值决定了并发请求的上限。
3.3 关键运行参数与显存模型
vLLM 服务启动时有几个关键参数需要重点关注:
| 参数 | 作用 | 注意事项 |
|---|---|---|
--max-num-seqs | 最大并发序列数 | 太大容易 OOM,太小吞吐上不去 |
--max-model-len | 模型最大上下文长度 | 要小于模型本身支持长度 |
--gpu-memory-utilization | GPU 显存利用率上限 | 默认 0.9,可结合场景调低 |
--tensor-parallel-size | 张量并行卡数 | 多卡部署时使用 |
--dtype | 计算精度 | 可选 auto、half、bfloat16 等 |
参数之间相互影响。例如max-num-seqs增大,KV Cache 需求也增大,如果同时把max-model-len设置很大,显存可能瞬间不够。调优时建议先固定模型长度,再逐步增加max-num-seqs和并发压力,观察显存和延迟曲线。
4. 完整实战:本地部署一个 OpenAI 兼容的大模型服务
4.1 下载模型权重
这里以开源的中文对话模型为例,你可以使用 Hugging Face 上已有的模型权重。为了国内网络环境更稳定,也可以使用 ModelScope 下载。
示例中用 ModelScope 下载:
pip install modelscope modelscope download --model Qwen/Qwen2.5-7B-Instruct --local_dir ./models/Qwen2.5-7B-Instruct如果你使用的是其他模型,比如 Llama-3.1-8B-Instruct,只需要把模型路径替换成对应的 Hugging Face 或 ModelScope 地址。需要确保模型格式是 Hugging Face Transformers 兼容的 safetensors 格式。
4.2 使用 vLLM 启动服务
激活虚拟环境后,运行以下命令启动 OpenAI 兼容服务:
vllm serve ./models/Qwen2.5-7B-Instruct \ --host 0.0.0.0 \ --port 8000 \ --max-num-seqs 16 \ --max-model-len 8192 \ --gpu-memory-utilization 0.9参数说明:
--host 0.0.0.0允许外部机器访问服务。--port 8000指定监听端口。--max-num-seqs 16控制最大并发序列数为 16。--max-model-len 8192设定最大输入加输出的总 token 数。--gpu-memory-utilization 0.9表示最多使用 90% GPU 显存。
启动日志会显示模型路径、GPU 数量、使用算子等信息。看到Starting vLLM server和Uvicorn running on http://0.0.0.0:8000说明服务已经就绪。
4.3 用 Python SDK 调用服务
安装 OpenAI Python SDK:
pip install openai调用代码:
from openai import OpenAI client = OpenAI( base_url="http://localhost:8000/v1", api_key="EMPTY", ) response = client.chat.completions.create( model="./models/Qwen2.5-7B-Instruct", messages=[ {"role": "system", "content": "你是一个乐于助人的助手。"}, {"role": "user", "content": "用一句话介绍 vLLM 是什么。"} ], temperature=0.7, max_tokens=512, ) print(response.choices[0].message.content)注意model字段需要传服务启动时的模型路径名称,这个名称在服务日志里通常有提示。base_url一定要包含/v1后缀,否则 OpenAI SDK 拼接接口路径时会出现 404。
4.4 使用 curl 快速验证
如果不方便写 Python,可以直接用 curl 验证:
curl http://localhost:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "./models/Qwen2.5-7B-Instruct", "messages": [ {"role": "user", "content": "介绍一下 PagedAttention"} ], "max_tokens": 256 }'返回结果为 JSON 格式,choices[0].message.content字段就是模型输出内容。如果返回 404,检查model字段是否与服务端模型路径一致;如果返回 429,说明并发请求超过服务能力。
4.5 观察日志与资源占用
启动服务后,使用nvidia-smi观察 GPU 显存和利用率:
nvidia-smi正常状态下,显存占用应该接近gpu-memory-utilization设定的比例,GPU 利用率会随着请求并发数波动。如果长时间没有请求,利用率下降是正常现象,不必担心。
在压测时可以配合使用watch -n 1 nvidia-smi,实时观察显存是否接近上限,如果接近上限,需要降低max-num-seqs或减小max-model-len。
5. Docker 部署 vLLM 服务
5.1 为什么生产环境推荐 Docker
vLLM 依赖的 CUDA 版本、PyTorch 版本、Python 版本比较多,不同项目之间容易互相影响。Docker 可以把整个运行时环境打包成镜像,在开发、测试、生产环境保持一致,部署时只需要拉取镜像并设置环境变量和挂载目录即可。
尤其对于需要频繁发布新版本的团队,Docker 镜像支持版本标签,回滚和灰度都比较方便。官方也提供了预置的 OpenAI 兼容服务镜像。
5.2 拉取官方 Docker 镜像
vLLM 官方镜像名一般为vllm/vllm-openai,具体 tag 以官方文档为准。拉取方式:
docker pull vllm/vllm-openai:latest如果需要使用 NVIDIA GPU,还需要确保主机已经安装 NVIDIA Container Toolkit,并通过nvidia-ctk配置 Docker runtime。昇腾环境则需要关注是否提供对应的容器镜像和 runtime,具体以硬件厂商文档为准。
5.3 运行容器并挂载模型目录
使用下面的命令启动容器:
docker run --runtime nvidia --gpus all \ -v ~/models:/models \ -p 8000:8000 \ --ipc=host \ vllm/vllm-openai:latest \ --model /models/Qwen2.5-7B-Instruct \ --host 0.0.0.0 \ --port 8000 \ --max-num-seqs 16这里-v ~/models:/models把宿主机模型目录挂载到容器内,--ipc=host是为了避免共享内存不足的问题。--gpus all表示容器可以使用宿主机上所有 GPU。
启动成功后,在宿主机上执行前面第 4.4 节的 curl 命令,能正常返回就是部署成功。
6. vLLM 与 SGLang 等推理框架怎么选
6.1 SGLang 的核心设计
SGLang 是另一个受到广泛关注的大模型推理框架,它在前端提供了一套结构化生成语言,允许开发者通过简洁的语法描述生成过程,比如在多轮对话、并行调用、约束解码等场景下减少重复计算。后端也做了 RadixAttention 之类的 KV Cache 复用优化。
SGLang 在部分工作负载下吞吐表现不错,尤其是高度结构化的智能体任务和复杂 Prompt 场景,其缓存复用优势会比较明显。
6.2 从对比维度看差异
| 对比维度 | vLLM | SGLang |
|---|---|---|
| 生态成熟度 | 更高,社区文档多 | 相对年轻 |
| OpenAI 兼容接口 | 内置支持 | 也支持,但使用体验取决于版本 |
| 硬件平台支持 | NVIDIA 最成熟,其他平台逐步扩展 | 以 NVIDIA 为主 |
| 结构化生成 | 支持基础能力 | 前端语言更强 |
| 部署复杂程度 | 低,官方镜像完善 | 中等 |
| 模型支持范围 | 覆盖大部分主流模型 | 对常见模型支持较广 |
这个表格只是通用性对比,具体到某个模型或某个版本的算子优化,可能两个框架表现差异很大,选型时最好用真实业务数据做一轮基准测试。
6.3 选型建议
如果你需要一个稳定、文档丰富、社区活跃的框架,vLLM 是更稳妥的选择。如果项目中有大量结构化生成、多分支推理、复杂约束解码的场景,SGLang 值得重点评估。
另外要注意,大模型推理框架的更新节奏很快,两个框架的功能差距可能在一个季度内就发生变化。建议在 GitHub 上关注项目 Release Notes,核心依赖升级后再决定是否切换。
7. 常见问题与排查思路
7.1 昇腾 910B 服务器上无法通过 vLLM 启动 Embedding 向量和 Reranker 模型
昇腾 910B(包括 910B-A2 型号)上经常出现 vLLM 启动失败的反馈,尤其是 Embedding 向量模型和 Reranker 排序模型。这个问题的核心不是“vLLM 不能在昇腾上运行”,而是“当前使用的 vLLM 版本是否包含对应的昇腾后端支持”。
排查思路如下:
- 确认安装渠道。vLLM 默认 PyPI 包主要面向 NVIDIA CUDA 平台,昇腾上通常需要安装对应的社区适配版本或厂商提供的插件。安装前先确认 pip 包名和文档描述。
- 检查 CANN 版本和驱动。昇腾推理依赖 CANN 工具链,版本不匹配会导致算子编译或加载失败。需要对照适配文档检查 CANN、driver、固件版本。
- 确认模型类型支持。vLLM 对 Chat 类模型的支持最完善,Embedding 和 Reranker 模型在很多版本中支持不完整,启动报错不一定是环境问题,可能是模型类型尚未被前端解析器识别。
- 临时验证方法。先用官方明确支持的 Chat 模型启动一次,确认昇腾后端整体可用;再替换成 Embedding 模型,看具体报错是处于模型加载阶段还是算子执行阶段。
- 替代方案。如果昇腾环境始终无法通过 vLLM 启动向量模型,可以考虑使用昇腾生态内的其他推理工具链,或将向量模型单独部署在 CPU 环境,通过 API 网关分流。
7.2 显存不足与 OOM
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 启动即 OOM | gpu-memory-utilization设置过高 | 降低到 0.8 或 0.85 |
| 请求高峰时 OOM | max-num-seqs过大 | 逐步调低并发数 |
| 显存足够仍 OOM | max-model-len太长 | 按业务场景裁剪上下文长度 |
显存不足时不要马上加卡,先观察nvidia-smi的显存占用曲线,确认是模型权重占用多还是 KV Cache 占用多。模型权重占用多说明模型太大,需要量化或者多卡并行;KV Cache 占用多说明并发序列太多或上下文太长。
7.3 服务启动很慢或模型加载失败
服务启动慢通常是模型权重文件较大,从磁盘加载到显存需要时间。如果网络文件系统挂载模型目录,加载速度还会受网络带宽影响。建议把模型权重放到本地 SSD,或者增加进程内权重缓存。
模型加载失败时,优先检查 Hugging Face 模型目录是否完整,有没有缺少config.json、tokenizer.json、model.safetensors等关键文件。
7.4 请求超时与并发限制
客户端出现超时,可能不是服务端处理慢,而是服务端队列积压太多请求。vLLM 是异步引擎,请求进入队列后等待调度。
此时可以检查服务端日志中的排队耗时。如果排队耗时较长,适当增加max-num-seqs或增加服务实例数量;如果某个请求本身生成长度太长,也需要设置合理的max_tokens上限。
8. 最佳实践与工程建议
8.1 锁定模型与框架版本
生产环境不要随意升级 vLLM 版本。每次升级前,先在测试环境用相同的模型、相同的 Prompt 集合做回归验证,对比输出质量和吞吐指标。框架版本一旦确定,在镜像或 requirements 文件中固定版本号,避免latest标签带来的不确定性。
模型文件也建议固定版本。Hugging Face 模型经常有v1、v2等历史快照,部署脚本中应记录准确的模型 revision 或下载时间,防止磁盘上的模型文件被动静更新。
8.2 参数调优顺序
性能调优建议按照以下顺序进行:
- 确定业务允许的最大延迟。
- 根据延迟要求选择模型大小和量化方式。
- 设置合理的
max-model-len,不要超过实际业务场景的最大 token 数。 - 用压测工具逐步增大并发,观察延迟和吞吐。
- 在保证延迟达标的前提下增大
max-num-seqs,直到吞吐不再明显提升。 - 调整批处理相关参数,此时再考虑是否升级到多卡并行。
不要一开始就追求最大吞吐,延迟过高会直接影响在线业务体验。
8.3 服务稳定性与观测
vLLM 服务需要监控的指标包括:请求成功率、平均首 token 延迟、平均生成延迟、排队长度、GPU 显存使用率、GPU 利用率。生产环境可以接入 Prometheus,vLLM 导出指标后配置告警规则。
建议至少配置以下告警:
- GPU 显存使用率持续超过 95%。
- 请求成功率低于 99%。
- 排队长度超过阈值且持续上涨。
- GPU 利用率长期低于 20% 但请求延迟仍高,说明调度或 I/O 存在瓶颈。
8.4 安全与权限
vLLM 服务默认没有鉴权机制,直接暴露到公网存在被恶意刷接口的风险。生产环境必须在前面加一层 API 网关或认证服务,为每个调用方分配独立 API Key,并配置 IP 白名单和 QPS 限制。
模型本身也有内容安全风险,建议在服务链路中增加输入输出审核,防止恶意 Prompt 注入。涉及内部数据的场景,还要关注模型是否泄露训练数据中的敏感信息。
对于昇腾等国产加速卡环境,建议在单独的测试环境验证好权限和资源隔离后再上生产,不要直接在多人共享的服务器上随意安装系统级依赖。
9. 总结与学习路线
9.1 本文掌握的关键点
通过这篇文章,你应该了解 vLLM 的核心优势来自 PagedAttention 和 Continuous Batching,而不是简单的工程包装;能够独立完成 vLLM 的 pip 安装、Docker 部署和 OpenAI 兼容服务的调用;也知道了max-num-seqs、max-model-len、gpu-memory-utilization这几个参数如何影响显存和吞吐。
对于昇腾 910B 上无法启动 Embedding 和 Reranker 模型的问题,要注意区分平台适配和模型类型支持两个维度,先确认安装来源,再检查模型类型,最后再考虑替代方案。
9.2 下一步可以继续学习什么
如果你对部署层已经比较熟悉,下一步可以关注 vLLM 的源码实现,尤其是调度器模块的代码,理解一个 token 从请求进入到最终生成的完整生命周期。这比背参数更有价值。
如果业务需要多卡推理,可以继续学习张量并行、流水线并行在不同模型大小下的选择逻辑。量化方向也可以关注 AWQ、GPTQ 在 vLLM 中的实际效果,很多生产场景靠量化省下大量显存。
9.3 实际项目中最需要关注的风险
我在部署实践中感受最深的一点是:不要被吞吐指标迷惑。很多框架的基准测试都是在理想化脚本下跑出来的,真实业务里 Prompt 长度、生成长度、并发模型都有较大波动。部署前期就要设计好监控和压测流程,把参数调优建立在自己的业务数据上,而不是照搬别人的配置。
把上面这些实践放进你的部署方案里,应该能少踩不少坑。vLLM 生态还在快速演进,保持对官方 Release Notes 和团队动态的关注,是长期维护一个推理平台的基本功。