☰
WSL2 下安装 vLLM 的完整实战:GPU 直通、CUDA 配置与踩坑指南
2026/10/16 7:33:28 网站建设 项目流程

很多做深度学习推理的朋友,平时主力机是 Windows,但真心跑训练和推理时还是想去 Linux 环境里折腾。折腾的原因倒不是说 Windows 不能干活,而是像 vLLM 这类高性能推理库,很多依赖、系统库、编译参数都是围绕 Linux 生态设计的,在 Windows 上硬莽会遇到一堆预编译轮子缺失、环境变量混乱、兼容性诡异的问题。vLLM 本身就是高性能大模型推理引擎,靠 PagedAttention 这类内存管理技巧把推理吞吐拉得很高,也是目前很多大模型服务端实际在跑的那套方案。对于不方便装双系统、或者只想在现有机器上快速验证效果的人来说,WSL2 环境算是一个折中选择:既能拿到接近原生 Linux 的内核能力,又能保留 Windows 的日常使用习惯。

这篇文章我按实际踩坑顺序来写,从环境检查、磁盘内存配置、CUDA 工具链、到真正把 vLLM 跑起来,再附带我遇到过的各类报错和处理方式。给两类人看:一是完全没接触过 WSL2,想直接照着操作的小白;二是在 Windows 上装过 CUDA、但被 WSL2 的 GPU 直通问题卡过的人。我把话说得直接一点:这条路能走通,但不是装个软件那么简单,前置环境比安装命令本身更重要。

1. 为什么要把 vLLM 装到 WSL2 里

1.1 这套组合解决了什么问题

vLLM 这个引擎本身是为了高并发、大吞吐的 LLM 推理场景设计的。它最核心的价值,是让显存里能同时驻留更多请求批次,同时通过连续批处理和页面式注意力机制,把 GPU 的利用率压得很高。比起传统的逐条推理,vLLM 在同样的硬件上能服务的 QPS 会高不少,这也是很多部署方案选它的原因。

但是,vLLM 官方对 Windows 的原生支持一直不完整。它的依赖链里包含不少需要在 Linux 下编译的算子,虽然现在也有 Windows 的尝试版本,但我个人不推荐在生产环境用。更常见的做法是:Windows 承担日常开发、写代码、看日志,真正的推理服务放到一台 Linux 服务器上。问题在于,很多个人开发者手里没有那么一台现成的 Linux GPU 机器,又不想因为一个小实验就去重装系统。

WSL2 在这里的价值,是把 Windows 里已有的 GPU 资源直接透传给 Linux 环境。WSL2 不是虚拟机,它跑在轻量级虚拟化层上,Linux 内核是独立运行的,但显卡驱动和显存可以由 Windows 主机统一管理。通过这套机制,你在 Linux 环境里执行 nvidia-smi 看到的显卡信息和 Windows 任务管理器里看到的,是同一张卡、同一份显存。

1.2 环境适配的边界在哪

WSL2 里跑 vLLM 并不等于完全等于一台裸机 Linux 服务器。性能损耗主要出现在文件 I/O 和部分系统调用上,GPU 计算本身因为走的直通通道,损耗非常小。这意味着如果你的场景是批量推理、并发请求、显存加载这类计算密集型任务,WSL2 完全够用;但如果你的场景是频繁读取分布在 Windows 盘符下的大规模数据集,IO 性能会不太好看。

另外一个边界是网络。WSL2 的网络是虚拟化网卡,默认情况下外部设备访问你 WSL2 里跑的服务会麻烦一点,但本机访问完全没问题。你要在 WSL2 里启动一个 vLLM 服务,再从 Windows 浏览器或代码里调用 localhost:8000,这个是直接通了的。如果想让局域网里其他机器访问,需要额外配置端口转发,这块我在后面会提到。

还有一个很多人忽视的点:WSL2 的 Linux 发行版本和 Windows 系统版本会互相约束。老一点的 Windows 版本可能不支持 WSL2 的 GPU 直通,或者功能开关不完整。我建议你先确认自己的系统能装 Docker Desktop 的 WSL2 后端,或者直接执行 wsl --status 看输出,再做后续规划。

