uv 深入指南:重新理解 Python 的包管理、依赖解析与项目工程化

对于 Python 的开发者来说,uv 并不只是一个"更快的 pip"。它实际上正在重新定义 Python 项目的依赖管理、虚拟环境管理、Python 版本管理、命令行工具管理以及项目构建流程。

一、为什么 Python 需要 uv?

Python 的生态非常成熟,但长期以来,项目工程化实际上是由多个工具拼接完成的:

objectivec 复制代码
Python
 ├── pyenv / conda       → Python 版本管理
 ├── venv / virtualenv   → 虚拟环境
 ├── pip                 → 包安装
 ├── pip-tools           → 依赖锁定
 ├── pipx                → CLI 工具隔离
 ├── Poetry / PDM        → 项目依赖管理
 ├── setuptools          → 包构建
 └── twine               → 包发布

这种工具链并不是不能使用,而是存在明显的问题:

  1. 工具之间职责分散;
  2. 不同工具之间存在配置重复;
  3. Python 版本、虚拟环境和依赖之间缺乏统一管理;
  4. requirements.txt 对复杂项目的表达能力有限;
  5. pip 本身并不是完整的项目管理工具;
  6. 依赖解析和安装速度长期是 Python 生态中的痛点。

uv 的出现,核心就是试图把这些能力统一起来。

官方将 uv 定义为:

An extremely fast Python package and project manager, written in Rust.(一个用Rust编写的速度极快的Python包和项目管理工具。)

也就是说,uv 的定位并不是单纯替代 pip,而是一个完整的 Python package and project manager(Python 包与项目管理器) 。官方甚至将它定位为可以覆盖 pippip-toolspipxpoetrypyenvtwinevirtualenv 等工具能力的统一工具。(GitHub)


二、uv 到底是什么?

uv 是由 Astral 开发的 Python 工具,使用 Rust 实现。

Astral 同时也是 Ruff、ty 等 Python 工具的开发团队。

如果从功能层次来看,可以把 uv 理解成下面这个结构:

csharp 复制代码
                         uv
                          │
        ┌─────────────────┼──────────────────┐
        │                 │                  │
   Python 管理        项目管理           工具管理
        │                 │                  │
 uv python install   uv init            uvx
 uv python pin       uv add             uv tool
 uv python list      uv remove
                     uv lock
                     uv sync
                     uv run
                     uv build
                     uv publish
        │                 │
        └────────────┬────┘
                     │
                 pip 接口
                     │
               uv pip install
               uv pip compile
               uv pip sync
               uv pip check

因此,uv 最值得理解的不是某个命令,而是它背后的统一项目模型


三、uv 与 pip 最大的区别

很多开发者第一次接触 uv,会把它理解成:

复制代码
pip install requests

换成:

复制代码
uv pip install requests

这样理解只能看到 uv 的一小部分。

uv 实际上存在两套接口:

erlang 复制代码
uv pip ...

以及:

erlang 复制代码
uv ...

前者是 pip-compatible interface(兼容 pip 工作流的接口)

后者是 uv 原生的 project interface(项目管理接口)

例如:

复制代码
uv pip install requests

和:

csharp 复制代码
uv add requests

虽然最终都可能安装 requests,但它们表达的语义完全不同。

3.1 uv pip

它更接近传统 Python:

sql 复制代码
uv venv

uv pip install fastapi
uv pip install pydantic

uv pip freeze
uv pip list
uv pip check

适用于:

  • 传统项目;
  • 已经存在 requirements.txt
  • Docker 构建;
  • 临时虚拟环境;
  • 需要兼容 pip 工作流的项目。

3.2 原生 uv 项目

推荐的新项目则应该使用:

csharp 复制代码
uv init
uv add fastapi
uv add pydantic
uv run python main.py

这里的重点变化是:

依赖不再只是"安装到当前环境",而是成为项目声明的一部分。

最终依赖会进入:

复制代码
pyproject.toml

同时生成:

csharp 复制代码
uv.lock

因此:

复制代码
pip install

更像是:

修改一个环境。

而:

csharp 复制代码
uv add

更像是:

修改一个项目。

这是理解 uv 的第一个关键。


四、uv 的核心项目模型

一个典型的 uv 项目:

csharp 复制代码
my-project/
├── .git/
├── .gitignore
├── .python-version
├── .venv/
├── pyproject.toml
├── uv.lock
├── README.md
└── src/
    └── my_project/
        └── __init__.py

其中几个文件分别承担不同职责。

文件 作用
pyproject.toml 项目元数据与依赖声明
uv.lock 精确依赖解析结果
.python-version 项目 Python 版本选择
.venv 项目虚拟环境
src/ 项目源代码

uv 官方推荐将 uv.lock 纳入版本控制,因为它保存的是项目依赖的精确解析结果。(Astral 文档)


五、创建第一个 uv 项目

直接:

csharp 复制代码
uv init my-project

进入:

bash 复制代码
cd my-project

然后:

arduino 复制代码
uv run python

uv 会自动处理项目环境。

也可以明确创建:

