2026/10/16 7:33:41

WSL2 下安装 vLLM 的完整实战:GPU 直通、CUDA 配置与踩坑指南

WSL2 下安装 vLLM 的完整实战:GPU 直通、CUDA 配置与踩坑指南 很多做深度学习推理的朋友平时主力机是 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需要把默认版本切到 2wsl --set-default-version 2然后把需要 Linux 访问的发行版从 WSL1 迁移到 WSL2wsl --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] memory16GB processors8 swap8GBmemory 是指 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 python3.10 -y conda activate vllmPython 版本我选择 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某组织/小模型名称, dtypefloat16) 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_urlhttp://localhost:8000/v1, api_keyEMPTY ) resp client.chat.completions.create( model某组织/模型名称, messages[ {role: system, content: 你是助手}, {role: user, content: 介绍一下 WSL2 和 vLLM 的关系} ], max_tokens512 ) print(resp.choices[0].message.content)这里 base_url 要写完整到/v1api_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同时观察终端日志里的排队等待时间和吞吐速度。如果大批量请求导致 OOMvLLM 会打印一条明确的显存不足日志并且拒绝排队。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再装 vLLMpip 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 listenport8000 listenaddress0.0.0.0 connectport8000 connectaddressWSL2的IPWSL2 的 IP 每次重启可能变化所以需要写脚本动态更新。另外还需要在 Windows 防火墙里放行 8000 端口。这个步骤做完才能从局域网内其他机器访问。5.6 缓存与版本冲突vLLM 升级之后经常出现缓存中旧版本算子库残留。如果你是从低版本升到高版本建议做法是全新环境重装而不要只升级 vllm。因为 vLLM 的依赖链很紧它用到的一些 C 扩展和 CUDA kernel 需要与 torch 保持严格一致。你只升了 vllm 但 torch 没动很可能启动时报出符号缺失、misconfigured 之类的错误。我习惯用的完整清理命令conda create -n vllm2 python3.10 -y conda activate vllm2 pip install vllm不推荐在同一环境里反复 update。5.7 常见错误速查表症状大概率原因处理方式nvidia-smi 不存在驱动或工具包未安装更新 Windows 驱动并安装 nvidia 工具torch.cuda.is_available() 为 Falsetorch 是 CPU 版重装 GPU 版 torchCUDA 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 下以管理员打开 PowerShellwsl --shutdown diskpart # 然后选择挂载的 vhdx 文件执行 compact如果你实在不想折腾用 Docker Desktop 的 WSL2 后端里的磁盘工具也可以但本质上一样。环境跑得久了磁盘只增不减是个现实问题需要定期关注。我个人实际操作下来最影响体验的不是 vLLM 本身而是 Windows 和 WSL2 之间那层文件系统边界。把模型、数据集、宿主机代码目录规划好性能问题会少掉一大半。希望这篇文章能让你少走一点弯路把时间花在真正有价值的推理调优上。