2. 装之前先把 WSL2 准备好

2.1 确认系统版本并启用功能开关

这一步是整套流程里最容易翻车的环节。很多人装完发行版发现 GPU 用不了,回查才发现最早的 Windows 功能没有完全启用。

首先打开管理员权限的 PowerShell,执行:

wsl --status wsl --version

如果系统提示 WSL 已经安装并显示默认版本为 2,那基础条件满足。如果提示没有 WSL 或版本太老,先执行:

wsl --install

执行完重启电脑。这个命令会默认安装 WSL2 内核和一个 Linux 发行版。不过我不太建议全程用这个默认发行版,原因后面讲。

如果你曾经装过 WSL1,需要把默认版本切到 2:

wsl --set-default-version 2

然后把需要 Linux 访问的发行版从 WSL1 迁移到 WSL2:

wsl --set-version 发行版名称 2

很多人到这里漏了一步:确认“虚拟机平台”功能已经开启。可以在 PowerShell 里执行:

dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

如果是新装系统,通常 wsl --install 会自动处理,但老系统经常缺这个。漏掉的话 WSL2 会启动失败或者进入 WSL1 兼容模式。

提示:检查 WSL 版本的输出中,如果显示 WSL 版本为 1.x,说明你的 Windows 当前用的是旧版 WSL,需要更新到新的 Store 版 WSL。直接运行 wsl --update 即可。

2.2 配置 GPU 直通与新版驱动

WSL2 的 GPU 直通能力,本质上依赖 Windows 侧的显卡驱动。WSL2 里的 Linux 环境不需要单独安装显卡驱动,它会在启动时通过 Windows 的显卡驱动接口映射 CUDA 能力。所以前提条件只有一个:Windows 侧驱动必须支持 WSL 的 GPU 加速。

这里非常关键的一个坑在于:驱动版本和 CUDA 版本的关系。在 Windows 原生环境里,你装着 CUDA 开发包,配套驱动也能用;但 WSL2 环境里,Linux 侧的 CUDA 运行库是装在发行版里的,而驱动层用的是 Windows 的显卡驱动。我在第一次跑的时候,Linux 侧用 pip 装的 CUDA 库版本比 Windows 驱动要求的新,结果启动时 CUDA 初始化直接报错,报错信息又不会明确告诉你是驱动版本不够。

我的建议是:先更新 Windows 侧显卡驱动到最新稳定版,然后再在 Linux 侧安装 CUDA 工具包时,优先选择比自己驱动版本低一到两个小版本的 CUDA 版本。例如驱动支持到某个高版本,CUDA 就选稳定版而不是最新版。

验证 GPU 直通是否生效,在 WSL2 终端里执行:

nvidia-smi

能显示显卡型号、驱动版本、显存大小,就是通了。如果提示 command not found,先安装:

sudo apt update sudo apt install -y nvidia-utils-xxx

具体安装包名可能会因为发行版不同而不同,最简单的方式是直接装 CUDA 工具集里的它,参考 3.2 节。

如果 nvidia-smi 存在但看不到显卡,大概率是 Linux 内核模块没挂载。检查:

ls /dev/nvidia* cat /proc/driver/nvidia/version

正常的输出应该有 nvidia0、nvidiactl、nvidia-modeset 这些设备文件。如果你看到 /dev/nvidia-uvm 缺失,我后文第 5 节给了处理办法。

2.3 规划 Linux 虚拟磁盘和内存大小

WSL2 的 Linux 文件系统保存在一个名为 ext4.vhdx 的虚拟磁盘里。这个 vhdx 文件放在 Windows 用户目录下,默认情况随着你往里塞模型、装依赖会不断膨胀。模型文件稍微大一点,几十 GB 就出去了。我给你的建议是不要用默认位置,至少不要让它和系统盘抢空间。

具体做法:在 Windows 的用户目录下创建 .wslconfig 文件,内容如下:

[wsl2] memory=16GB processors=8 swap=8GB

