4、快速上手:使用vLLM加载模型并生成文本

在了解了 vLLM 的核心组件与 PagedAttention 原理之后,我们直接进入实战环节。本章的目标是:在本地环境中,用最少的代码,通过 vLLM 加载一个开源大语言模型,并成功生成一段文本。你将看到,与原生 Hugging Face Transformers 的推理流程相比,vLLM 的 API 设计极为简洁,同时内部自动完成了 KV Cache 管理、连续批处理与 CUDA 图优化。

4.1 环境准备与安装

在开始之前,请确保你的环境满足以下条件:

  • 操作系统:Linux(推荐 Ubuntu 20.04+)或 Windows WSL2。
  • Python:3.9 ~ 3.12。
  • GPU:NVIDIA GPU(显存建议 ≥ 8GB),并已安装 CUDA 11.8 或更高版本。
  • 驱动:NVIDIA 驱动版本 ≥ 525。

安装 vLLM 非常简单,推荐使用 pip 直接安装预编译的 wheel 包:

pip install vllm

安装完成后,可以通过以下命令验证是否安装成功,并查看版本号:

python -c "import vllm; print(vllm.__version__)"
提示:如果你的 GPU 显存较小(如 8GB),建议从 Hugging Face 下载 Qwen2.5-1.5B-Instruct 或 facebook/opt-125m 等小型模型进行测试。vLLM 对模型格式要求为 safetensors 或 bin 权重,主流开源模型均已支持。

4.2 核心原理:LLM 类与离线推理

vLLM 的离线推理入口是 vllm.LLM 类。它负责加载模型、初始化 KV Cache 池、创建 CUDA 图空间,并提供一个线程安全的 generate() 方法。与 Transformers 的 pipeline 不同,vLLM 的 LLM 类在初始化时即完成显存预分配,因此首次调用 generate() 时无需等待动态分配。

其核心流程如下:

  1. 模型加载:通过 model 参数指定 Hugging Face 模型 ID 或本地路径。
  2. 分词器加载:自动从模型目录中加载对应的 tokenizer。
  3. 显存规划:根据 gpu_memory_utilization(默认 0.9)计算 KV Cache 可用显存。
  4. 请求调度:generate() 接收一个或多个 prompt,内部进行连续批处理。

下面是最小可用的生成代码:

from vllm import LLM, SamplingParams

# 1. 加载模型(首次运行会下载权重)
llm = LLM(model="Qwen/Qwen2.5-1.5B-Instruct")

# 2. 配置采样参数
sampling_params = SamplingParams(
    temperature=0.7,
    top_p=0.9,
    max_tokens=256,
    repetition_penalty=1.05
)

# 3. 输入提示词
prompts = [
    "请用一句话解释什么是大语言模型:",
    "写一首关于秋天的五言绝句:"
]

# 4. 批量生成
outputs = llm.generate(prompts, sampling_params)

# 5. 打印结果
for output in outputs:
    prompt = output.prompt
    generated_text = output.outputs[0].text
    print(f"Prompt: {prompt!r}\nGenerated: {generated_text!r}\n")

这段代码完成了从加载到生成的全部流程。注意 outputs 是一个 RequestOutput 列表,每个对象包含 prompt、outputs(可能有多条候选,取决于 n 参数)以及 token 级信息。

关键点:vLLM 的 generate() 是同步阻塞的。对于需要流式输出或高并发的场景,应使用 AsyncLLMEngine 或启动 OpenAI 兼容服务器(见 4.4 节)。

4.3 方法流程:采样参数与批处理

SamplingParams 是控制生成质量的核心对象。下表列出了最常用的参数及其作用:

参数 默认值 说明
temperature 1.0 采样温度。越低越确定,越高越发散。
top_p 1.0 核采样阈值。只从累积概率超过 top_p 的 token 中采样。
max_tokens 16 生成的最大 token 数(不含输入)。
repetition_penalty 1.0 重复惩罚。大于 1 抑制重复,小于 1 鼓励重复。
n 1 每个 prompt 生成几条候选序列。
stop None 停止生成的字符串列表,如 ["\n"]。

vLLM 的批处理是动态的。当你传入一个包含多个 prompt 的列表时,vLLM 会将它们组成一个 序列组,并在每次前向传播时,只计算当前尚未完成的序列。这意味着即使某个序列提前到达 max_tokens 或触发停止条件,它也会立即从批处理中移除,释放显存给其他序列。

