不能只用 uv pip freeze,因其仅快照已装包,不记录间接依赖约束、平台标记及构建依赖,跨平台或版本差异时易导致安装失败或不兼容。

直接用 uv lock + uv pip install -r 是最稳的迁移路径,但只靠 uv pip freeze > requirements.txt 在跨平台或带构建依赖时大概率出错。
为什么不能只用 uv pip freeze
uv pip freeze 本质是“快照当前已安装包”,它不记录间接依赖的精确版本约束、不处理平台标记(比如 win-amd64 vs manylinux)、也不包含构建时需要的 build-system 依赖。一旦目标机器 Python 版本不同、系统架构不同,或者某个包在 PyPI 上删了旧轮子,pip install -r 就会失败或降级到不兼容版本。
- 常见错误现象:
ERROR: Could not find a version that satisfies the requirement torch==2.3.0+cu121(Linux 导出的 CUDA 包在 Windows 上根本不存在) - 真实使用场景:你本地是 Ubuntu 24.04 + Python 3.12,要迁到 Windows Server 2022 + Python 3.12,但
requirements.txt里写的torch没带平台标记 - 关键差异:
uv lock生成的uv.lock是完整依赖图,含所有传递依赖、哈希、平台条件;而freeze只是扁平列表
uv lock 必须配合 --platform 才能跨系统迁移
导出锁文件时,必须显式声明目标平台,否则 UV 默认按当前系统生成——这在 Linux → Windows 或 macOS → Linux 迁移中毫无意义。
- Linux 上导出 Windows 环境:
uv lock --platform win-amd64 --python-version 3.12 - macOS 上导出 Linux 环境:
uv lock --platform manylinux2014-x86_64 --python-version 3.11 - 参数影响:漏掉
--platform会导致锁文件里保留platform_system == "Linux"这类条件,Windows 上解析失败;漏掉--python-version可能引入不支持该 Python 版本的包(如某些pyproject.toml里写了requires-python = ">=3.13") - 验证方式:打开生成的
uv.lock,搜索"platform"字段,确认值与目标一致(如"win-amd64")
离线迁移必须用 uv pip download 预取 wheel
锁文件只是“蓝图”,真正部署时若目标机器没网,得提前把所有 wheel 下载好。UV 的 pip download 会自动按锁文件里的平台和 Python 版本筛选正确二进制包。
- 在联网机器上执行:
uv pip download --locked --platform win-amd64 --python-version 3.12 -d ./wheels - 生成的
./wheels目录可直接拷贝到离线机器,再用uv pip install --find-links ./wheels --no-index -r requirements.txt - 容易踩的坑:不用
--locked会重新解析依赖,可能下载新版 wheel;不加--find-links和--no-index,UV 仍会尝试连 PyPI 导致失败 - 性能提示:下载过程默认并行,
./wheels目录大小通常比pip wheel方案小 20–40%,因为 UV 跳过冗余构建依赖
导入时别跳过 uv venv 创建步骤
即使目标机器已有 Python,也必须用 uv venv 创建新环境,而不是复用全局 Python 或旧虚拟环境。UV 的虚拟环境包含缓存路径、隔离的 site-packages 结构,以及与锁文件绑定的解释器 ABI 标识。
- 正确操作:
uv venv --python 3.12 .venv && source .venv/bin/activate && uv pip install --locked(Linux/macOS) - Windows 对应:
uv venv --python 3.12 .venv && .venv\Scripts\activate.ps1 && uv pip install --locked - 为什么强调
--python:UV 会校验锁文件中声明的 Python 兼容性,如果省略且系统默认 Python 是 3.9,而锁文件要求 3.12,uv pip install --locked会直接报错 - 忽略这点的后果:看似安装成功,但运行时报
ImportError: cannot import name 'xxx' from 'yyy',实际是 ABI 不匹配或扩展模块加载失败
真正麻烦的不是命令本身,而是平台标记、Python 小版本、锁文件哈希三者必须严格对齐——少一个,--locked 就会拒绝安装,而不是静默降级。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