memory 是指 WSL2 最多能用的内存,processors 是指最多能占用的 CPU 核数。这两项不是越大越好,因为 WSL2 和 Windows 共享物理资源。如果你机器是 32GB 内存,给 WSL2 分配 16GB 左右比较合理,留一半给 Windows 做日常任务和缓存。

虚拟磁盘位置迁移涉及到一个技巧。在微软文档里的标准做法是导出导入发行版,但手动移动 vhdx 更灵活,前提是你能找到文件。在 WSL2 里执行:

wsl --shutdown

然后定位到C:\Users\你的用户名\AppData\Local\Packages\CanonicalGroupLimited...之类的路径,找到 ext4.vhdx。把文件剪切到你想放的目录,再执行 WSL2 导入。如果你觉得麻烦,也可以把模型数据放到 Windows 盘符下,通过/mnt/d/模型目录访问,但要注意性能折扣。我个人的做法是:环境自身放在 C 盘 vhdx 里,模型权重文件放入 D 盘的普通文件夹,用软链接指过去,这样模型丢失后方便管理。

3. vLLM 安装的完整流程

3.1 选择合适的 CUDA 工具链

WSL2 里装 vLLM 之前,先把 CUDA 环境理顺。这里有两种路线,我分别说明。

路线一:安装完整的 CUDA Toolkit。适合需要编译扩展算子或者调试 CUDA 代码的场景。执行:

sudo apt update sudo apt install -y build-essential wget 某个CUDA安装包.run # 这里自己选择合适的版本 sudo sh cuda_xxx_linux.run --toolkit --silent --override

装完配置环境变量:

export PATH=/usr/local/cuda/bin:$PATH export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH

路线二:不装完整 Toolkit,只靠 pip 包自带的 CUDA 库。vLLM 通过 PyPI 安装时会自动拉取预编译的 CUDA 依赖,比如 torch 和 flash attention 相关算子都捆绑好了。这种方式对纯推理用户最友好,装完就能跑。

我推荐大多数场景选路线二,因为 vLLM 对 CUDA 运行库的管理已经做得很完善,你完全没必要手动装一套可能和它冲突的工具链。如果后面要做自定义算子或者修改 kernel,再装完整 Toolkit。但要注意:无论哪条路线,Windows 侧的显卡驱动是唯一决定 CUDA 运行上限的因素。

提示:安装 CUDA 之前,在 WSL2 里执行uname -r看一下内核版本。内核太旧的话部分 GPU 直通特性可能不可用,建议先wsl --update。

3.2 创建独立的 Python 环境

vLLM 依赖比较重,而且和 PyTorch 版本强绑定,千万不要直接把环境装进系统默认 Python 里。我建议用 Miniconda 管理环境。首先在 WSL2 中下载 Miniconda 安装脚本:

wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh bash Miniconda3-latest-Linux-x86_64.sh

安装后做一次初始化:

source ~/.bashrc conda init

然后创建 vLLM 专用环境:

conda create -n vllm python=3.10 -y conda activate vllm

Python 版本我选择 3.10,不是最新版本。3.11、3.12 虽然也能跑,但在一些扩展库的预编译轮子上,3.10 兼容性最稳定。如果你只想做推理不碰源码,3.10 是保守又可靠的选择。

3.3 安装 vLLM 本体

环境就绪之后,直接安装:

pip install --upgrade pip pip install vllm

这里不要加--user,因为 conda 环境本身就是隔离的。安装过程会拉取 torch、transformers、safetensors、xformers 一系列依赖,体积很大,几百 MB 到 1GB 都有可能。如果网络条件一般,建议先配置 pip 镜像源再安装,速度会快很多:

pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

如果你需要最新的 commit 或特性,也可以从源码安装:

git clone https://github.com/vllm-project/vllm.git cd vllm pip install -e .

源码安装会触发编译,比较耗时。我个人建议第一遍直接用 pip 轮子,确认能跑通之后再考虑源码。

安装完成后,验证一下版本和依赖是否完整:

python -c "import vllm; print(vllm.__version__)"

3.4 用一个小模型做冒烟测试