bash 复制代码
uv sync

此时通常会得到:

csharp 复制代码
my-project/
├── .venv/
├── pyproject.toml
└── uv.lock

这和传统流程:

复制代码
python -m venv .venv

.venv\Scripts\activate

pip install -r requirements.txt

相比,少了大量手工步骤。


六、pyproject.toml:uv 项目的核心配置

一个典型配置:

ini 复制代码
[project]
name = "my-project"
version = "0.1.0"
description = "My Python project"
requires-python = ">=3.12"
dependencies = [
    "fastapi>=0.115",
    "pydantic>=2.10",
    "httpx>=0.28",
]

然后执行:

bash 复制代码
uv sync

uv 会:

  1. 读取项目声明;
  2. 解析依赖;
  3. 生成或更新 uv.lock
  4. 创建 .venv
  5. 安装解析后的依赖。

七、uv add 为什么比 pip install 更重要?

传统项目:

复制代码
pip install fastapi

安装成功后,你还需要:

复制代码
pip freeze > requirements.txt

然后手工维护依赖。

uv:

csharp 复制代码
uv add fastapi

会直接修改:

ini 复制代码
[project]
dependencies = [
    "fastapi>=..."
]

同时更新:

csharp 复制代码
uv.lock

并同步项目环境。

所以推荐的工作方式是:

csharp 复制代码
uv add fastapi
uv add sqlalchemy
uv add pydantic

而不是:

复制代码
uv pip install fastapi
uv pip install sqlalchemy
uv pip install pydantic

如果你正在维护一个标准 uv 项目,后者实际上是在绕开 uv 的项目模型。


八、uv.lock:uv 最核心的能力之一

如果说:

复制代码
pyproject.toml

解决的是:

我需要什么?

那么:

csharp 复制代码
uv.lock

解决的是:

到底安装什么?

例如:

ini 复制代码
dependencies = [
    "fastapi>=0.115",
]

并不意味着每次安装都一定得到同一个 FastAPI 版本。

因为 FastAPI 还会依赖:

erlang 复制代码
starlette
pydantic
typing-extensions
...

这些依赖还有自己的依赖。

最终形成:

复制代码
fastapi
├── starlette
│   └── anyio
├── pydantic
│   ├── annotated-types
│   └── pydantic-core
└── typing-extensions

uv resolver(依赖解析器)会把整个依赖图进行解析。

最终把结果保存到:

csharp 复制代码
uv.lock

九、uv.lock 与 requirements.txt 有什么区别?

传统:

复制代码
requirements.txt

可能是:

ini 复制代码
fastapi==0.115.6
pydantic==2.10.5
starlette==0.41.3
...

它更像一个安装清单

uv.lock 是 uv 项目的解析结果数据库

它可以表达:

  • 精确版本;
  • 依赖关系;
  • Python 条件;
  • 操作系统条件;
  • CPU 架构;
  • package source(包来源);
  • Git dependency(Git 依赖);
  • URL dependency;
  • extras;
  • dependency groups;
  • workspace 信息等。

更重要的是:

uv.lock 是 universal lockfile(通用锁文件)。

它能够在同一个锁文件中描述不同平台、架构和 Python 版本下的依赖解析结果。(Astral 文档)


十、什么是 Universal Resolution(通用依赖解析)?

这是 uv 非常重要、但很多入门文章不会讲清楚的地方。

假设你的项目支持:

ini 复制代码
requires-python = ">=3.10"

同时需要:

复制代码
Windows
Linux
macOS

某个依赖可能存在:

css 复制代码
Linux → A
Windows → B
macOS → C

传统 requirements 文件通常需要针对不同环境生成不同结果。

而 uv 的 universal resolution(通用解析)会在一个 lockfile 中表达这些条件。

例如概念上可能形成:

ini 复制代码
package-x==1.0 ; sys_platform == "linux"
package-x==2.0 ; sys_platform == "win32"

因此:

csharp 复制代码
一个项目
   │
   └── 一个 uv.lock
          │
          ├── Linux
          ├── Windows
          ├── macOS
          ├── x86_64
          ├── ARM64
          └── 不同 Python 版本

都可以由同一个锁文件描述。

uv 官方将其称为 universal resolution(通用依赖解析) 。(Astral 文档)


十一、uv 为什么这么快?

uv 的性能并不是简单因为:

Rust 比 Python 快。

这只是其中一部分。

它的速度优势来自多个层面。

11.1 Rust 实现

uv 的核心实现使用 Rust。

相比传统 Python 工具链,减少了解释器层面的开销。


11.2 高度并发

依赖下载、元数据获取、安装等过程可以充分利用并发。


11.3 全局缓存

uv 使用 aggressive caching(积极缓存)。

例如:

css 复制代码
         Global Cache
              │
       ┌──────┼──────┐
       │      │      │
    Project A Project B Project C
       │      │      │
       └──────┼──────┘
              │
          Shared Packages

同一个依赖不需要在每个项目里重复下载。

官方文档特别强调,uv 的缓存目录最好与 Python 环境位于同一文件系统,否则无法充分利用链接机制,可能退化为复制操作。(Astral 文档)


