4. vLLM单机部署:从源码到API服务
好,咱们进入实战环节。这一章我带你走一遍vLLM单机部署的完整流程——从安装、下载模型,到启动一个兼容OpenAI的API服务,最后用客户端调一下试试。整个过程我踩过不少坑,这次一并告诉你。
核心流程一览:源码安装 vs pip安装 → 模型下载与加载 → 启动API服务 → 客户端调用测试
4.1 安装方式:pip还是源码?
我个人习惯先用pip装,快速验证环境。但如果你需要定制化或者用最新特性,那就得走源码安装。两种方式我都试过,给你说说区别。
4.1.1 pip安装(推荐新手)
说白了就是一行命令的事。不过要注意——vLLM对CUDA版本有要求,我建议用CUDA 11.8或12.1以上。
# 创建虚拟环境(我习惯用conda)
conda create -n vllm_env python=3.10 -y
conda activate vllm_env
# pip安装vLLM
pip install vllm
# 验证安装
python -c "import vllm; print(vllm.__version__)"
小提示:如果你在国产GPU(比如华为昇腾、寒武纪)上跑,pip安装可能不直接支持。这时候需要走源码编译,或者用厂商提供的定制版vLLM。我之前在昇腾上折腾过,坑不少。
4.1.2 源码安装(进阶玩家)
为什么要源码安装?嗯,两个场景:一是你想改vLLM内部逻辑(比如自定义调度策略),二是官方还没发布你需要的功能。我去年为了支持一个特殊的量化格式,就不得不从源码编译。
# 克隆仓库
git clone https://github.com/vllm-project/vllm.git
cd vllm
# 安装依赖
pip install -e .
# 编译(这一步比较耗时,我机器上大概15分钟)
# 如果遇到编译错误,八成是CUDA路径没配好
export CUDA_HOME=/usr/local/cuda-12.1
python setup.py build_ext --inplace
注意:源码安装时,确保你的gcc版本在9以上。我曾经因为gcc 7.5编译到一半报错,查了半天才发现是编译器太老。
4.2 模型下载与加载
装完vLLM,下一步就是搞模型。你可以从HuggingFace下载,也可以用本地已经有的模型文件。我个人更推荐先下载到本地,避免每次启动都去拉网络。
4.2.1 从HuggingFace下载
这里有个小技巧——用huggingface-cli工具,支持断点续传。我下载70B模型时网络断了三次,全靠它续命。
# 安装huggingface-cli
pip install huggingface-hub
# 登录(如果需要访问gated模型)
huggingface-cli login
# 下载模型(以Qwen2.5-7B为例)
huggingface-cli download Qwen/Qwen2.5-7B-Instruct --local-dir ./models/Qwen2.5-7B-Instruct
4.2.2 加载模型到vLLM
模型下载好之后,加载就很简单了。但这里有个坑——显存不够怎么办?我建议先用nvidia-smi看看剩余显存,再决定模型精度和并行策略。
# 加载模型并启动推理(Python脚本方式)
from vllm import LLM, SamplingParams
# 初始化模型
llm = LLM(
model="./models/Qwen2.5-7B-Instruct",
tensor_parallel_size=1, # 单卡就用1,多卡可以设2、4、8
dtype="auto", # 自动选择精度,一般float16
gpu_memory_utilization=0.9, # 显存利用率,别设太高,留点给KV cache
)
# 设置采样参数
sampling_params = SamplingParams(
temperature=0.7,
top_p=0.9,
max_tokens=512,
)
# 推理
outputs = llm.generate(["请介绍一下vLLM的特点"], sampling_params)
print(outputs[0].outputs[0].text)
关键参数说明:
tensor_parallel_size:张量并行数,单卡设1,多卡按GPU数量设gpu_memory_utilization:显存利用率,建议0.85-0.95,太高容易OOMdtype:模型精度,auto自动选,也可以强制设float16或bfloat16
4.3 启动OpenAI兼容的API服务
vLLM最方便的一点——它直接实现了OpenAI的API接口格式。这意味着你之前用OpenAI SDK写的代码,换个base_url就能用。我团队迁移时几乎没改代码。
4.3.1 命令行启动
# 最简单的启动方式
python -m vllm.entrypoints.openai.api_server \
--model ./models/Qwen2.5-7B-Instruct \
--port 8000 \
--host 0.0.0.0
# 带更多参数的启动
python -m vllm.entrypoints.openai.api_server \
--model ./models/Qwen2.5-7B-Instruct \
--tensor-parallel-size 2 \
--gpu-memory-utilization 0.9 \
--max-model-len 8192 \
--port 8000 \
--host 0.0.0.0
避坑指南:我曾经把--host设成127.0.0.1,结果其他机器访问不了。如果你需要局域网访问,记得用0.0.0.0。另外,端口8000容易被占用,可以换成8080或9000。
4.3.2 验证服务是否启动成功
启动后,你会看到类似这样的日志:
INFO: Started server process [12345]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:8000
看到这个就说明服务起来了。你可以用浏览器访问http://localhost:8000/docs,会看到Swagger文档页面。
4.4 客户端调用测试
服务跑起来了,怎么调?两种方式:curl命令行,或者用Python的OpenAI SDK。我平时调试用curl,正式集成用SDK。
4.4.1 用curl测试
# 聊天补全接口
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "./models/Qwen2.5-7B-Instruct",
"messages": [
{"role": "system", "content": "你是一个有用的助手。"},
{"role": "user", "content": "请用一句话介绍vLLM"}
],
"temperature": 0.7,
"max_tokens": 100
}'
返回结果大概长这样:
{
"id": "cmpl-xxx",
"object": "chat.completion",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "vLLM是一个高性能的大语言模型推理引擎,通过PagedAttention和连续批处理技术实现高效推理。"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 28,
"completion_tokens": 25,
"total_tokens": 53
}
}
4.4.2 用Python SDK测试
这才是正式集成的方式。你想想看,如果你之前用OpenAI的SDK,现在只需要改两行代码:
from openai import OpenAI
# 只需要改base_url和api_key(vLLM不校验key,但格式要保留)
client = OpenAI(
base_url="http://localhost:8000/v1",
api_key="not-needed" # vLLM不校验,但字段必须传
)
# 调用方式和OpenAI完全一致
response = client.chat.completions.create(
model="./models/Qwen2.5-7B-Instruct",
messages=[
{"role": "system", "content": "你是一个Python专家。"},
{"role": "user", "content": "请写一个快速排序的Python实现"}
],
temperature=0.7,
max_tokens=500
)
print(response.choices[0].message.content)
迁移成本几乎为零。我去年把一个生产系统从OpenAI切到vLLM,只改了base_url和api_key两行,其他代码纹丝不动。这就是兼容OpenAI接口的好处。
4.4.3 流式输出测试
如果你需要流式输出(像ChatGPT那样一个字一个字蹦),也很简单:
# 流式调用
stream = client.chat.completions.create(
model="./models/Qwen2.5-7B-Instruct",
messages=[{"role": "user", "content": "讲个笑话"}],
stream=True, # 开启流式
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
注意:流式输出时,max_tokens不要设太大,否则前端等待时间过长。我一般设512或1024,用户体验比较好。
4.5 常见问题与排查
最后,我把部署过程中最常遇到的几个问题列出来,你遇到了可以直接对照排查。
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 启动时报CUDA out of memory | 显存不足,或gpu_memory_utilization设太高 |
降低gpu_memory_utilization到0.8,或换小模型 |
| API返回404 | 请求路径不对,vLLM的API路径是/v1/chat/completions |
检查URL是否包含/v1前缀 |
| 模型加载极慢 | 第一次加载需要下载或转换模型格式 | 提前用huggingface-cli下载到本地 |
| 流式输出卡顿 | max_tokens太大或网络延迟 |
减小max_tokens,或检查网络带宽 |
嗯,以上就是vLLM单机部署的完整流程。从安装到启动服务,再到客户端调用,每一步我都把实际项目中踩过的坑告诉你了。你跟着走一遍,应该半小时内就能跑起来一个可用的推理服务。