一、环境信息(本机实测)
| 项目 | 值 |
|---|---|
| 操作系统 | Ubuntu 22.04.5 LTS |
| GPU | NVIDIA Tesla V100-SXM2-16GB |
| 驱动版本 | 570.195.03 |
| CUDA | 12.4 (nvcc V12.4.131) |
| PyTorch | 2.4.0+cu118 |
| vLLM | dev (claude build) |
| Python | 3.10.12 |
| pip 镜像 | https://mirrors.aliyun.com/pypi/simple/ |
| 模型 | Qwen/Qwen2.5-1.5B-Instruct (2.9 GB) |
| 内存 | 30 GB |
本教程所有命令都是在 root 用户下执行。如果使用普通用户,部分命令前需要加 sudo。
二、CUDA & 驱动配置
2.1 检查当前驱动和 CUDA
# 查看 GPU 信息和驱动版本
nvidia-smi# 查看 CUDA 编译器版本
nvcc --version# 或查看 CUDA 版本文件
cat /usr/local/cuda/version.txt 2>/dev/null
2.2 安装 NVIDIA 驱动(如果没有)
# 查看推荐驱动版本
ubuntu-drivers devices# 自动安装推荐驱动
apt install -y nvidia-driver-570# 重启后验证
nvidia-smi
2.3 安装 CUDA(如果没有)
# 从 NVIDIA 官网下载(选对版本)
wget https://developer.download.nvidia.com/compute/cuda/12.4.0/local_installers/cuda_12.4.0_550.54.14_linux.run
sh cuda_12.4.0_550.54.14_linux.run# 添加环境变量(写入 ~/.bashrc)
export PATH=/usr/local/cuda/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH
重要提示:PyTorch 的 CUDA 版本可以低于系统 CUDA 版本(向后兼容)。 例如系统装 CUDA 12.4,PyTorch 可以用 cu118(兼容 CUDA 11.8+)。 不要盲目追新,以 PyTorch 官方的兼容列表为准。
三、PyTorch 安装
3.1 配置 pip 镜像(国内服务器必做,否则慢到崩溃)
# 阿里云源(推荐,实测稳定)
pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/# 也可用其他源
# https://pypi.tuna.tsinghua.edu.cn/simple (清华)
# https://mirrors.ustc.edu.cn/pypi/simple/ (中科大)
3.2 安装 PyTorch
去 PyTorch 历史版本 找到匹配 CUDA 的版本。
V100(计算能力 7.0)不支持 cu124,推荐 cu118:
# CUDA 11.8 + PyTorch 2.4.0(阿里云镜像)
pip install torch==2.4.0 torchvision==0.19.0 torchaudio==2.4.0 \--index-url https://download.pytorch.org/whl/cu118# 验证
python3 -c "import torch; print(f'PyTorch {torch.__version__}, CUDA: {torch.cuda.is_available()}')"
# 输出: PyTorch 2.4.0+cu118, CUDA: True
四、vLLM 安装与配置
4.1 pip 安装 vLLM
# 直接安装(会自动装配套的 PyTorch,但国内建议先装好 PyTorch)
pip install vllm# 如果网不好,从阿里云源安装
pip install vllm -i https://mirrors.aliyun.com/pypi/simple/
4.2 验证安装
python3 -c "import vllm; print(f'vLLM {vllm.__version__}')"# 查看所有支持的参数
vllm serve --help
已知问题 - pyairports 假包:
阿里云 PyPI 上的 pyairports 0.0.1 是 sample 空包,不能 import。
vLLM 依赖 outlines,outlines 依赖 pyairports。
解决方法:修改 outlines 源码,把报错的那一行注释掉:
阿里云 PyPI 上的 pyairports 0.0.1 是 sample 空包,不能 import。
vLLM 依赖 outlines,outlines 依赖 pyairports。
解决方法:修改 outlines 源码,把报错的那一行注释掉:
# 编辑 /usr/local/lib/python3.10/dist-packages/outlines/types/airports.py
# 将第4行:
# from pyairports.airports import AIRPORT_LIST
# 改为:
# AIRPORT_LIST = []
或者直接从 PyPI 官方源安装正确的版本:
pip install pyairports --index-url https://pypi.org/simple/
五、模型下载与加载
5.1 从 HuggingFace 下载模型
# 方法1:用 huggingface-cli(推荐,支持断点续传)
pip install huggingface-hub
huggingface-cli download Qwen/Qwen2.5-1.5B-Instruct \--local-dir /root/models/Qwen/Qwen2.5-1.5B-Instruct# 方法2:用镜像站加速(国内必用)
export HF_ENDPOINT=https://hf-mirror.com
huggingface-cli download Qwen/Qwen2.5-1.5B-Instruct \--local-dir /root/models/Qwen/Qwen2.5-1.5B-Instruct# 方法3:用 Python 代码下载
python3 -c "
from huggingface_hub import snapshot_download
snapshot_download('Qwen/Qwen2.5-1.5B-Instruct',local_dir='/root/models/Qwen/Qwen2.5-1.5B-Instruct')
"
5.2 模型文件结构
/root/models/Qwen/Qwen2.5-1.5B-Instruct/
├── config.json # 模型配置
├── model.safetensors # 权重文件(2.9 GB)
├── tokenizer.json # Tokenizer
├── tokenizer_config.json
├── vocab.json
├── merges.txt
└── generation_config.json
建议:模型文件放在
HF 缓存默认在
/root/models/ 下统一管理,方便 vLLM 用绝对路径加载。HF 缓存默认在
~/.cache/huggingface/hub/,但 vLLM 直接传路径更方便。六、启动推理服务
6.1 基本启动命令
vllm serve /root/models/Qwen/Qwen2.5-1.5B-Instruct \--host 0.0.0.0 --port 8000 --max-model-len 4096 \--dtype float16 --trust-remote-code --enforce-eager
参数说明:
| 参数 | 说明 |
|---|---|
--host 0.0.0.0 |
允许外部访问(不设则只能本机访问) |
--port 8000 |
服务端口 |
--max-model-len 4096 |
最大上下文长度(越长越耗显存) |
--dtype float16 |
半精度推理,省显存(V100 原生支持) |
--trust-remote-code |
允许加载自定义模型代码 |
--enforce-eager |
跳过 CUDA Graphs 捕获,加快启动(V100 上推荐) |
--gpu-memory-utilization 0.9 |
GPU 显存利用率(默认 0.9) |
--max-num-seqs 256 |
最大并发请求数 |
6.2 后台运行(推荐)
nohup vllm serve /root/models/Qwen/Qwen2.5-1.5B-Instruct \--host 0.0.0.0 --port 8000 --max-model-len 4096 \--dtype float16 --trust-remote-code --enforce-eager \> /tmp/vllm.log 2>&1 &
6.3 查看服务和日志
# 查看进程
ps aux | grep vllm | grep -v grep# 查看日志(实时)
tail -f /tmp/vllm.log# 查看端口
ss -tlnp | grep 8000# 停止服务
kill $(ps aux | grep 'vllm serve' | grep -v grep | awk '{print $2}')# 强制停止(杀子进程)
fuser -k 8000/tcp
pkill -9 -f "vllm"
6.4 启动成功的标志
日志最后几行应该看到:
INFO: Started server process [pid]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on socket ('0.0.0.0', 8000) (Press CTRL+C to quit)
七、外部测试模型
服务启动后,用 curl 直接测试(可以在本机或另一台机器上执行):
7.1 健康检查
curl http://8.159.159.103:8000/health# 返回 200 OK 即正常
# 如返回空,检查日志是否有错误
7.2 聊天测试(一条命令)
curl -s http://8.159.159.103:8000/v1/chat/completions \-H "Content-Type: application/json" \-d '{"model": "/root/models/Qwen/Qwen2.5-1.5B-Instruct","messages": [{"role": "user", "content": "你好,你是谁?"}],"max_tokens": 100,"temperature": 0.7}' | python3 -m json.tool
7.3 查看可用模型列表
curl -s http://8.159.159.103:8000/v1/models | python3 -m json.tool
7.4 Completion 测试(非聊天模式)
curl -s http://8.159.159.103:8000/v1/completions \-H "Content-Type: application/json" \-d '{"model": "/root/models/Qwen/Qwen2.5-1.5B-Instruct","prompt": "人工智能的未来是","max_tokens": 50}' | python3 -m json.tool
7.5 性能压测
# 简单计时
time curl -s http://8.159.159.103:8000/v1/chat/completions \-H "Content-Type: application/json" \-d '{"model": "/root/models/Qwen/Qwen2.5-1.5B-Instruct","messages": [{"role":"user","content":"写一首五言绝句"}],"max_tokens": 200}' &>/dev/null
八、外部调用模型(API 方式)
vLLM 提供兼容 OpenAI API 格式的接口,可以直接用 OpenAI 的客户端库调用:
8.1 Python 调用(推荐)
pip install openai
from openai import OpenAIclient = OpenAI(base_url="http://8.159.159.103:8000/v1",api_key="not-needed" # vLLM 默认不校验 API Key
)# 聊天补全
response = client.chat.completions.create(model="/root/models/Qwen/Qwen2.5-1.5B-Instruct",messages=[{"role": "system", "content": "你是一个有用的助手。"},{"role": "user", "content": "用 Python 写一个冒泡排序"}],max_tokens=500,temperature=0.7
)print(response.choices[0].message.content)# 查看用量
print(f"输入 tokens: {response.usage.prompt_tokens}")
print(f"输出 tokens: {response.usage.completion_tokens}")
8.2 流式输出(SSE)
from openai import OpenAIclient = OpenAI(base_url="http://8.159.159.103:8000/v1",api_key="not-needed"
)stream = client.chat.completions.create(model="/root/models/Qwen/Qwen2.5-1.5B-Instruct",messages=[{"role": "user", "content": "讲个笑话"}],max_tokens=200,stream=True
)for chunk in stream:if chunk.choices[0].delta.content is not None:print(chunk.choices[0].delta.content, end="", flush=True)
print()
8.3 cURL 调用(任何语言通用)
curl -s http://8.159.159.103:8000/v1/chat/completions \-H "Content-Type: application/json" \-d '{"model": "/root/models/Qwen/Qwen2.5-1.5B-Instruct","messages": [{"role": "system", "content": "你是有用的助手"},{"role": "user", "content": "1+1等于几?"}],"max_tokens": 100,"temperature": 0.7,"stream": false}'
8.4 JavaScript / Node.js 调用
import OpenAI from 'openai';const client = new OpenAI({baseURL: 'http://8.159.159.103:8000/v1',apiKey: 'not-needed',
});const response = await client.chat.completions.create({model: '/root/models/Qwen/Qwen2.5-1.5B-Instruct',messages: [{ role: 'user', content: '你好' }],max_tokens: 100,
});console.log(response.choices[0].message.content);
8.5 安全设置(如需 API Key 校验)
vllm serve /root/models/Qwen/Qwen2.5-1.5B-Instruct \--host 0.0.0.0 --port 8000 \--api-key "your-secret-key-here" \...其他参数
客户端使用时加上 api_key="your-secret-key-here"。
安全提醒:如果服务绑定 0.0.0.0 且开放公网,建议:
1. 设置防火墙只允许特定 IP 访问(如使用 Nginx 反向代理)
2. 或设置 --api-key 参数
3. 或只监听内网 IP:--host 192.168.x.x
4. 不要在公网暴露不带认证的 LLM 服务!
1. 设置防火墙只允许特定 IP 访问(如使用 Nginx 反向代理)
2. 或设置 --api-key 参数
3. 或只监听内网 IP:--host 192.168.x.x
4. 不要在公网暴露不带认证的 LLM 服务!
九、常见问题
Q1: CUDA out of memory
错误:
torch.OutOfMemoryError: CUDA out of memory原因:显存不足。V100 16GB 跑 1.5B 模型没问题,但之前的进程没释放显存。
解决:
- 先杀掉所有残留进程:
pkill -9 -f "vllm" && sleep 2 - 用
nvidia-smi确认显存已释放 - 减小显存占用参数:
--gpu-memory-utilization 0.7、--max-model-len 2048 - 打开
--enforce-eager跳过 CUDA Graphs 的额外显存开销 - 实在不够可以换更小的模型,如 Qwen2.5-0.5B
Q2: Address already in use(端口被占用)
错误:
OSError: [Errno 98] Address already in use原因:上一个 vLLM 进程没完全退出,或 engine 子进程残留。
解决:
# 方法1:杀掉占用端口的进程
fuser -k 8000/tcp# 方法2:杀掉所有 vLLM 相关进程(包括子进程)
pkill -9 -f "vllm"# 方法3:检查还有什么占着端口
ss -tlnp | grep 8000# 确认释放后再启动
sleep 2 && vllm serve ...
Q3: Engine process failed to start
错误:
RuntimeError: Engine process failed to start原因:引擎子进程启动时崩溃了,但主进程没捕获到详细错误。
解决:
- 先检查显存是否足够(
nvidia-smi)——OOM 是最常见原因 - 查看完整日志:
tail -50 /tmp/vllm.log - 直接跑 engine 测试:
python3 -c "from vllm.engine.multiprocessing.engine import MQLLMEngine"
Q4: 启动时联网下载模型,但网络不通
错误:
Network is unreachable 或连接 huggingface.co 超时原因:国内服务器访问 HuggingFace 被墙或 DNS 污染。
解决:
# 方案1:改用镜像站
export HF_ENDPOINT=https://hf-mirror.com# 方案2:先手动下载,再用本地路径加载
vllm serve /root/models/Qwen/Qwen2.5-1.5B-Instruct ...# 方案3:用 huggingface-cli 配合镜像站下载
pip install huggingface-hub
HF_ENDPOINT=https://hf-mirror.com huggingface-cli download Qwen/Qwen2.5-1.5B-Instruct
Q5: Internal Server Error (500) 关于 pyairports
错误:
ModuleNotFoundError: No module named 'pyairports'如本文 4.2 节所述,这是阿里云 PyPI 上 pyairports 包为空的问题。
解决:
# 方案1:从官方 PyPI 安装(最快)
pip install pyairports --index-url https://pypi.org/simple/# 方案2:修改 outlines 源码绕过
sed -i "s/from pyairports.airports import AIRPORT_LIST/# fixed\nAIRPORT_LIST = []/" \/usr/local/lib/python3.10/dist-packages/outlines/types/airports.py# 方案3:重启服务(让子进程继承修复)
pkill -9 -f "vllm"
# 重启...
Q6: V100 不支持 FlashAttention
日志:
Cannot use FlashAttention-2 backend for Volta and Turing GPUs. Using XFormers backend.这是正常现象。V100(Volta 架构)不支持 FlashAttention-2,vLLM 会自动切换到 XFormers 后端,不影响功能,只是推理速度比 Ampere 架构稍慢。
Q7: 如何选择模型大小
| GPU 显存 | 推荐最大模型 | 说明 |
|---|---|---|
| 8 GB | 0.5B ~ 1B | 如 Qwen2.5-0.5B |
| 16 GB(V100) | 1.5B ~ 7B | 7B 需 --dtype float16,可加 --enforce-eager |
| 24 GB | 7B ~ 13B | 可上 Qwen2.5-7B |
| 40 GB+(A100) | 13B ~ 70B | 70B 需要多卡或量化 |
Q8: 服务日志太多怎么办
# 启动时加 --disable-log-requests 关闭请求日志
vllm serve ... --disable-log-requests# 只输出错误信息
grep -E "ERROR|Error|Traceback" /tmp/vllm.log
Q9: 监控 GPU 状态
# 实时监控(每秒刷新)
watch -n 1 nvidia-smi# 只查看显存使用
nvidia-smi --query-gpu=memory.used,memory.free --format=csv# 查看进程占用
nvidia-smi pmon -c 1
Q10: 如何开机自启
# 写入 /etc/rc.local 或 systemd service
# 简单方式:在 /root/start_vllm.sh 写入:
cat > /root/start_vllm.sh << 'SCRIPT'
#!/bin/bash
nohup vllm serve /root/models/Qwen/Qwen2.5-1.5B-Instruct \--host 0.0.0.0 --port 8000 --max-model-len 4096 \--dtype float16 --trust-remote-code --enforce-eager \> /tmp/vllm.log 2>&1 &
SCRIPT
chmod +x /root/start_vllm.sh
# 加到 crontab:
# @reboot /root/start_vllm.sh