十二、uv 的缓存机制

可以查看缓存目录:

bash 复制代码
uv cache dir

清理缓存:

复制代码
uv cache clean

清理无用缓存:

复制代码
uv cache prune

如果遇到:

css 复制代码
Failed to hardlink files
Falling back to full copy

这类提示,本质上通常意味着:

go 复制代码
cache
  ↓
无法进行 hardlink
  ↓
fallback 到 copy
  ↓
性能下降

特别是在:

  • Windows;
  • Docker;
  • 跨文件系统;
  • 网络文件系统;

中更容易遇到。

因此,uv 的缓存并不是简单的"下载缓存",而是其性能架构的一部分。


十三、uv run:推荐的项目运行方式

传统 Python:

bash 复制代码
source .venv/bin/activate

python main.py

uv:

arduino 复制代码
uv run python main.py

FastAPI:

arduino 复制代码
uv run uvicorn app.main:app

Pytest:

arduino 复制代码
uv run pytest

Ruff:

arduino 复制代码
uv run ruff check .

它的一个重要特点是:

uv run 会在运行命令前检查 lockfile 和项目环境是否需要更新。

因此:

arduino 复制代码
uv run pytest

并不只是:

复制代码
python pytest

而更接近:

csharp 复制代码
检查 pyproject.toml
        ↓
检查 uv.lock
        ↓
检查 .venv
        ↓
同步环境
        ↓
执行 pytest

官方文档明确说明,uv run 会确保命令运行在项目所需的锁定依赖环境中。(Astral 文档)


十四、uv sync 到底做什么?

bash 复制代码
uv sync

可以理解成:

根据项目声明和 lockfile,把项目环境同步到期望状态。

例如:

bash 复制代码
pyproject.toml
       ↓
    uv.lock
       ↓
     uv sync
       ↓
     .venv

因此:

csharp 复制代码
uv add

解决:

修改项目依赖。

而:

bash 复制代码
uv sync

解决:

让环境符合项目依赖。


十五、uv lockuv syncuv run 的区别

这是实际开发中非常容易混淆的三个命令。

命令 核心职责
uv lock 更新依赖解析结果
uv sync 将环境同步到 lockfile
uv run 同步后执行命令

可以理解成:

csharp 复制代码
pyproject.toml
       │
       │ uv lock
       ↓
   uv.lock
       │
       │ uv sync
       ↓
     .venv
       │
       │ uv run
       ↓
   application

十六、--locked--frozen

CI/CD 中非常重要。

--locked

arduino 复制代码
uv run --locked pytest

含义是:

不允许更新 lockfile。

如果:

csharp 复制代码
pyproject.toml
      ≠
uv.lock

就直接失败。

适合 CI。


--frozen

arduino 复制代码
uv run --frozen pytest

更严格:

直接把已有 uv.lock 当作唯一事实来源,不检查它是否需要更新。

如果没有 uv.lock,直接失败。

因此 CI 中经常可以看到类似:

css 复制代码
uv sync --locked
uv run --locked pytest

或者在完全受控的构建流程中使用 --frozen

官方 CLI 对两者的语义有明确区分。(Astral 文档)


十七、开发依赖:dependency groups

传统项目通常:

复制代码
requirements.txt
requirements-dev.txt

uv 推荐:

ini 复制代码
[dependency-groups]
dev = [
    "pytest",
    "ruff",
    "mypy",
]

然后:

sql 复制代码
uv add --dev pytest

等价于:

csharp 复制代码
uv add --group dev pytest

也可以创建更多组:

ini 复制代码
[dependency-groups]
dev = [
    "pytest",
]

lint = [
    "ruff",
]

docs = [
    "mkdocs",
]

安装:

bash 复制代码
uv sync --group docs

全部:

bash 复制代码
uv sync --all-groups

uv 会对 dependency groups 一起进行依赖解析,因此不同 group 之间如果存在不可解决的版本冲突,lock 阶段就会失败。(Astral 文档)


十八、为什么 dependency groups 比 requirements-dev.txt 更好?

假设:

复制代码
requirements.txt
requirements-dev.txt
requirements-test.txt
requirements-docs.txt

每个文件都可能存在重复依赖:

复制代码
pytest
ruff
pydantic

而 uv:

ini 复制代码
[project]
dependencies = [
    "fastapi",
]

[dependency-groups]
dev = [
    "ruff",
]

test = [
    "pytest",
]

docs = [
    "mkdocs",
]

这些依赖最终可以进入同一个:

csharp 复制代码
uv.lock

因此:

bash 复制代码
一个项目
   │
   ├── production dependencies
   ├── dev dependencies
   ├── test dependencies
   └── docs dependencies
             │
             ↓
          uv.lock

这是大型项目管理上的重要优势。


十九、可选依赖 extras

如果你的项目是一个需要发布的 Python package,可以使用:

ini 复制代码
[project.optional-dependencies]

postgres = [
    "asyncpg",
]

redis = [
    "redis",
]

all = [
    "asyncpg",
    "redis",
]

