如果说 Ollama + Open WebUI 解决的是“先把体验跑起来”,那 vLLM 更像是在回答另一个问题:
当体验已经有了之后,怎么把模型服务做得更像一个正式的推理接口?
这也是为什么很多团队在跑通第一套 AI 体验环境后,下一步都会很自然地进入 vLLM。
原因并不复杂:
- 它更偏正式推理服务
- 更强调吞吐和显存利用率
- 天然更适合做 API 服务
- 对接现有应用时,OpenAI 兼容接口非常有用
换句话说,Ollama 更适合快速体验,vLLM 更适合往“服务化”方向走。
但在真正开始部署 vLLM 时,很多人又会遇到新的选择题:
- 应该先本地装,还是直接上 Docker
- 是用
vllm serve,还是用 Python 模块方式启动 - 服务启动之后,到底怎么验证它是不是一个真的可用 API
这篇文章就是为了解决这些问题。
我会把 vLLM 的第一阶段实践拆成两条并行路径:
- 本地部署:更适合理解链路和调试问题
- Docker 部署:更适合固化环境和快速复现
最后再把两条路径统一收口到同一件事上:
用 OpenAI 兼容接口验证,确认你的 vLLM 服务不是“进程在跑”,而是真的可以被应用调用。
这一篇仍然保持可实操写法:
- 先讲为什么值得做
- 再给命令
- 关键地方补预期输出
- 说明每一步什么样才算成功
文中的模型路径、镜像版本、CUDA 版本和端口都基于课程环境整理,与你的实际环境不同是正常现象。
重点是部署逻辑和验证思路。
摘要
如果你只想先看结论,可以先记住三点:
vLLM更适合作为正式推理服务入口,而不是单纯体验工具- 本地部署适合理解依赖链路,Docker 部署适合快速固化环境
- 不管用哪条路径,最后都应该用
curl访问/v1/models、/v1/chat/completions或/v1/completions做接口验证
这一篇最关键的验收点有三个:
vllm --version正常输出版本号- 服务启动后,
http://localhost:8000/v1/models能返回模型列表 curl请求推理接口时,能拿到结构化 JSON 响应
系列导航
这是“大模型私有化部署实践”系列的第六篇。当前系列顺序如下:
- 本地、Docker、K8S:大模型私有化部署路线怎么选
- 大模型推理环境准备实战:GPU、驱动、CUDA、容器运行时
- 基于 Ubuntu 24.04 搭建 AI 推理用原生 K8S 集群
- 为 K8S 补齐入口与存储:MetalLB、Gateway API、NFS 动态供给
- 用 Ollama + Open WebUI 快速搭建本地 AI 体验环境
- vLLM 私有化部署实战:本地部署、Docker 部署、接口验证
- vLLM 上 K8S:服务部署、对外暴露、监控与验证
- SGLang 私有化部署实战:本地部署、Docker 部署、能力体验
- SGLang 上 K8S:接入 Open WebUI、服务发布与 GPU 运维
- vLLM 和 SGLang 到底怎么选
如果说上一篇解决的是“先做一条可交互体验链路”,这一篇解决的就是:
如何从体验环境走向正式推理服务,把模型暴露成一个更标准、更适合应用对接的 API。
1. 为什么从 Ollama 走到 vLLM 是一条很自然的路径
很多团队第一次接触私有化部署时,都会先用 Ollama 快速把东西跑起来。
这是合理的,因为它上手快、闭环短、容易看到结果。
但当你开始考虑下面这些需求时,vLLM 的优势就会越来越明显:
- 希望模型服务更像标准 API
- 希望更关注吞吐和显存效率
- 希望后续能平滑进入 K8S 服务化
- 希望用 OpenAI 风格接口对接现有应用
从这个角度看,vLLM 更像是从“体验阶段”走向“推理服务阶段”的第一块踏板。
1.1 vLLM 更适合什么场景
简单说,vLLM 更适合下面这些方向:
- 单机 GPU 上提供正式推理接口
- 内网共享一个稳定的模型 API
- 对接已有应用、脚本或 SDK
- 为后续 K8S 服务化做准备
1.2 这篇为什么同时讲本地和 Docker 两条路径
因为它们解决的问题不一样:
- 本地部署更适合理解 vLLM 和 PyTorch、CUDA 的关系
- Docker 部署更适合快速复现和减少宿主机污染
很多人一开始会把这两条路径理解成二选一。
其实更实用的理解是:
本地路径帮助你看清楚问题,Docker 路径帮助你把问题收敛起来。
2. 部署前先确认一件事:第 2 篇的环境链路已经打通
虽然这一篇不再展开讲 GPU、驱动、CUDA 和容器运行时的底层准备,但在真正装 vLLM 前,最好先确认这些基础动作已经通过:
nvidia-smi
nvcc --version
python -c "import torch; print(torch.cuda.is_available()); print(torch.cuda.device_count())"
至少应该能看到:
True
1
如果这一步都还没通过,建议先回看第 2 篇,而不是继续往上装 vLLM。
3. 本地部署路径:最适合吃透运行链路
本地部署的目标,不是追求“最省心”,而是追求“最容易看清问题在哪一层”。
它特别适合这几类情况:
- 你第一次接触 vLLM
- 你想确认某个模型能不能在当前机器上跑起来
- 你想搞清楚 vLLM、PyTorch、CUDA 的关系
3.1 准备 Miniconda 和独立 Python 环境
如果你的机器上还没有合适的 Python 隔离环境,建议先准备 Miniconda。
mkdir -p ~/miniconda3
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda3/Miniconda3-latest-Linux-x86_64.sh
bash ~/miniconda3/Miniconda3-latest-Linux-x86_64.sh -b -u -p ~/miniconda3
~/miniconda3/bin/conda init bash
source ~/.bashrc
课程里的典型安装输出会出现:
PREFIX=/root/miniconda3
Unpacking bootstrapper...
Installing base environment...
installation finished.
然后创建 vLLM 专用环境:
conda create --name vllm python=3.10 -y
conda activate vllm
python --version
预期输出类似:
Python 3.10.x
如果你已经有稳定的 Python 3.10 环境,这一步也可以跳过,但独立环境依然更推荐。
3.2 安装 PyTorch 和 vLLM
在课程环境里,使用的是和 CUDA 对应的 PyTorch wheel,再安装 vLLM。
例如:
wget https://download.pytorch.org/whl/cu124/torch-2.6.0%2Bcu124-cp310-cp310-linux_x86_64.whl
pip install torch-2.6.0+cu124-cp310-cp310-linux_x86_64.whl
pip install vllm
vllm --version
预期输出类似:
0.13.0
如果这里 vllm --version 都过不了,就先不要继续启动服务。
优先检查:
- 当前虚拟环境是不是你刚创建的那个
pip install是否装到了错误的 Python 环境- PyTorch wheel 和 CUDA 版本是否兼容
3.3 准备模型目录
本地部署时,你需要一个明确的模型目录。
课程里使用的是类似:
/data/ModelScope/Deepseek-Qwen
你可以先检查目录是否真的存在:
ls /data/ModelScope
ls /data/ModelScope/Deepseek-Qwen
这里最重要的不是目录名长什么样,而是:
- 路径真实存在
- 当前用户有权限访问
- 模型权重已经完整准备好
3.4 用 vllm serve 启动服务
最直接的方式,就是用 vllm serve:
vllm serve /data/ModelScope/Deepseek-Qwen \
--host 0.0.0.0 \
--port 8000 \
--served-model-name deepseek \
--max-model-len 8192 \
--dtype auto \
--gpu-memory-utilization 0.8
这里几个最关键的参数分别是:
--host 0.0.0.0:允许外部访问--port 8000:服务监听端口--served-model-name deepseek:接口调用时要写的模型名--max-model-len 8192:模型最大上下文长度--gpu-memory-utilization 0.8:显存占用比例控制
正常启动时,日志里通常会持续打印模型加载信息。
如果服务已经稳定起来,终端不会立刻退出,而是持续驻留。
3.5 也可以用 Python 模块方式启动
课程里还给了另一种写法:
python -m vllm.entrypoints.openai.api_server \
--model /data/ModelScope/Deepseek-Qwen \
--host 0.0.0.0 \
--port 8000 \
--served-model-name deepseek
这两种方式本质目标一致,都是起 OpenAI 兼容 API 服务。
如果你只是为了快速跑通,优先用 vllm serve 就够了。
3.6 用 systemd 把本地服务托管起来
如果你不想每次手动在终端前台启动,也可以做一个简单的 systemd 托管:
[Unit]
Description=vLLM API Server
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/data
ExecStart=/root/miniconda3/envs/vllm/bin/vllm serve /data/ModelScope/Deepseek-Qwen \
--host 0.0.0.0 \
--port 8000 \
--served-model-name deepseek \
--max-model-len 8192 \
--dtype auto \
--gpu-memory-utilization 0.8
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
保存为 /etc/systemd/system/vllm.service 后执行:
systemctl daemon-reload
systemctl enable vllm
systemctl start vllm
systemctl status vllm --no-pager
如果运行正常,状态里至少应该看到:
Active: active (running)
4. 先别急着接应用,先做本地 API 验证
不管你是前台启动还是 systemd 托管,真正重要的都不是“进程在不在”,而是“接口能不能用”。
4.1 先看模型列表接口
先用最基础的接口确认服务起来了:
curl http://localhost:8000/v1/models
如果服务正常,返回通常类似:
{
"object": "list",
"data": [
{
"id": "deepseek",
"object": "model",
"owned_by": "vllm"
}
]
}
只要这里拿不到结果,就先不要继续调用 /v1/chat/completions。
4.2 用 completions 接口做一次最小验证
课程里给的是这样的测试方式:
curl http://localhost:8000/v1/completions \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek",
"prompt": "地球为什么是圆的?",
"max_tokens": 100
}'
如果正常,返回会是结构化 JSON,类似:
{
"id": "cmpl-xxxx",
"object": "text_completion",
"model": "deepseek",
"choices": [
{
"index": 0,
"text": "地球之所以近似球形,主要是因为引力会把物质尽量拉向中心..."
}
]
}
4.3 如果你更习惯聊天接口,也可以直接测 /v1/chat/completions
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek",
"messages": [
{"role": "user", "content": "请用一句话介绍 vLLM 是什么"}
],
"max_tokens": 128
}'
只要你能拿到结构化回复,说明这条本地服务链路已经基本成立。
5. Docker 部署路径:更适合快速固化和复现环境
当你已经理解了本地路径之后,Docker 通常会成为更实用的一条路。
它最大的价值不是“更高级”,而是“环境更容易固定下来”。
特别适合这些场景:
- 单机 GPU 服务器长期提供推理接口
- 团队希望统一部署方式
- 不想把大量 Python 依赖直接堆在宿主机上
5.1 先确认 Docker 和 GPU 运行时已经打通
按照第 2 篇的逻辑,在真正跑 vLLM 镜像前,先确认 Docker 和 NVIDIA Container Toolkit 已经通了:
docker run --rm --gpus all nvidia/cuda:12.4.0-base-ubuntu22.04 nvidia-smi
如果这里都还不通,就不要继续拉 vLLM 镜像。
5.2 安装或检查 Docker
课程里使用的是二进制方式安装 Docker,也可以用你自己的标准安装方式。
关键不是安装路径,而是最后能正常工作:
systemctl enable --now docker
docker version
docker info | grep -A5 Runtimes
如果 NVIDIA 运行时配置好了,docker info 里通常会出现类似:
Runtimes: io.containerd.runc.v2 nvidia runc
Default Runtime: runc
5.3 安装并配置 NVIDIA Container Toolkit
如果你前面还没做过,这一步是 Docker 路线的关键:
sudo apt update
sudo apt install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
cat /etc/docker/daemon.json
课程里的典型输出会出现:
INFO[0000] Config file does not exist; using empty config
INFO[0000] Wrote updated config to /etc/docker/daemon.json
INFO[0000] It is recommended that docker daemon be restarted.
而 /etc/docker/daemon.json 里通常会包含类似内容:
{
"runtimes": {
"nvidia": {
"args": [],
"path": "nvidia-container-runtime"
}
}
}
6. 用 Docker 启动 vLLM
课程里使用的是 vllm/vllm-openai:latest 镜像。
这类镜像的优点是非常直接:启动后就是 OpenAI 兼容 API 服务。
6.1 先准备模型挂载目录
假设宿主机模型目录是:
/data/ModelScope
先确认目录存在:
ls /data/ModelScope
6.2 启动容器
如果镜像是本地包,也可以先加载:
docker load -i vllm-openai.tar
然后启动服务:
docker run -d \
--name vllm-server \
--gpus all \
--shm-size=1g \
-p 8000:8000 \
-v /data/ModelScope:/models \
vllm/vllm-openai:latest \
--model /models/Deepseek-Qwen \
--served-model-name deepseek \
--max-model-len 8192 \
--dtype auto
这里最关键的参数有:
--gpus all:把宿主机 GPU 给容器--shm-size=1g:给共享内存更大的空间-p 8000:8000:把容器内 API 暴露到宿主机-v /data/ModelScope:/models:让容器能访问宿主机模型目录--model /models/Deepseek-Qwen:指定容器内模型路径
6.3 查看容器运行状态
docker ps
docker logs -f vllm-server
docker ps 正常情况下至少能看到:
CONTAINER ID IMAGE COMMAND STATUS PORTS
xxxxxxxxxxxx vllm/vllm-openai:latest "python3 -m vllm...." Up 20 seconds 0.0.0.0:8000->8000/tcp
只要容器启动后马上退出,就优先看日志,不要先猜模型或框架有问题。
7. 用接口验证 Docker 版 vLLM
本地版和 Docker 版在验证方法上,其实应该保持一致。
无论底层怎么部署,最后都应该回到“API 到底能不能用”。
7.1 先看 /v1/models
curl http://localhost:8000/v1/models
如果正常,返回类似:
{
"object": "list",
"data": [
{
"id": "deepseek",
"object": "model",
"owned_by": "vllm"
}
]
}
7.2 再测 /v1/chat/completions
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek",
"messages": [
{"role": "user", "content": "请解释一下为什么地球近似球形"}
],
"max_tokens": 128
}'
7.3 如果镜像配置了 API Key
有些部署方式会带上 --api-key 参数。
如果你启动容器时配置了 API Key,请记得调用时也带上:
curl http://localhost:8000/v1/models \
-H "Authorization: Bearer your-api-key"
8. 本地部署和 Docker 部署,到底该先用哪个
这其实是很多团队最关心的现实问题。
我的建议是:
- 第一次理解 vLLM:优先本地部署
- 第一次给别人复现:优先 Docker 部署
- 计划长期提供服务:Docker 往往更稳
8.1 本地部署更适合什么
本地部署更适合:
- 学习链路
- 排查环境问题
- 理解 PyTorch、CUDA、vLLM 的关系
8.2 Docker 部署更适合什么
Docker 部署更适合:
- 固化环境
- 快速迁移
- 做统一的服务交付方式
如果用一句话概括:
本地部署帮你把问题看清楚,Docker 部署帮你把问题收敛起来。
9. 最常见的几类问题,基本都卡在这几个地方
到了 vLLM 这一步,最常见的问题通常不再是“命令不会写”,而是下面这些。
9.1 服务进程在,但模型接口没起来
典型表现:
- 进程在跑
- 但
curl http://localhost:8000/v1/models没返回
这通常说明模型还没加载完成,或者服务其实卡在启动阶段。
优先看前台日志或 docker logs。
9.2 本地环境能装,接口一调用就报错
典型表现:
vllm --version正常- 但服务启动报 CUDA 或模型相关错误
这类问题往往还是回到:
- PyTorch / CUDA 兼容性
- 模型路径
- 显存是否够用
9.3 Docker 容器能起,但容器里没 GPU
典型表现:
docker ps有容器- 但推理速度异常慢或日志提示 GPU 不可用
这时要先回头检查:
--gpus all有没有加- NVIDIA Container Toolkit 是否配置好了
docker run --rm --gpus all nvidia/cuda ... nvidia-smi是否正常
9.4 模型名和接口调用里的 model 对不上
这类问题也非常常见。
例如你启动时用了:
--served-model-name deepseek
那调用接口时就要写:
"model": "deepseek"
而不是模型目录名,更不是随便起一个别名。
10. 结语:vLLM 是从体验环境走向正式推理服务的第一步
跑完这一篇之后,你会明显感觉到一件事:
和 Ollama 相比,vLLM 已经更像一个“面向应用的推理服务”了。
它的重点不再只是“我能不能跟模型聊起来”,而是:
- 这个服务能不能稳定暴露成 API
- 其他应用能不能按标准方式调用它
- 后面能不能平滑放进容器或集群里
这也是为什么它非常适合作为系列里的下一步。
从系列节奏上看,这一篇解决的是:
- 单机层面把正式推理服务跑通
- 把本地和 Docker 两条路径吃透
- 用 OpenAI 兼容接口把服务验证清楚
而再往下一步,问题就不再是“单机怎么跑”,而是“这套服务怎么放进 K8S,变成团队共享的正式能力”。
下一篇文章,我们就继续沿着这条线往前走:
把 vLLM 放进 K8S,接上 PVC、Service、Gateway 和监控链路,真正把它做成一个可对外使用的集群推理服务。
评论区