在 WSL2 里装好 Ubuntu 22.04 之后,很多人最先踩到的坑,就是 pip install torch 时被 error: externally-managed-environment 拦下来。报错原文一般长这样:error: externally-managed-environment,下面还有一句 This environment is externally managed。第一次看到这个提示的人,多半会以为是自己的 WSL2 出了问题,或者 pip 坏了。其实恰恰相反,这是系统在保护自己。
这个报错源自 PEP 668 机制,Debian、Ubuntu 从较新版本开始默认启用了对系统 Python 环境的“外部托管”标记。简单说,就是系统告诉你:不要用 pip 直接往全局 Python 里塞包,否则可能把 apt 依赖的 Python 环境搞坏。这篇文章会从报错原理讲起,教你几种应对方案,然后完整走一遍在 WSL2 + Ubuntu 22.04 下安装 PyTorch 和 vLLM,并跑通一个小模型推理的流程。内容偏实操,适合刚接触 WSL2、想在 Windows 上做深度学习或大模型推理的同学参考。
1. 先说结论:这个报错到底什么来头
1.1 PEP 668 与“系统托管”的真相
error: externally-managed-environment 不是某个软件包的报错,而是 pip 在检查当前 Python 环境时,发现了一个特殊标记文件 /usr/lib/python3.x/EXTERNALLY-MANAGED。只要存在这个文件,pip 就会认为当前解释器由系统包管理器(apt)统一托管,不允许直接用 pip 安装全局包。
这套机制对应的规范叫 PEP 668,原文标题是 “Mark Python base environments as externally managed”,目标很明确:避免 pip 和 apt 混用同一个 Python 环境,防止依赖冲突击穿系统关键包。Linux 发行版里很多核心组件依赖 Python,比如 apt、软件中心、系统初始化脚本,如果你用 pip 强制覆盖了某个系统包的版本,轻则系统工具报错,重则整个 Python 环境崩溃,只能重装系统。
所以当你看到 This environment is externally managed 这句提示时,可以理解为 Python 官方机制在替系统把关。这不是你的 WSL2 坏了,而是你正在触碰一个不被推荐的操作路径。
1.2 为什么 Ubuntu 要“拦”你
很多人不理解:我装 PyTorch 为什么还要被系统管着?其实问题不在 PyTorch,而在于“往哪里装”。
Ubuntu 的系统 Python 分成两类包:一类是 apt 装的,位于 /usr/lib/python3/dist-packages,这类包和系统工具深度绑定;另一类是 pip 装的,位于 /usr/local/lib/python3.x/dist-packages。问题在于,如果你用 pip 把一个包升级成和 apt 不完全兼容的版本,apt 管理的软件可能运行几分钟后就开始报 ImportError。
比如 python3-apt、python3-distutils、python3-gi 这些包,一旦被覆盖,系统自带的 UI 工具、更新管理器、网络管理模块都容易出问题。Ubuntu 启用了 externally-managed 标记之后,等于直接断掉了这条危险的路径,逼着你用虚拟环境或系统包管理器来安装 Python 库。
1.3 WSL2 里更容易踩到,是因为默认环境太“裸”
在 WSL2 的 Ubuntu 22.04 里,刚安装完系统后通常没有 Python 虚拟环境工具,很多人从菜鸟教程里学到的是 pip install xxx,于是直接在全局环境里装。系统报错后,因为不熟悉 PEP 668,上网一搜答案五花八门,最坑的答案是让你删掉 EXTERNALLY-MANAGED 文件,这在很多场景下会埋下隐患。
我的建议是:在 WSL2 里做任何 Python 开发,最好从一开始就养成“先建虚拟环境,再装包”的习惯。这样不仅能绕开 externally-managed-environment,还能隔离项目依赖,避免不同项目之间的包冲突。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备:WSL2 + Ubuntu 22.04 的前置配置
2.1 一键安装 WSL2:从检查虚拟化开始
如果你还没装好 WSL2,先把基础环境搞定。Windows 10(2004 版本以上)和 Windows 11 都支持命令行安装,管理员身份打开 PowerShell,执行:
powershell复制wsl --install
这个命令会自动启用 WSL 功能,安装虚拟机平台,并默认安装 Ubuntu。安装完成后重启系统,再用 wsl --set-default-version 2 把 WSL 版本切到 2,因为 WSL1 不支持 GPU 透传,装 PyTorch 也没法用 GPU。
有一个高频问题:wsl --install 报“无法启动,因为此计算机上未启用虚拟化”。这时需要进 BIOS 开启 Intel VT-x / AMD-V 虚拟化选项。另外如果你电脑上装了 VMware 或 VirtualBox,它们可能和 WSL2 的 Hyper-V 冲突,需要先关闭第三方虚拟化软件,或者调整 Windows 功能配置。
2.2 WSL2 资源限制与镜像网络(.wslconfig)
WSL2 本质是一个轻量虚拟机,但它默认只使用物理内存的 50%,对于一些模型加载场景可能不够用。在 Windows 用户目录下新建一个 .wslconfig 文件,可以自定义资源分配:
ini复制[wsl2]
memory=16GB
processors=4
swap=8GB
localhostForwarding=true
我习惯把内存直接设成物理内存的 80% 左右,比如 32GB 内存的机器给 WSL2 分配 24GB,这样跑 vLLM 的时候不容易爆内存。改完配置后执行 wsl --shutdown 再启动 WSL2 生效。
如果你的 Windows 系统较新,还可以在 .wslconfig 里开启镜像网络模式:
ini复制[wsl2]
networkingMode=mirrored
镜像网络的好处是 WSL2 内的端口和 Windows 完全一致,访问 localhost:8000 不需要额外端口转发,调试 vLLM 的 OpenAI 兼容接口时会省不少事。
2.3 GPU 透传:为什么 nvidia-smi 能直接在 WSL2 里用
进入 WSL2 后,先检查 GPU 是否透传成功:
bash复制nvidia-smi
如果能正常显示显卡信息,说明 WSL2 的 GPU 透传已经生效。WSL2 的 CUDA 支持是微软和 NVIDIA 合作的成果,Windows 上安装的 NVIDIA 驱动本身就是支持 WSL2 的版本,Linux 内核里不需要再装驱动。
注意:nvidia-smi 显示的 CUDA Version 是驱动支持的最高 CUDA 版本,不是系统里已经安装了 CUDA Toolkit。这一点后面安装 PyTorch 时非常重要,很多人就是在这里被误导,跑去装了全套 CUDA Toolkit,结果浪费时间。
3. 破解 externally-managed-environment 的三条路
3.1 推荐做法:venv 虚拟环境隔离
遇到 error: externally-managed-environment,我最推荐的做法是建一个虚拟环境。venv 是 Python 自带的工具,不需要额外安装第三方包管理器。在 WSL2 的 Ubuntu 22.04 里,先确认有没有 venv 模块:
bash复制python3 -m venv --help
如果提示没有该模块,先安装:
bash复制sudo apt update
sudo apt install python3-venv
然后在你的项目目录里创建并激活虚拟环境:
bash复制mkdir ~/llm-project && cd ~/llm-project
python3 -m venv .venv
source .venv/bin/activate
激活后,命令行提示符前面会出现 (.venv)。这时再执行 pip install,所有包都会装进 .venv/lib/python3.10/site-packages,和系统 Python 完全隔离。此时装 PyTorch、vLLM,不会再出现 externally-managed-environment 报错。
venv 的原理其实很简单:它在虚拟环境目录里放了一个独立的 Python 解释器副本(或者软链接),并设置了环境变量 PATH、VIRTUAL_ENV,让 shell 优先使用虚拟环境里的 python 和 pip。这也意味着你随时可以用 deactivate 退出,回到系统 Python。
3.2 特殊场景才用的 --break-system-packages
如果你只是临时装一个小工具,又不想建虚拟环境,pip 会提示你可以用 --break-system-packages 强制安装。它的含义是“我知道这是系统管理的 Python 环境,但我偏要装,出了问题我自己负责”。
我一般只在两种情况下用它:一是在一次性的 Docker 容器里,反正容器销毁了无所谓;二是在明确知道某个包不会和系统包冲突时,比如装一个纯 Python 的 CLI 工具。对于 PyTorch、vLLM 这种依赖树很深的包,我强烈不建议用这个参数装在全局环境里,因为 torch 的依赖会和系统包发生冲突,到时候排查起来非常痛苦。
真要临时用,命令是这样:
bash复制pip install --break-system-packages some-small-package
但请记住,这只是应急方案,不是常规操作。
3.3 备选方案:pipx 与 uv
如果你的目标是安装一个命令行工具,而不是做项目开发,用 pipx 更合适。pipx 会为每个工具创建独立虚拟环境,然后只在系统层面暴露可执行文件,避免全局环境的污染:
bash复制sudo apt install pipx
pipx install some-cli-tool
另外最近比较火的 uv(用 Rust 写的 Python 包管理器)也很值得尝试。它速度非常快,并且会自动处理虚拟环境逻辑。最简单的用法是:
bash复制uv venv
source .venv/bin/activate
uv pip install torch vllm
uv 的好处是安装包速度快一个量级,依赖解析也做得更稳。如果你能从零开始一个项目,用 uv 替代 pip 会省心很多。
4. 安装 PyTorch + CUDA 环境:版本匹配是关键
4.1 先别急着装 CUDA Toolkit
很多教程会让你先到 NVIDIA 官网下载 CUDA Toolkit,但在 WSL2 里这一步通常不是必须的。为什么?因为 PyTorch 的官方安装包(wheel)已经自带了运行时所需的 CUDA 库,你只需要有 NVIDIA 驱动支持即可。你真正需要关注的是驱动支持的 CUDA 版本和 PyTorch wheel 的 CUDA 版本是否匹配。
比如 nvidia-smi 显示 CUDA Version: 12.4,说明驱动支持最高 CUDA 12.4。这时你安装 PyTorch 的 cu121 或 cu124 版本都没问题。如果你去装一个完整的 CUDA Toolkit,反而可能覆盖驱动的某些组件,引发不必要的麻烦。
判断驱动是否支持 CUDA 12.x,直接看 nvidia-smi 右上角的版本号就行。确认办法:
bash复制nvidia-smi | grep "CUDA Version"
4.2 选择 CUDA 版本与安装命令
当前 PyTorch 官方提供的 CUDA 版本主要有 cu118、cu121、cu124、cu126。对绝大多数深度学习场景,我推荐 cu121 或 cu124,因为兼容性好,坑少。如果你用的是 RTX 40 系列新卡,建议直接用 cu124。
创建好虚拟环境后,执行:
bash复制pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu124
如果你的机器没有 NVIDIA GPU,比如在 WSL2 里只做 CPU 推理,那就装 CPU 版本:
bash复制pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
注意:官方源在境外,如果你下载速度很慢,可以加 --proxy 参数,或者使用国内镜像源,但镜像源不一定保证同步所有 CUDA 版本的 wheel,还是建议优先用官方源,下载慢一点没关系,稳定最重要。
4.3 验证 PyTorch 是否真的用上了 GPU
安装完成后,先做一个最小验证,确认 GPU 可用:
bash复制python -c "import torch; print(torch.__version__); print(torch.cuda.is_available()); print(torch.cuda.get_device_name(0))"
如果输出类似:
code复制2.4.0+cu124
True
NVIDIA GeForce RTX 4090 Laptop GPU
说明 PyTorch 已经成功识别的 GPU。如果 torch.cuda.is_available() 返回 False,通常有三种原因:驱动没透传到 WSL2(nvidia-smi 无法显示)、PyTorch 安装成了 CPU 版本、当前 CUDA 版本和驱动不匹配。
小提示:很多人在 WSL2 里第一次运行时,会因为防火墙或驱动服务没启动导致 nvidia-smi 报错。可以试试在 Windows 侧打开一个 PowerShell 执行 wsl --shutdown,然后重新进入 WSL2,大部分驱动识别问题都能解决。
5. 安装 vLLM 并跑通大模型推理
5.1 vLLM 是什么,为什么值得装
vLLM 是一个专门针对大模型推理加速的框架,核心特性是 PagedAttention 连续批处理,显存利用率比传统方案高很多。同样是部署 Qwen2.5-7B,普通 HuggingFace Transformers 推理可能只能同时处理几路请求,vLLM 可以做到几十路还不怎么增加显存开销。
这也是为什么现在做生产级 LLM 服务时,vLLM 几乎成了默认选项。它的 API 兼容 OpenAI 格式,接入现有的翻译、问答、Agent 应用非常方便。
需要注意,vLLM 目前对 NVIDIA GPU 的适配最成熟,对 AMD ROCm 也有一定支持。如果你用的是非 NVIDIA 硬件,比如昇腾等国产加速卡,vLLM 官方仓库默认可能无法直接启动部分模型,需要特定插件或厂商提供的适配方案。这一点在选型时要提前确认。
5.2 安装 vLLM 的依赖注意事项
安装 vLLM 前,我建议先理清依赖顺序。最稳妥的方法是:在虚拟环境里直接 pip install vllm,让 pip 自动解析依赖并安装匹配的 PyTorch 版本。
bash复制pip install vllm
这里有一个很重要的经验:不要先手动安装 PyTorch 再安装 vLLM。因为 vLLM 对 PyTorch 有固定版本要求,如果你先装了最新版 PyTorch,vLLM 安装时可能会自动安装它指定的 PyTorch 版本,覆盖掉你之前的安装,造成版本混乱。
vLLM 比较吃编译环境,如果系统里缺少 ninja、gcc、g++ 等编译工具,安装过程中可能触发本地编译,速度慢且容易失败。在 Ubuntu 上提前装好这些工具:
bash复制sudo apt update
sudo apt install build-essential ninja-build cmake
安装完成后验证:
bash复制python -c "import vllm; print(vllm.__version__)"
如果没报错,说明 vLLM 装好了。
5.3 实际部署 Qwen3-8B 的完整过程
安装 vLLM 后,最直观的验证方式是直接用 vllm serve 命令拉起一个大模型。先确认模型是否已经下载。HuggingFace 官方模型下载很稳定,但国内网络有时不稳定,可以使用指定镜像:
bash复制export HF_ENDPOINT=https://hf-mirror.com
然后启动一个较小规模的模型,比如 Qwen3-8B:
bash复制vllm serve Qwen/Qwen3-8B --gpu-memory-utilization 0.85 --max-model-len 8192 --max-num-seqs 32
参数解释一下:
--gpu-memory-utilization 0.85:允许 vLLM 最多使用 85% 的显存,给显存留出余量,避免 OOM。--max-model-len 8192:设置最大上下文长度,输入加输出总长度不能超过这个值。如果显存够大,可以设成 16384。--max-num-seqs 32:控制一次最多并发处理多少条序列,默认 256,显存不够时调小一点。
启动成功后,终端会打印模型加载信息和监听地址,默认是 0.0.0.0:8000。你可以在另一个终端里用 curl 测试:
bash复制curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen/Qwen3-8B",
"messages": [{"role": "user", "content": "你好,介绍一下你自己"}]
}'
返回的 JSON 里带有 choices 字段,就是模型生成的回答。
如果启动时显存不足,优先检查两点:一是 .wslconfig 给 WSL2 分配的内存是否够大;二是是否用了 --max-model-len 限制了上下文。一个小技巧是先加 --enforce-eager 参数强制使用 eager 模式,跳过 CUDA graph 的捕获过程,能明显减少启动时的显存占用,代价是推理速度略降。
生产环境中,很多人会把 vLLM 打包进 Docker 通过 docker-compose 部署,官方镜像 vllm/vllm-openai 已经包含了运行环境,这样能避免本机 Python 依赖污染。如果你有这方面的需求,可以直接参考官方镜像示例写 docker-compose.yml。
6. 常见问题与排查实录
6.1 高频报错速查表
整理了一份我在实际部署中遇到的典型问题,按现象、原因、解决思路列出来,方便你对照排查。
| 现象 | 原因 | 解决思路 |
|---|---|---|
error: externally-managed-environment |
系统 Python 启用了 PEP 668 | 创建 venv 虚拟环境,或临时用 --break-system-packages |
pip install torch 下载慢 |
官方源在境外 | 使用代理,或等待官方源镜像同步后使用国内镜像 |
torch.cuda.is_available() 返回 False |
装的是 CPU 版 / 驱动未透传 / CUDA 版本不匹配 | 检查 nvidia-smi,重新安装对应 CUDA 版本的 torch |
nvidia-smi 提示找不到设备 |
Windows 驱动未安装或 WSL2 未重启 | 安装最新 NVIDIA 驱动,执行 wsl --shutdown 重进 |
| vLLM 安装时编译报错 | 缺少编译工具或内存不足 | 安装 build-essential、ninja、cmake |
| vLLM 启动时报 CUDA graph 失败 | 显存不足或驱动兼容问题 | 加 --enforce-eager,调低 --gpu-memory-utilization |
| vLLM 启动后在 Windows 访问 localhost 失败 | WSL2 端口转发异常 | 开启镜像网络模式,或用 wsl --shutdown 重启 WSL2 |
| 模型生成结果乱码 | 模型 tokenizer 未正确加载 | 重新下载模型文件,检查磁盘空间 |
| 昇腾等非 NVIDIA 硬件上 vLLM 启动失败 | vLLM 默认适配 NVIDIA/AMD | 咨询硬件厂商的适配方案,或使用专用推理引擎 |
6.2 我踩过的几个坑与补救办法
第一个坑是直接在系统 Python 里装了 PyTorch,因为当时图省事用了 --break-system-packages,结果后来系统 update 时提示 python3-apt 出现了依赖问题,修复花了不少时间。从那以后,我在 WSL2 里所有项目都强制用 venv,不会再碰系统 Python。
第二个坑是 vLLM 和 PyTorch 的版本打架。我一开始在虚拟环境里先装了 PyTorch 2.3,然后又装 vLLM,结果 vLLM 把 PyTorch 换成了 2.2,导致相关环境变量冲突,启动时报了一堆堆栈错误。现在我都是直接 pip install vllm,让它自己决定 PyTorch 版本,再按需安装 torchvision 等额外包。
第三个坑是 WSL2 内存不足。有一次启动 Qwen3-32B 的 INT4 量化版本,模型加载到一半进程直接被 kill 掉,排查了半天发现是 .wslconfig 没配置,WSL2 默认只给物理内存的一半,32GB 的机器只有 16GB 可用,加载大模型当然不够。调整内存配置后问题就解决了。
第四个坑是关于 WSL2 的 GUI 显示问题。如果你在 WSL2 里用 gedit 等图形编辑器偶尔无法显示,这并不是环境配置失败,WSL2 的 GUI 支持依赖 Windows 的 WSLg,更新系统或重新启动 WSL 服务后基本都能恢复。更省心的方法是直接用 Windows Terminal 加 VS Code 的 WSL 插件。
我在实际部署中比较固定的顺序是:先建 venv,再装 vLLM,最后按需补 torch 相关增强包,这样能最大程度避免版本冲突。WSL2 环境里跑大模型,最值得你提前确认的其实不是 pip 报错,而是内存配额和 GPU 透传有没有打通,这两点确定以后,剩下的就是按文章里的命令一步步执行。希望这篇实践总结能帮你少踩几个坑。