然后:

bash 复制代码
uv sync --extra postgres

或者:

bash 复制代码
uv sync --all-extras

这里需要区分:

bash 复制代码
dependency groups

和:

arduino 复制代码
optional dependencies / extras

一般可以理解为:

bash 复制代码
dependency groups
→ 项目开发环境组织方式

extras
→ package 对外提供的可选功能

二十、Python 版本管理

这是 uv 与 pip 最大的能力差异之一。

uv 不仅管理 package,还可以管理 Python 本身。

例如:

复制代码
uv python install 3.12

查看:

复制代码
uv python list

安装多个版本:

复制代码
uv python install 3.11 3.12 3.13

指定项目:

复制代码
uv python pin 3.12

会生成:

复制代码
.python-version

例如:

复制代码
3.12

之后项目中的 uv 命令就可以根据这个版本工作。

官方当前支持管理 CPython、PyPy、Pyodide 等实现,并能够根据需要自动获取 Python。(GitHub)


二十一、.python-versionrequires-python

这是两个经常被混淆的概念。

例如:

ini 复制代码
[project]
requires-python = ">=3.11,<3.14"

表达的是:

这个项目支持哪些 Python 版本。

而:

复制代码
.python-version

表达的是:

当前开发环境默认使用哪个 Python 版本。

因此:

markdown 复制代码
requires-python
    ↓
兼容范围

.python-version
    ↓
当前项目默认解释器

例如:

ini 复制代码
requires-python = ">=3.11,<3.14"

同时:

复制代码
.python-version
3.12

完全合理。


二十二、uvx:Python CLI 工具的新方式

以前安装 Ruff:

复制代码
pip install ruff

然后:

sql 复制代码
ruff check .

如果只是临时使用某个工具,就会产生一个问题:

为什么为了运行一个 CLI 工具,要把它安装到当前环境?

uv 提供:

复制代码
uvx ruff

它实际上等价于:

arduino 复制代码
uv tool run ruff

uv 会为工具创建隔离环境。

因此:

复制代码
uvx ruff
uvx black
uvx mypy

不会污染你的项目环境。

官方建议,对于很多"一次性执行"的 Python CLI 工具,uvx 往往比永久安装更加合适。(GitHub)


二十三、uv tool install

如果你需要长期使用某个 CLI:

复制代码
uv tool install ruff

它会安装到独立的工具环境,但将命令暴露到 PATH。

因此:

markdown 复制代码
项目依赖
    ↓
  uv add

临时 CLI
    ↓
   uvx

长期 CLI
    ↓
uv tool install

这是非常清晰的职责划分。


二十四、uv 支持 PEP 723:单文件 Python 应用

uv 还有一个非常有意思的能力:

给一个 .py 文件声明自己的依赖。

例如:

python 复制代码
# /// script
# requires-python = ">=3.12"
# dependencies = [
#   "requests",
#   "rich",
# ]
# ///

import requests
from rich import print

print(requests.get("https://example.com").status_code)

然后:

arduino 复制代码
uv run example.py

uv 会根据脚本中的 metadata(元数据)创建隔离环境并安装依赖。

这特别适合:

  • 运维脚本;
  • 数据处理脚本;
  • 自动化脚本;
  • 临时工具;
  • AI 实验代码。

官方文档将这一能力建立在 PEP 723 inline script metadata(内联脚本依赖元数据)之上。(Astral 文档)


二十五、uv pip:传统项目迁移的桥梁

如果你暂时不想修改现有项目:

复制代码
requirements.txt

完全可以:

复制代码
uv venv

uv pip install -r requirements.txt

甚至:

python 复制代码
uv pip compile requirements.in

以及:

bash 复制代码
uv pip sync requirements.txt

因此 uv 并不要求你"一次性重构整个项目"。

可以采用:

csharp 复制代码
旧项目
  │
  ├── pip
  ↓
uv pip
  │
  ↓
pyproject.toml
  │
  ↓
uv.lock
  │
  ↓
完整 uv project

官方也专门提供了从 pip 项目迁移到 uv project 的迁移路径。(Astral 文档)


二十六、uv pip compile

如果你的团队仍然依赖:

复制代码
requirements.in

可以:

css 复制代码
uv pip compile requirements.in \
    --output-file requirements.txt

它类似于:

python 复制代码
pip-tools / pip-compile

但底层使用 uv 的 resolver(依赖解析器)。

还可以:

bash 复制代码
uv pip sync requirements.txt

将环境严格同步到 requirements 文件。

因此对于旧项目:

bash 复制代码
requirements.in
       ↓
uv pip compile
       ↓
requirements.txt
       ↓
uv pip sync
       ↓
.venv

是一个非常实用的迁移方案。(Astral 文档)


二十七、uv 的依赖解析能力

对于资深 Python 开发者来说,这可能比 CLI 更值得关注。

uv 的 resolver 不只是:

复制代码
找到一个能安装的版本

而是对整个依赖图进行统一解析。

例如:

css 复制代码
A
├── C >= 1,<3
│
B
└── C >= 2,<4