在正式启动大模型服务之前,先跑一个小模型验证环境完整性是最稳妥的。选择一个小参数模型,比如 1B 量级的开源模型,下载体积大约 2GB 左右。

先测试一个最简单的推理请求:

python -c " from vllm import LLM, SamplingParams llm = LLM(model='某组织/小模型名称', dtype='float16') out = llm.generate(['用一句话介绍你自己']) print(out) "

这里有两个细节需要注意:

  • dtype 设为 float16,降低显存占用。
  • 如果这一步报 CUDA 错误,说明前面 GPU 直通没配好,直接去看第 5 节。

冒烟测试通过之后,再用 vLLM 的 OpenAI 兼容服务方式启动正式服务,这才是服务于实际业务的关键一步。

4. 跑通一个可调用的推理服务

4.1 启动 OpenAI 兼容接口

vLLM 提供一个内置的 API 服务,接口协议兼容 OpenAI 格式,这意味着你之前写的各种调用代码都可以复用。启动命令如下:

python -m vllm.entrypoints.openai.api_server \ --model 某组织/模型名称 \ --dtype float16 \ --port 8000 \ --gpu-memory-utilization 0.85 \ --max-model-len 8192

这里我解释一下每个参数的实际意义,避免你照抄后不清楚会发生什么。

--model指定模型名称,vLLM 会自动从模型仓库下载权重,如果已经有本地权重,可以填本地路径。--dtype float16强制使用半精度,减少显存。--gpu-memory-utilization 0.85告诉 vLLM 可以用到 85% 的显存,剩余部分留给 CUDA 上下文和临时操作。这个值尽量不要设到 0.95 以上,因为显存被全部占满后,一旦请求长度超过预估值,就可能触发 OOM。--max-model-len 8192限制输入输出 token 总长度,过长的请求会被直接拒绝或截断。

启动成功后,终端会打印类似INFO: Started server process和监听地址。此时在 Windows 浏览器里访问:

http://localhost:8000/docs

能看到一个交互式 API 文档页面。这证明了 WSL2 内部服务已经被 Windows 正常访问到了。

4.2 用 curl 和 Python 验证请求链路

先用 curl 做一个最简单的连通性测试:

curl http://localhost:8000/v1/models

这条命令会返回当前加载的模型名列表。接着做一个文本生成请求:

curl http://localhost:8000/v1/completions \ -H "Content-Type: application/json" \ -d '{ "model": "某组织/模型名称", "prompt": "讲一个程序员的笑话", "max_tokens": 256, "temperature": 0.7 }'

如果你更习惯用 Python 调用,这样写:

from openai import OpenAI client = OpenAI( base_url="http://localhost:8000/v1", api_key="EMPTY" ) resp = client.chat.completions.create( model="某组织/模型名称", messages=[ {"role": "system", "content": "你是助手"}, {"role": "user", "content": "介绍一下 WSL2 和 vLLM 的关系"} ], max_tokens=512 ) print(resp.choices[0].message.content)

这里 base_url 要写完整到/v1,api_key 随意填一个值,因为 vLLM 默认不校验 key。

4.3 并发请求和吞吐指标的简单观测

启动服务后,如果你想知道自己的显存和请求情况,可以一边压测一边开另一个终端执行 nvidia-smi 看显存使用率。vLLM 日志会打印每次请求的 prefill 耗时、decode 耗时以及 tokens/s 吞吐数据。

经常有人问“为什么我调用了接口但返回很慢?”这里要区分 prefill 和 decode。prefill 是计算用户输入的阶段,它是一次性计算整个输入序列,耗时会比较集中;decode 是逐 token 生成,每生成一个 token 都要和整个模型做一次前向计算。vLLM 日志里分别展示了这两个阶段的耗时,我建议你看项目文档里的 Import 与 export。

批量请求的压测可以这样简单做:

for i in {1..10}; do curl -X POST http://localhost:8000/v1/completions \ -H "Content-Type: application/json" \ -d '{"model":"某组织/模型名称","prompt":"你好","max_tokens":50}' & done wait

