AI Infra 学习路线 · 阶段三 · 推理线 · 模块二
目标:在本地部署 vLLM,理解专业推理框架,和 transformers 对比
环境:Windows + WSL2 + RTX 5060 Ti(Blackwell sm_120,8G)+ uv 管理的 venv
本篇覆盖:安装策略 + 跑通过程 + 五个坑 + 一个重要性能发现
0. 背景:为什么 vLLM 在这套环境上难装
- vLLM 对环境挑剔,和 CUDA/PyTorch 版本绑定紧。
- RTX 5060 Ti 是 Blackwell(sm_120),非常新,框架生态还在追赶。
- WSL 在原生 Linux 的坑之上再加一层(NVML 不兼容 fork、调试工具受限等)。
- 结论:能装上,但不是开箱即用,需要逐个填坑。
1. 安装策略(关键:别覆盖你已有的好 torch)
核心原则:保护现有能用的 PyTorch cu130,别让 vLLM 装错 CUDA 版本。
做法:
- 建独立 venv(炸了不影响主环境 mycuda):
uv venv vllm-env--python3.12sourcevllm-env/bin/activate - 先装 cu130 的 torch,再装 vllm,都指定 cu130 后端:
uv pipinstalltorch --torch-backend=cu130 uv pipinstallvllm --torch-backend=cu130
注意:vLLM 官方现在直接提供 cu130 预编译版,不用从源码编译(省几小时)。
关键观察:装 vllm 时它把 torch 2.12 换成了2.11.0+cu130(vllm 0.22.1 要求 torch 2.11)。
- 这是良性的:它换的是cu130版本(不是降级到不支持 Blackwell 的 cu126/cu128)。
- 最怕的覆盖是降到旧 CUDA → 那会让 Blackwell 没法编译 kernel。务必装完检查:
python-c"import torch; print(torch.__version__, torch.cuda.is_available())"# 应是 2.11.0+cu130 True
2. 五个坑(按出现顺序,这是本篇精华)
坑 1:import vllm —— 居然一次过
担心的 undefined symbol 没出现。前面装对 cu130 + vllm 自动带了 flashinfer,绕过了。
(很多老帖子卡在这,运气+正确装法。)
坑 2:多进程递归启动(WSL 必踩)
报错:An attempt has been made to start a new process before the current process has finished its bootstrapping phase,日志里"正在加载模型"打印了两遍。
- 根因:WSL 下 NVML 不兼容 fork,vLLM 强制用spawn启动子进程;spawn 会重新 import 你的脚本,若执行代码在顶层就会无限递归。
- 解决:执行代码必须包进
if __name__ == "__main__":defmain():llm=LLM(...)...if__name__=="__main__":main() - 记牢:WSL 上用 vLLM(或任何 spawn 多进程库),执行代码必须放在 main 守卫里。
坑 3:Python.h: No such file or directory
报错:fatal error: Python.h: No such file or directory(在 torch.compile 的 JIT 编译阶段)。
- 根因:vLLM/Triton 要即时编译(JIT)一小段 C 代码,需要 Python 的 C 开发头文件,但系统没装。
- 解决(系统级 apt 包,不是 pip):
sudoaptinstall-ypython3.12-dev build-essential# 注意要匹配 venv 的 Python 版本(这里是 3.12) - 这是搜索资料里提到的"FlashInfer/Triton JIT 需要 gcc/python3-dev/nvcc/ninja"那类坑之一。
坑 4:FlashInfer requires GPUs with sm75 or higher(误导性报错)
报错出现在采样(sampler)环节:RuntimeError: FlashInfer requires GPUs with sm75 or higher。
- 真相:5060Ti 是 sm_120,远高于 sm75,本该满足。是 FlashInfer 的架构检测 check_cuda_arch() 没读到你的能力(Blackwell 太新),拿到空值才误判。
- 旁证:日志里有警告
Failed to get device capability: SM 12.x requires CUDA >= 12.9(警告非致命,但说明检测有问题)。 - 解决(绕开 FlashInfer 采样,改用 PyTorch 原生采样):
exportVLLM_USE_FLASHINFER_SAMPLER=0python vllm_first.py - 备选(方案B):LLM(…, enforce_eager=True) 关掉 compile/CUDA graph 等 JIT 路径,也能绕开很多此类问题(代价是慢)。可与方案A叠加。
坑 5:(性能问题,见第 4 节)—— 跑通了但极慢
3. 跑通的最小脚本
fromvllmimportLLM,SamplingParamsdefmain():llm=LLM(model="Qwen/Qwen2.5-0.5B-Instruct",dtype="float16",gpu_memory_utilization=0.7,# 只用70%显存,8G卡稳妥max_model_len=2048,# 限制上下文,降低 KV cache 压力)sampling_params=SamplingParams(temperature=0,max_tokens=100)outputs=llm.generate(["用一句话解释什么是GPU"],sampling_params)foroinoutputs:print(o.outputs[0].text)if__name__=="__main__":main()运行(带绕开 FlashInfer 的环境变量):
exportVLLM_USE_FLASHINFER_SAMPLER=0python vllm_first.py模型已在 HF 缓存(~/.cache/huggingface/hub),vLLM 自动复用,不重新下载。
缓存是用户级的,跨 venv 共享(mycuda 下过的模型 vllm-env 也能用)。
4. 重要性能发现(比"跑通"更有价值的认知)
现象:vLLM 生成一段约 100 token 花了27.88 秒;而 transformers 跑同一个 0.5B 模型,100 token 仅 0.7 秒(~50 tok/s)。vLLM 反而慢了几十倍。
原因(不是 vLLM 差,是"未充分适配的 vLLM 在 Blackwell 上慢"):
- 日志警告:
Triton kernel JIT compilation during inference: _compute_slot_mapping_kernel. This causes a latency spike—— 推理过程中还在临时 JIT 编译 kernel,极慢。 - 为绕坑关掉了 FlashInfer 采样,走了较慢的回退路径。
- vLLM 的高性能依赖其优化好的 CUDA kernel/CUDA graph/FlashInfer,这些在 Blackwell 上要么没适配、要么被我们为跑通而关掉。
核心认知(Infra 工程师该有的判断):
在前沿硬件上,“能让它跑起来” ≠ “能让它跑得快”。框架的优化路径往往还没适配新硬件。
这个 27 秒不代表 vLLM 慢,代表「未充分适配 + 为兼容做的妥协」慢。
衍生的工程决策(项目里值得写的思考):
vLLM 在本卡"能跑但跑不快",transformers"又稳又快"。这种现实约束下怎么权衡、怎么对比,本身就是有深度的项目主题,比一个完美 benchmark 更体现工程判断力。
5. 跑通过程中看到的 vLLM 内部信号(值得注意)
日志里这些是 vLLM 比 transformers 精细之处,后面要深入:
Initializing a V1 LLM engine—— vLLM 的引擎架构enable_prefix_caching=True—— 前缀缓存(相同前缀 KV 复用)enable_chunked_prefill=True—— 分块 prefillChunked prefill ... max_num_batched_tokens=8192—— 批处理调度- KV cache 初始化(determine_available_memory)—— vLLM 启动时预先规划 KV cache 显存,这是它的核心管理机制
Using FlashAttention version 2—— 注意力后端- torch.compile 编译模型(花了 8.9s)—— 启动慢的原因之一,但能换运行时加速(正常硬件上)