那么 resolver 需要找到:

复制代码
C >=2,<3

如果:

css 复制代码
A → C <2
B → C >=2

就无法解决。

uv 会报告:

yaml 复制代码
No solution found

而不是简单地把某个版本装进去。


二十八、Dependency Overrides

真实项目中经常遇到:

css 复制代码
A → C <2
B → C >=2

但你经过测试后发现:

A 实际上也可以使用 C 2.x。

这时候可以使用 dependency override(依赖覆盖)。

例如:

ini 复制代码
[tool.uv]
override-dependencies = [
    "C>=2",
]

但这应该谨慎使用。

因为:

override 本质上是在告诉 resolver:忽略原始包声明中的某些约束。

如果上游包真的不兼容新版本,那么:

复制代码
resolver 成功
≠
程序运行正确

因此 override 应该被视为最后手段,而不是解决依赖冲突的常规方式。(Astral 文档)


二十九、Constraint 与 Override 的区别

这是高级依赖管理中非常重要的一组概念。

Constraint(约束)

sql 复制代码
constraint

是在缩小候选范围。

例如:

shell 复制代码
C>=2,<3

它不会主动把 C 加入项目,只是在 C 已经出现时限制版本。


Override

arduino 复制代码
override

则是在告诉 resolver:

忽略原始依赖声明,按照我的规则解析。

所以:

arduino 复制代码
constraint
→ 缩小范围

override
→ 改写约束

两者不要混用。


三十、Package Index:官方源、私有源与多源

企业项目通常不会只使用 PyPI。

例如:

diff 复制代码
PyPI
+
公司内部 PyPI
+
PyTorch index

uv 支持配置多个 package index(包索引)。

例如:

ini 复制代码
[[tool.uv.index]]
name = "pytorch"
url = "https://download.pytorch.org/whl/cpu"

然后:

ini 复制代码
[tool.uv.sources]
torch = { index = "pytorch" }

这样就可以让不同依赖从不同来源解析。

官方文档支持配置多个 index,并定义它们的优先顺序。(GitHub)

这对于:

  • PyTorch;
  • CUDA;
  • 企业私有包;
  • 内部 SDK;
  • 镜像仓库;

尤其重要。


三十一、Git 依赖

uv 支持直接:

csharp 复制代码
uv add git+https://github.com/psf/requests

也可以在:

ini 复制代码
[tool.uv.sources]
my-package = { git = "https://github.com/example/my-package" }

中定义。

这对于内部组件、尚未发布到 PyPI 的 package 很有价值。

同时 uv 会对 Git dependency(Git 依赖)的解析结果进行缓存,并能够在编译依赖时固定到具体 commit。(Astral 文档)


三十二、Path Dependency

大型 Python 项目经常存在:

markdown 复制代码
project/
├── app/
└── libs/
    └── common/

可以使用:

ini 复制代码
[tool.uv.sources]
common = { path = "./libs/common" }

开发过程中还可以使用 editable:

ini 复制代码
[tool.uv.sources]
common = { path = "./libs/common", editable = true }

这样非常适合:

复制代码
主应用
  ↓
内部 Python SDK
  ↓
公共工具库

这种多包开发模式。


三十三、Workspace:大型 Python 仓库的解决方案

如果项目越来越大:

markdown 复制代码
repo/
├── services/
│   ├── api/
│   ├── worker/
│   └── scheduler/
│
└── libs/
    ├── common/
    └── storage/

你可能不希望每个 package 都完全独立。

uv 提供:

复制代码
workspace

这个概念来自 Rust Cargo。

一个 workspace 可以:

go 复制代码
package A
package B
package C
       │
       ↓
   一个 uv.lock

每个 package 有自己的:

复制代码
pyproject.toml

但 workspace 共享:

csharp 复制代码
uv.lock

因此可以统一管理大型 monorepo(单仓多项目)。(Astral 文档)


三十四、什么时候应该使用 Workspace?

适合:

go 复制代码
Monorepo
大型 Python 平台
多个内部 SDK
多个相互依赖的 Python package

例如:

javascript 复制代码
document-platform/
├── services/
│   ├── api/
│   └── parser/
│
├── packages/
│   ├── common/
│   ├── storage/
│   └── client/
│
└── pyproject.toml

可以将其组织成 workspace。

但是 workspace 并不是越早使用越好。

如果几个 package:

  • 需要完全独立的 Python 版本;
  • 依赖版本存在冲突;
  • 希望完全独立的虚拟环境;

那么 path dependency 可能更合适。

官方也明确指出,存在冲突需求或独立环境需求时,workspace 并不一定是最佳选择。(Astral 文档)


三十五、uv build

uv 不只是环境管理工具。

还可以:

复制代码
uv build

生成:

复制代码
dist/
├── xxx.tar.gz
└── xxx.whl

也就是:

复制代码
sdist
wheel

然后:

复制代码
uv publish

发布到 package index。

官方文档目前将 uv builduv publish 都作为项目打包与发布能力的一部分。(GitHub)

因此:

csharp 复制代码
开发
 ↓
