1. 为什么我劝你把 pip、virtualenv、pyenv 全换成 uv
如果你写过半年以上的 Python,大概率经历过这种场景:新克隆一个仓库,README 里写着「先python -m venv venv,再source venv/bin/activate,然后pip install -r requirements.txt」,结果装到一半报编译错误,回头发现自己的全局 Python 是 3.9,而项目要 3.12。于是你开始装 pyenv、改 shell 配置、重开终端,半小时过去了,代码一行没跑。
uv 就是来终结这套流程的。它是一个用 Rust 写的 Python 包与项目管理器,官方定位是「pip、pip-tools、pipx、poetry、pyenv、virtualenv 的统一替代品」。我第一次在 MCP Server 项目里用它,是因为客户端配置里直接写了uv run test.py,当时还纳闷:虚拟环境去哪了?后来才明白,uv 把「创建环境、装依赖、激活环境、运行脚本」压缩成了一条命令,环境路径、Python 版本、依赖锁定它全帮你记着。
它到底能做什么?简单说四件事:管理 Python 解释器版本(类似 pyenv)、创建隔离虚拟环境(类似 virtualenv)、安装与解析依赖(类似 pip + pip-tools)、锁定依赖保证可复现(类似 poetry lock)。适合谁?适合所有被「环境不一致」折磨过的 Python 开发者,尤其是要写 MCP Server、做数据脚本、维护多个项目的同学。
这篇不是官网文档的翻译,而是我把 uv 从安装到依赖锁定、多版本切换、再到 MCP 场景踩过的坑,整理成一份可以照着敲的完整工作流。你跟着走一遍,基本就能把项目里的 requirements.txt 和 venv 目录一起删掉了。
2. 安装 uv 与 TaoToken 前置准备:让依赖解析和模型调用都跑通
在正式进入 uv 工作流之前,先把两件事准备好:uv 本身,以及一个能稳定调用大模型 API 的入口。前者负责你的 Python 环境,后者负责你在写 MCP Server 或 AI 脚本时能直接调模型。这里我用 TaoToken 作为统一入口,它的 API 地址是https://taotoken.net/api,官网在https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=,注册后在控制台生成 Key 即可。
先说 uv 安装。macOS 和 Linux 一条命令:
curl -LsSf https://astral.sh/uv/install.sh | shWindows 用 PowerShell:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"装完终端会提示你把$HOME/.local/bin加进 PATH。macOS 上执行:
source $HOME/.local/bin/env uv --version看到类似uv 0.6.14就成功了。注意 uv 不需要你预先装 Python,它自带解释器下载能力,这点比 pip 友好太多。
接下来是 TaoToken 的前置。为什么放在这里?因为后面第 4 节我会用一个「调用模型生成摘要」的脚本来验证环境隔离,脚本里需要读 API Key。你可以在 TaoToken 控制台创建 Key,然后写进环境变量:
export TAOTOKEN_API_KEY="sk-你的key" export TAOTOKEN_BASE_URL="https://taotoken.net/api"如果你打算长期做编码类 Agent 项目,可以顺手了解下 Coding Plan,它更适合高频调用场景;只是偶尔验证模型,用模型对话页面就够了。这里不展开,先把 Key 拿到手,后面脚本直接引用。
有一点要提醒:uv 的全局缓存目录和 Python 解释器目录是分开的,卸载时别只删二进制。完整卸载顺序是:
uv cache clean rm -r "$(uv python dir)" rm -r "$(uv tool dir)" rm ~/.local/bin/uv ~/.local/bin/uvx我试过只删二进制不清理缓存,结果重装后磁盘里还躺着几个 G 的 wheel 包。所以养成先清缓存再删二进制的习惯。
3. 可复制配置:pyproject.toml、uv.lock 与镜像源完整片段
uv 的核心工作流围绕三个文件转:.python-version、pyproject.toml、uv.lock。理解它们的分工,你就能掌控整个环境。
.python-version记录项目要用的解释器版本,由uv python pin生成。pyproject.toml是项目元数据和依赖声明,uv.lock是精确到每个包及其哈希的锁定文件,保证任何人 clone 后装出来的依赖完全一致。
先建项目。推荐先建目录再初始化,这样能先 pin 版本:
mkdir uv-demo && cd uv-demo uv python pin 3.12 uv init执行后目录里会出现README.md、main.py、pyproject.toml,同时 uv 会帮你git init。此时pyproject.toml内容大致如下:
[project] name = "uv-demo" version = "0.1.0" description = "Add your description here" readme = "README.md" requires-python = ">=3.12" dependencies = []国内网络下,默认 PyPI 源会很慢。在pyproject.toml里加清华源:
[[tool.uv.index]] url = "https://pypi.tuna.tsinghua.edu.cn/simple" default = true注意优先级:pyproject.toml里的 index 配置高于环境变量UV_DEFAULT_INDEX。如果你在 CI 里用环境变量临时指定,本地文件会覆盖它,排查时别搞混。
现在加依赖。比如加requests和httpx:
uv add requests httpxuv 会自动创建.venv、解析依赖、写入pyproject.toml的dependencies,并生成uv.lock。此时pyproject.toml变成:
[project] name = "uv-demo" version = "0.1.0" requires-python = ">=3.12" dependencies = [ "requests>=2.32.3", "httpx>=0.27.0", ] [[tool.uv.index]] url = "https://pypi.tuna.tsinghua.edu.cn/simple" default = true如果你要指定精确版本,用uv add requests==2.32.3。要加开发依赖,用uv add --dev pytest,它会写进[dependency-groups]而不是主依赖。
关于 MCP Server 场景,客户端配置里通常这样写:
{ "mcpServers": { "my-tool": { "command": "uv", "args": ["--directory", "/path/to/project", "run", "server.py"] } } }这里三件套必须齐全:Base URL 指向https://taotoken.net/api,Key 用环境变量注入,Model ID 在脚本里指定。uv 负责把server.py跑起来,TaoToken 负责模型调用,两者职责清晰。如果你用 Cline 或 Claude Code 这类工具,配置逻辑一样,只是字段名不同。
4. 验证请求:用 uv run 跑通环境隔离与依赖一致性
配置写好了,怎么确认环境真的隔离、依赖真的锁定?我设计了一个小脚本,既验证 uv 的环境隔离,又顺带验证 TaoToken 的模型调用。
在项目根目录建check_env.py:
import os import sys import httpx print("Python 版本:", sys.version) print("解释器路径:", sys.executable) print("虚拟环境:", os.environ.get("VIRTUAL_ENV", "未激活(uv run 自动管理)")) api_key = os.environ.get("TAOTOKEN_API_KEY") base_url = os.environ.get("TAOTOKEN_BASE_URL", "https://taotoken.net/api") if not api_key: print("未设置 TAOTOKEN_API_KEY,跳过模型调用") sys.exit(0) resp = httpx.post( f"{base_url}/v1/chat/completions", headers={"Authorization": f"Bearer {api_key}"}, json={ "model": "gpt-4o-mini", "messages": [{"role": "user", "content": "用一句话说明什么是虚拟环境"}], }, timeout=30, ) print("状态码:", resp.status_code) print("模型返回:", resp.json()["choices"][0]["message"]["content"])运行:
uv run check_env.py你会看到sys.executable指向项目下的.venv/bin/python,而不是系统 Python。这就是隔离生效的证据。如果模型调用成功,状态码是 200,返回一句话解释。这一步同时验证了两件事:uv 的环境隔离没问题,TaoToken 的 API 通路没问题。
再验证依赖一致性。先看锁定文件:
uv lock --check如果uv.lock和pyproject.toml一致,命令静默退出;不一致会报错并提示你运行uv lock。然后模拟新机器:
rm -rf .venv uv syncuv sync会严格按uv.lock重建环境,速度极快,因为 wheel 都走全局缓存。装完再跑一次uv run check_env.py,输出应该完全一致。这就是「依赖一致性」的验证闭环。
多版本切换也顺手验证一下。假设你要临时用 3.11 跑:
uv python install 3.11 uv run --python 3.11 check_env.pyuv run --python会临时用指定解释器,不改动.python-version。要永久切换,就uv python pin 3.11再uv sync。注意.python-version只影响 uv 管理的环境,不会动你系统的python3命令,这点设计很干净。
5. 本篇常见错排查:401、local proxy failed、reading choices 与 OAuth
这一节把我踩过的坑按报错原文列出来,你对照着查。
401 Unauthorized。模型调用返回 401,九成是 Key 没读到。先确认echo $TAOTOKEN_API_KEY有值,再确认脚本里读的是同一个变量名。如果你在 MCP 客户端里配置,注意客户端启动的子进程不一定继承你 shell 的环境变量,最好在配置里显式写env字段。另外 Key 别硬编码进pyproject.toml,那文件是要进 git 的。
local proxy failed / connection refused。这个报错通常出现在uv add或uv sync阶段,说明 uv 连不上 PyPI 或你配的镜像源。先检查pyproject.toml里的[[tool.uv.index]]URL 有没有写错,清华源是https://pypi.tuna.tsinghua.edu.cn/simple,结尾的/simple不能少。如果公司网络有内网源,把 URL 换成内网地址。还有一种情况是UV_DEFAULT_INDEX环境变量和文件配置冲突,用uv add --verbose看它实际用了哪个源。
reading choices 相关报错。这类错误一般出现在解析模型返回时,比如KeyError: 'choices'或reading 'choices' of undefined。原因是 API 返回的不是标准 chat completions 结构,可能是错误响应体。打印resp.text看原始内容,常见的是模型名写错、或者 Base URL 少了/v1。TaoToken 的 Base URL 是https://taotoken.net/api,拼 chat completions 路径时注意补全。
OAuth 相关报错。如果你用 Claude Code 或 Codex 这类工具,可能会遇到 OAuth token 过期。这类工具通常有自己的登录态,和 uv 无关。排查时先确认工具本身的登录是否有效,再看它调用的命令是不是uv run。如果是 Codex 的auth.json,检查里面的 token 字段是否过期;Cline 的 MCP 配置则检查command和args是否指向正确的 uv 路径。
uv.lock 冲突。多人协作时,如果两个人同时改依赖,uv.lock会冲突。别手动编辑 lock 文件,正确做法是git checkout --theirs uv.lock或--ours选一边,然后uv lock重新生成,再uv sync。lock 文件是机器生成的,手改必出错。
虚拟环境没生效。有人习惯source .venv/bin/activate,但在 uv 工作流里没必要。如果你激活了旧环境又跑uv run,可能出现包版本混乱。建议直接deactivate,全程用uv run,让 uv 自己管。
6. 语义一致 CTA:把 uv 工作流接到你的 AI 编码链路里
走到这里,你已经有了一个可复现的 uv 项目:.python-version定版本,pyproject.toml声明依赖,uv.lock锁死一致性,uv run一键跑脚本。接下来就是把它接到真实的 AI 编码场景里。
如果你主要在做 MCP Server 或 Agent 类项目,建议去 TaoToken 控制台生成一个专用 Key,然后按第 3 节的 JSON 片段配到你的客户端里。Base URL 用https://taotoken.net/api,Model ID 按你实际用的模型填。需要长期高频调用的话,Coding Plan 比按次调用更划算;只是偶尔验证模型输出,用模型对话页面手动测几条就行。
接入文档里有各语言 SDK 的调用示例,API Keys 页面管理你的凭证。我自己的习惯是:每个项目一个 Key,方便按项目排查用量,也避免一个 Key 泄露影响所有项目。
最后留一个实用技巧:把uv run写进你的 Makefile 或 npm scripts,比如make run对应uv run main.py,make test对应uv run pytest。这样团队里不管谁用什么系统,跑出来的环境都一致。uv 的全局缓存还会让第二次uv sync快得离谱,CI 里能省不少时间。环境这件事,交给 uv 之后,你基本可以忘了它的存在。