同时观察终端日志里的排队等待时间和吞吐速度。如果大批量请求导致 OOM,vLLM 会打印一条明确的显存不足日志,并且拒绝排队。

5. 踩坑记录与排查定位

5.1 GPU 完全没被识别

这是最典型的第一个问题。症状是启动 vLLM 时直接报错:

AssertionError: Torch not compiled with CUDA enabled

但它其实分两种情况。

第一种是 torch 装成了 CPU 版本。验证方法:

python -c "import torch; print(torch.cuda.is_available())"

如果输出 False,先重装 GPU 版 torch,再装 vLLM:

pip uninstall torch -y pip install torch --index-url https://download.pytorch.org/whl/cu124

第二种是 torch 认为 WSL2 环境不是 CUDA 环境。这种通常表现为torch.cuda.is_available()是 True,但启动 vLLM 后直接报 CUDA driver 版本不匹配。遇到这种情况,检查 Windows 侧显卡驱动版本是否够新。WSL2 的 GPU 直通对驱动版本有硬性要求,太旧的版本只支持 WSL1,不支持 CUDA。

5.2 CUDA 初始化报错 invalid device function

这个报错的常见原因是 WSL2 里存在的 Linux CUDA 库和 Windows 驱动不匹配。我遇到过一次这样的情况:Windows 显卡驱动更新到了新版本,Linux 侧 pip 安装的 torch 也带了新 CUDA 库,但系统里还残留一份旧版 CUDA toolkit,在 LD_LIBRARY_PATH 里被优先加载。

排查方式:

echo $LD_LIBRARY_PATH ls /usr/local/cuda/lib64

如果有多个版本库同时存在,指定 vLLM 使用新版本库。最简单的方法是清理掉 /usr/local/cuda 下不需要的版本,而不是试图用环境变量去覆盖。

5.3 显存不足与 max-model-len 设置

vLLM 对显存的需求经常被低估。一个 7B 模型的 fp16 权重已经占用约 14GB 显存,你还需要给 KV cache 预留空间。如果你的显卡是 12GB 显存,强行加载 7B 模型基本没有余量。这种情况下有三个思路:

第一个思路,用更小的模型或者应用量化,比如用 int8 或 int4 权重。vLLM 对量化模型的支持已经比较成熟,启动参数加 --dtype float16 之外还需要按模型方式指定 load format。第二个思路,把 gpu-memory-utilization 调低,虽然能降低 OOM 概率,但 KV cache 变小会限制并发能力。第三个思路,老老实实换显卡或者用 CPU 推理。CPU 推理 vLLM 也支持,但吞吐量完全不是一个数量级。

我个人的经验是,模型显存占用 = 权重字节数 + 激活值 + KV cache。KV cache 的大小与 max-model-len、并发数、层数有关。动手之前先估算一下能不能放得下,别等到服务启动报错再回头查,效率太低。

5.4 通过 /mnt/c 路径读取模型导致加载缓慢

很多人在 WSL2 里把模型放在 Windows 的 D 盘,然后直接用/mnt/d/models/xxx作为 --model 参数。这个做法可以工作,但要意识到:WSL2 访问 Windows 盘符属于跨界文件系统访问,性能有损耗,而且大文件的读取会占用大量 CPU。启动时加载模型需要读入整个权重文件,如果走 /mnt/d,加载时间可能比 Linux 原生文件系统慢上数倍。

我建议的做法是:模型文件放在 WSL2 内部文件系统,比如 ~/models 下。空间不够就按 2.3 节迁移 vhdx,或者用符号链接把 Windows 盘目录挂到 WSL2 文件树里,而不是直接在启动命令里填 /mnt 路径。

建议在 WSL2 里建立软链:

mkdir -p ~/models ln -s /mnt/d/ai-models/某个模型目录 ~/models/某个模型

再用 ./models/某个模型 作为 --model 参数。

5.5 端口冲突与局域网访问

如果你在 Windows 侧已经有服务占了 8000 端口,vLLM 起不来。改端口或者查占用:

netstat -ano | grep 8000