uv add
 ↓
uv lock
 ↓
uv test
 ↓
uv build
 ↓
uv publish

已经可以形成比较完整的 Python package 生命周期。


三十六、uv 与 Poetry 的区别

很多开发者会问:

uv 是不是另一个 Poetry?

从项目管理角度看,两者确实存在明显重叠。

但理念不同。

可以粗略理解:

复制代码
Poetry
→ Python project manager

uv
→ Python ecosystem manager(Python 生态系统管理器)

uv 更强调:

diff 复制代码
Python
+ package
+ project
+ environment
+ tools
+ scripts
+ workspace
+ build

并且提供:

复制代码
uv pip

作为传统工作流的兼容入口。

因此 uv 的迁移成本通常比较低。


三十七、uv 与 conda 的区别

conda 不只是 Python package manager。

它实际上管理:

复制代码
Python
C/C++
系统级依赖
二进制库
科学计算环境

因此:

复制代码
conda

在科学计算领域仍然有自己的价值。

uv 的核心目标则更加聚焦:

diff 复制代码
Python runtime
+
Python packages
+
Python projects

对于:

objectivec 复制代码
FastAPI
Django
LangChain
AI Agent
Web backend
CLI
普通 Python 服务

uv 通常更加轻量。


三十八、uv 与 pyenv 的区别

传统:

go 复制代码
pyenv
  ↓
管理 Python 版本

venv
  ↓
创建虚拟环境

pip
  ↓
安装 package

uv 可以把这些能力整合:

markdown 复制代码
uv python install
       ↓
Python

uv venv
       ↓
Virtual Environment

uv add
       ↓
Dependencies

因此不再必须维护:

复制代码
pyenv + venv + pip

这样一套工具组合。


三十九、uv 与 pipx 的区别

传统:

复制代码
pipx install ruff

uv:

复制代码
uv tool install ruff

临时运行:

复制代码
uvx ruff

所以:

objectivec 复制代码
pipx
  ↓
隔离 CLI 工具

uv tool
  ↓
隔离 CLI 工具

uvx
  ↓
临时执行 CLI 工具

四十、uv 与 Docker

uv 非常适合现代 Python Docker 构建。

例如:

bash 复制代码
FROM python:3.12-slim

COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

WORKDIR /app

COPY pyproject.toml uv.lock ./

RUN uv sync --locked --no-install-project

COPY . .

RUN uv sync --locked

CMD ["uv", "run", "python", "main.py"]

核心思想是:

bash 复制代码
先复制依赖描述
        ↓
uv sync
        ↓
Docker cache
        ↓
再复制源代码

这样修改 Python 源代码时,不必每次重新安装所有依赖。

对于 CI/CD,还可以进一步使用:

bash 复制代码
uv sync --locked

确保构建过程不会偷偷修改锁文件。


四十一、企业项目中推荐的目录结构

对于一个中大型 Python 服务,我更推荐:

css 复制代码
my-service/
├── .github/
│   └── workflows/
├── src/
│   └── my_service/
│       ├── api/
│       ├── core/
│       ├── models/
│       ├── services/
│       └── main.py
├── tests/
├── scripts/
├── pyproject.toml
├── uv.lock
├── .python-version
├── .gitignore
└── README.md

pyproject.toml

ini 复制代码
[project]
name = "my-service"
version = "0.1.0"
requires-python = ">=3.12,<3.14"
dependencies = [
    "fastapi",
    "pydantic",
    "sqlalchemy",
]

[dependency-groups]
dev = [
    "pytest",
    "ruff",
    "mypy",
]

[build-system]
requires = ["uv_build>=0.12,<0.13"]
build-backend = "uv_build"

然后:

bash 复制代码
uv sync

开发:

arduino 复制代码
uv run pytest
uv run ruff check .
uv run mypy src

运行:

arduino 复制代码
uv run python -m my_service

四十二、uv 常用命令速查

Python 管理

arduino 复制代码
uv python list
uv python install 3.12
uv python pin 3.12
uv python find

项目

csharp 复制代码
uv init
uv add fastapi
uv remove fastapi
uv sync
uv lock
uv run
uv tree

开发依赖

sql 复制代码
uv add --dev pytest
uv add --group lint ruff

uv sync --all-groups
uv sync --no-default-groups

虚拟环境

css 复制代码
uv venv
uv venv --python 3.12

pip 兼容接口

bash 复制代码
uv pip install
uv pip uninstall
uv pip list
uv pip freeze
uv pip check
uv pip compile
uv pip sync

工具

复制代码
uvx ruff
uv tool install ruff
uv tool list
uv tool uninstall ruff

构建发布

复制代码
uv build
uv publish

缓存

bash 复制代码
uv cache dir
uv cache clean
uv cache prune

四十三、传统项目迁移到 uv 的推荐路径

不要直接把大型生产项目一次性重构。

推荐分阶段。

第一阶段:只替换 pip

原来:

复制代码
python -m venv .venv
pip install -r requirements.txt

改成:

复制代码
uv venv
uv pip install -r requirements.txt

