4. vLLM单机部署:从源码到API服务

好,咱们进入实战环节。这一章我带你走一遍vLLM单机部署的完整流程——从安装、下载模型,到启动一个兼容OpenAI的API服务,最后用客户端调一下试试。整个过程我踩过不少坑,这次一并告诉你。

核心流程一览:源码安装 vs pip安装 → 模型下载与加载 → 启动API服务 → 客户端调用测试

安装方式选择 源码 / pip 模型下载 HuggingFace / 本地 启动API服务 OpenAI 兼容接口 客户端测试 curl / Python SDK vLLM 单机部署四步走

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,太高容易OOM
  • dtype:模型精度,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单机部署的完整流程。从安装到启动服务,再到客户端调用,每一步我都把实际项目中踩过的坑告诉你了。你跟着走一遍,应该半小时内就能跑起来一个可用的推理服务。


专注资料整理