下面是一个更贴近实际使用的示例,展示了如何设置停止词与多候选生成:

from vllm import SamplingParams

params = SamplingParams(
    temperature=0.8,
    top_p=0.95,
    max_tokens=512,
    n=2,                     # 每个 prompt 生成 2 条候选
    stop=["\n\n", "###"],    # 遇到连续换行或 ### 停止
    stop_token_ids=[151645]  # Qwen 的结束 token ID
)

outputs = llm.generate("请给出三个提高学习效率的建议:", params)
for output in outputs:
    for idx, seq in enumerate(output.outputs):
        print(f"候选 {idx+1}: {seq.text}\n")

4.4 案例:启动 OpenAI 兼容的 API 服务器

除了离线推理,vLLM 还提供了 OpenAI 兼容的 HTTP 服务器。这使得你可以直接使用 openai Python 库或 curl 命令访问模型,非常适合集成到现有应用中。

启动服务器的命令如下:

python -m vllm.entrypoints.openai.api_server \
    --model Qwen/Qwen2.5-1.5B-Instruct \
    --host 0.0.0.0 \
    --port 8000 \
    --gpu-memory-utilization 0.85 \
    --max-model-len 4096

启动成功后,你可以用 curl 测试接口:

curl http://localhost:8000/v1/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen2.5-1.5B-Instruct",
    "prompt": "什么是注意力机制?",
    "max_tokens": 128,
    "temperature": 0.6
  }'

返回的 JSON 结构与 OpenAI 的 /v1/completions 完全一致,包含 choices、usage 等字段。对于对话模型,还可以使用 /v1/chat/completions 接口,传入 messages 列表。

注意:当使用 --max-model-len 4096 时,vLLM 会为每个序列预留最多 4096 个 token 的 KV Cache 空间。如果显存不足,启动时会报错。请根据模型实际上下文长度和 GPU 显存合理设置该值。

4.5 误区与复盘:常见问题排查

在实际使用中,初学者常遇到以下几类问题,这里逐一复盘:

  • 显存不足(OOM):vLLM 默认使用 90% 的显存作为 KV Cache。如果模型本身较大,可调低 gpu_memory_utilization 至 0.7,或换用更小的模型。
  • 生成速度慢:检查是否设置了 max_tokens 过大。vLLM 的连续批处理在长序列生成时优势明显,但单条短请求可能不如 Transformers 的贪心解码快。
  • 输出乱码或重复:这通常是采样参数设置不当。尝试降低 temperature 至 0.3~0.5,并增大 repetition_penalty 至 1.1~1.2。
  • 模型加载失败:确认模型路径正确,且 Hugging Face 缓存目录有足够磁盘空间。vLLM 不支持 .pt 格式的旧权重,需转换为 safetensors。

下面这张图总结了 vLLM 从加载到生成的核心数据流与显存分配逻辑,帮助你建立整体认知:

vLLM 离线推理数据流与显存分配 输入 Prompts ["解释注意力机制", "写一首诗", ...] (批量请求) vLLM LLM 实例 • 模型权重加载 • Tokenizer 初始化 • CUDA 图空间创建 • KV Cache 池预分配 GPU 显存布局 模型权重 (常驻显存) KV Cache 池 (PagedAttention 管理) 块大小 = 16 tokens gpu_memory_utilization=0.9 临时激活内存 (前向传播临时张量) 生成结果 RequestOutput 列表 包含 prompt + 生成文本 (token 级信息) 采样完成,返回文本 连续批处理调度 序列完成即退出批处理 新请求动态加入 KV Cache 按需分配,显存利用率提升 2~4 倍

通过上图可以看到,vLLM 将显存划分为三个主要区域:模型权重、KV Cache 池和临时激活内存。其中 KV Cache 池是 vLLM 的核心优化点,它通过 PagedAttention 将显存分割为固定大小的块,按需分配给不同序列,从而避免了传统推理中的显存碎片化与预分配浪费。

最后,建议你在自己的 GPU 上运行一次上述代码,并尝试修改 temperature、max_tokens 等参数,观察生成结果的变化。只有亲手操作,才能真正理解 vLLM 的高效与便捷。