先验证:

复制代码
应用
测试
CI
Docker

都没有问题。


第二阶段:引入 pyproject.toml

创建:

csharp 复制代码
uv init

然后迁移:

csharp 复制代码
uv add -r requirements.txt

将依赖转移到:

ini 复制代码
[project]
dependencies = [...]

第三阶段:使用 uv.lock

执行:

csharp 复制代码
uv lock

提交:

csharp 复制代码
uv.lock

到 Git。


第四阶段:统一开发命令

把:

erlang 复制代码
python -m pytest
python -m uvicorn ...
ruff ...

逐渐统一为:

arduino 复制代码
uv run pytest
uv run uvicorn ...
uv run ruff ...

第五阶段:CI/CD

将:

erlang 复制代码
pip install ...

替换成:

bash 复制代码
uv sync --locked

这样 CI 环境和开发环境都基于:

csharp 复制代码
pyproject.toml
+
uv.lock

四十四、生产项目应该提交哪些文件?

通常:

csharp 复制代码
提交 Git:

pyproject.toml
uv.lock
.python-version

通常不提交:

复制代码
.venv/

例如:

markdown 复制代码
.venv/
__pycache__/
*.pyc

uv.lock.python-version 是否提交,需要结合项目类型和团队策略,但对于应用项目,我通常建议:

csharp 复制代码
uv.lock       → 提交
.python-version → 提交
.venv         → 不提交

这样开发人员、CI 和部署环境都可以得到一致的依赖基线。


四十五、uv.lock 要不要手工修改?

不建议。

官方明确将 uv.lock 定义为由 uv 管理的 lockfile。

因此:

csharp 复制代码
不要:

vim uv.lock

而应该:

csharp 复制代码
uv add xxx
uv remove xxx
uv lock

让 uv 修改它。


四十六、生产环境如何保证可复现?

推荐:

csharp 复制代码
开发者
   ↓
pyproject.toml
   ↓
uv lock
   ↓
uv.lock
   ↓
Git
   ↓
CI
   ↓
uv sync --locked
   ↓
Docker
   ↓
Production

这里最重要的是:

bash 复制代码
uv sync --locked

而不是:

bash 复制代码
uv sync

因为生产环境应该避免:

构建时重新解析依赖。

否则:

css 复制代码
今天构建
→ A 1.2

一个月后构建
→ A 1.3

就可能出现环境漂移。


四十七、AI 项目为什么特别适合 uv?

对于现在的 Python AI 项目:

复制代码
LangChain
LangGraph
FastAPI
Pydantic
OpenAI SDK
Anthropic SDK
FAISS
Chroma
Transformers
PyTorch

依赖关系往往非常复杂。

例如:

复制代码
LangGraph
  ↓
LangChain
  ↓
Pydantic
  ↓
typing extensions

同时:

复制代码
PyTorch
  ↓
CUDA / CPU
  ↓
不同平台 wheel

传统:

复制代码
pip install
requirements.txt

在复杂环境下很容易演变成:

复制代码
requirements.txt
requirements-dev.txt
requirements-cuda.txt
requirements-cpu.txt
requirements-linux.txt

而 uv 的:

diff 复制代码
universal lockfile
+
dependency groups
+
package indexes
+
environment markers
+
workspace

非常适合这类复杂项目。


四十八、对于你这种 Python 后端 / AI 应用开发者,应该怎么用?

如果是:

diff 复制代码
FastAPI
+
LangGraph
+
LangChain
+
Pydantic
+
PostgreSQL
+
Redis

我建议直接采用:

arduino 复制代码
uv
│
├── Python 版本
│
├── pyproject.toml
│
├── uv.lock
│
├── .venv
│
├── dependency groups
│
├── uv run
│
└── uvx

而不是:

diff 复制代码
pyenv
+
venv
+
pip
+
pip-tools
+
pipx
+
requirements.txt

四十九、一个比较完整的现代 Python 工作流

初始化:

csharp 复制代码
uv init

指定 Python:

复制代码
uv python pin 3.12

添加运行时依赖:

csharp 复制代码
uv add fastapi
uv add pydantic
uv add sqlalchemy

添加开发依赖:

sql 复制代码
uv add --dev pytest
uv add --dev ruff

同步:

bash 复制代码
uv sync

运行:

arduino 复制代码
uv run python -m my_app

测试:

arduino 复制代码
uv run pytest

代码检查:

arduino 复制代码
uv run ruff check .

查看依赖:

复制代码
uv tree

升级依赖:

csharp 复制代码
uv lock --upgrade

构建:

复制代码
uv build

发布:

复制代码
uv publish

整个项目的生命周期就可以统一到:

csharp 复制代码
uv
 │
 ├── init
 ├── python
 ├── add
 ├── remove
 ├── lock
 ├── sync
 ├── run
 ├── tree
 ├── build
 └── publish

五十、几个容易踩坑的地方

1. 不要把 uv pipuv add 混为一谈

如果是 uv project:

csharp 复制代码
uv add xxx

通常优于:

复制代码
uv pip install xxx

因为前者会维护:

diff 复制代码
pyproject.toml
+
uv.lock
+
project environment

2. 不要手工修改 uv.lock

让 uv 管理。


3. 不要把 .venv 提交 Git

.venv 是环境,不是项目源代码。


4. 不要忽略 Python 版本

生产环境最好明确:

ini 复制代码
requires-python = ">=3.12,<3.13"

或者根据实际兼容范围定义。

同时:

复制代码
.python-version

固定开发环境。


5. Docker 中注意缓存目录和构建策略

如果 Dockerfile 没有正确利用 uv cache,那么 uv 的性能优势会被大幅削弱。


6. 不要滥用 dependency override

如果 resolver 无法解决:

arduino 复制代码
先检查依赖关系
→ 升级/降级直接依赖
→ 寻找兼容版本
→ 最后才考虑 override

五十一、如何理解 uv 的真正价值?

如果只把 uv 看成:

复制代码
pip 的 Rust 重写

实际上低估了它。

更准确的理解是:

bash 复制代码
                uv
                 │
      ┌──────────┼──────────┐
      │          │          │
 Python       Project      Tools
 Runtime      Management   Management
      │          │          │
      │          │          │
 python      pyproject     uvx
 install     uv.lock       tool
 pin         sync          install
      │          │          │
      └──────────┼──────────┘
                 │
          Dependency Resolver
                 │
          Global Cache
                 │
          Package Index

它真正解决的是:

Python 项目的完整生命周期管理问题。

而不仅仅是:

如何安装一个 Python 包。


五十二、最终应该如何选择?

如果你是一个刚接触 Python 的开发者:

复制代码
uv

可以直接作为默认工具。

如果你是多年 Python 开发者:

复制代码
pip
venv
requirements.txt

也没有必要马上全部抛弃。

更合理的路线是:

csharp 复制代码
现有项目
   │
   ↓
uv pip
   │
   ↓
验证兼容性
   │
   ↓
pyproject.toml
   │
   ↓
uv.lock
   │
   ↓
uv project

而新项目则可以直接:

csharp 复制代码
uv init

开始。


五十三、总结

uv 最值得关注的地方并不是"比 pip 快多少",而是它把 Python 开发过程中长期分散的工具链重新进行了整合:

markdown 复制代码
                过去

pyenv ────── → Python
venv ─────── → 环境
pip ──────── → 包
pip-tools ── → 锁定
pipx ─────── → CLI
Poetry ───── → 项目
setuptools ─ → 构建
twine ────── → 发布


                ↓


                uv

        ┌───────────────┐
        │      uv       │
        ├───────────────┤
        │ Python        │
        │ Environment   │
        │ Dependencies  │
        │ Resolver      │
        │ Lockfile      │
        │ Tools         │
        │ Scripts       │
        │ Workspace     │
        │ Build         │
        │ Publish       │
        └───────────────┘

对于现代 Python 项目而言,最值得掌握的不是几十个 uv 命令,而是下面这套模型:

arduino 复制代码
pyproject.toml
      │
      │ 声明
      ↓
依赖需求
      │
      │ resolver
      ↓
uv.lock
      │
      │ sync
      ↓
.venv
      │
      │ run
      ↓
Application

再进一步:

markdown 复制代码
.python-version
       │
       ↓
Python Runtime

pyproject.toml
       │
       ↓
Project Definition(定义)

uv.lock
       │
       ↓
Reproducible Resolution(可复现解析)

.venv
       │
       ↓
Project Environment

uv run
       │
       ↓
Execution

这套模型实际上比"pip install 安装几个包"高一个抽象层次。

对于 FastAPI、Django、LangChain、LangGraph、AI Agent、数据处理、CLI 工具以及大型 Python Monorepo 等现代项目,uv 已经不只是一个包安装器,而更接近 Python 项目的基础设施级工具链


官方资料

相关推荐
weixin199701080163 小时前
[特殊字符]️《从0到1搭多平台二手ERP中台:闲鱼+淘宝+京东+拼多多+Mercari统一调度》(附Python源码)
python
巡山小钻风来也3 小时前
【保姆级教程】自定义数据集微调PP-OCRv6文本检测模型
python·ocr·paddlepaddle
baopixiaoz3 小时前
BeeQuant × BeeAgent:用AI加速策略验证
大数据·人工智能·python·区块链
浩瀚地学3 小时前
deepagents学习打卡day04
python·agent
安易算力4 小时前
PUE优化工程实践:从1.5到1.2的制冷架构与气流组织改造路径
网络·python·容器·架构·kubernetes
troy1284 小时前
Codex 安全盲区:代码漏洞生成实测
windows·python·ci/cd·pycharm·django·github·fastapi
嵌入式学习菌5 小时前
Workbuddy自动写一个RS485 / LoRa 参数调试工具
python
钱栈up5 小时前
番茄小说榜单爬虫失效排查:从页面路由变更到API参数映射的全流程复盘
python
唐璜Taro6 小时前
Agent Harness 系列 · 第 1 篇|Agent 不只是换一个更强的模型
人工智能·python