如果要让同一局域网的其他机器访问 WSL2 里的 vLLM 服务,直接访问 Windows 机器的 IP 是访问不到的。因为 WSL2 有独立的虚拟网卡,端口不会自动映射到 Windows 外网接口。处理方式是在 PowerShell 里添加端口转发:

netsh interface portproxy add v4tov4 listenport=8000 listenaddress=0.0.0.0 connectport=8000 connectaddress=<WSL2的IP>

WSL2 的 IP 每次重启可能变化,所以需要写脚本动态更新。另外还需要在 Windows 防火墙里放行 8000 端口。这个步骤做完,才能从局域网内其他机器访问。

5.6 缓存与版本冲突

vLLM 升级之后经常出现缓存中旧版本算子库残留。如果你是从低版本升到高版本,建议做法是全新环境重装,而不要只升级 vllm。因为 vLLM 的依赖链很紧,它用到的一些 C++ 扩展和 CUDA kernel 需要与 torch 保持严格一致。你只升了 vllm 但 torch 没动,很可能启动时报出符号缺失、misconfigured 之类的错误。

我习惯用的完整清理命令:

conda create -n vllm2 python=3.10 -y conda activate vllm2 pip install vllm

不推荐在同一环境里反复 update。

5.7 常见错误速查表

症状大概率原因处理方式
nvidia-smi 不存在驱动或工具包未安装更新 Windows 驱动并安装 nvidia 工具
torch.cuda.is_available() 为 Falsetorch 是 CPU 版重装 GPU 版 torch
CUDA error: invalid device function驱动与 CUDA 库版本不匹配清理旧 CUDA,更新驱动
vLLM 启动时 OOM模型或 KV cache 超过显存改用小模型、量化或调低显存利用率
模型加载极慢路径在 /mnt 跨盘软链接或迁移模型到 WSL2 内部
局域网访问不了WSL2 端口未映射配置 portproxy 和防火墙

6. 我在这套环境里长期使用的几个习惯

最后说点操作习惯。我在这套 WSL2 + vLLM 环境里实际跑了几个月,日常开发循环是这样:Windows 上有 VS Code,通过 Remote-SSH 插件连到 WSL2 的同一个发行版里写代码。这样既能用 Windows 侧输入法和浏览器,又能真正在 Linux 环境里执行命令。建议你也创建固定的工作目录,别把一堆实验文件散落在 /root 或 /home 下。

启动服务时,我会用一个 systemd service 或者简单的 nohup 脚本管理,尤其是需要长期挂载的场景。WSL2 默认没有启用 systemd,可以先检查:

ps -p 1 -o comm=

如果输出不是 systemd,按发行版文档启用即可。启用后,vLLM 服务就可以用 systemctl 管理,比裸 nohup 稳很多。WSL2 窗口关闭不会导致 Linux 进程立刻终止,但重启 Windows 后服务还是要靠 systemd 拉起来的。如果只是临时验证,nohup 也够用。

我还习惯设定好.wslconfig里的 swap 值。很多人在 16GB 内存的机器上跑大模型,因为 Windows 和 WSL2 同时抢内存,容易出现 Windows 弹“内存不足”警告。swap 设置成 8GB,系统会更好地缓冲峰值内存压力,但千万别指望 swap 拯救显存不够的问题。

还有一点值得提醒:WSL2 空间滥用问题。虚拟磁盘文件不会因为你删文件就自动瘦身。要回收空间,在 Windows 下以管理员打开 PowerShell:

wsl --shutdown diskpart # 然后选择挂载的 vhdx 文件,执行 compact

如果你实在不想折腾,用 Docker Desktop 的 WSL2 后端里的磁盘工具也可以,但本质上一样。环境跑得久了,磁盘只增不减是个现实问题,需要定期关注。

我个人实际操作下来,最影响体验的不是 vLLM 本身,而是 Windows 和 WSL2 之间那层文件系统边界。把模型、数据集、宿主机代码目录规划好,性能问题会少掉一大半。希望这篇文章能让你少走一点弯路,把时间花在真正有价值的推理调优上。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询