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__)"
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() 时无需等待动态分配。
其核心流程如下:
- 模型加载:通过
model参数指定 Hugging Face 模型 ID 或本地路径。 - 分词器加载:自动从模型目录中加载对应的 tokenizer。
- 显存规划:根据
gpu_memory_utilization(默认 0.9)计算 KV Cache 可用显存。 - 请求调度:
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 级信息。
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 将显存划分为三个主要区域:模型权重、KV Cache 池和临时激活内存。其中 KV Cache 池是 vLLM 的核心优化点,它通过 PagedAttention 将显存分割为固定大小的块,按需分配给不同序列,从而避免了传统推理中的显存碎片化与预分配浪费。
最后,建议你在自己的 GPU 上运行一次上述代码,并尝试修改 temperature、max_tokens 等参数,观察生成结果的变化。只有亲手操作,才能真正理解 vLLM 的高效与便捷。