# ADR-0009:uv 与托管 Python 环境 - 状态:已接受 - 日期:2026-11-07 ## 背景 Python 任务需要一个可复现的运行环境,但宿主机上的工具链状态不可控:PATH 上的 uv 版本随启动方式变化(终端 / 快捷方式 / 计划任务各不相同),也可能根本没装;pip、conda 与项目 `.venv` 的组合更是无法预设。之前的实现直接依赖 PATH 里的 uv,并要求用户先手动准备好虚拟环境,出了问题要到第一次运行时才暴露。 ## 决策 1. **uv 是唯一的环境工具**:建环境、装依赖、跑预装都走 uv,不依赖 `pip.exe`。 2. **uv 来源只认平台副本或指定路径**:默认 `程序目录\uv\uv.exe`,或用户指定的 `uv.exe`;**不读系统 PATH**。缺失时从科大镜像 `mirrors.ustc.edu.cn/github-release/astral-sh/uv/LatestRelease` 下载当前架构压缩包,校验 sha256 后安装到程序目录。 3. **镜像只在装包时生效**:建环境 / 预装依赖时注入 `UV_DEFAULT_INDEX`(以及兼容的 `UV_INDEX_URL`);任务运行时不再注入 `PIP_*` 或镜像变量。 4. **路径默认值相对程序目录**:`UV_PYTHON_INSTALL_DIR` 默认 `python`、`UV_CACHE_DIR` 默认 `uv-cache`,注入前统一按可执行文件目录解析成绝对路径;用户可改成绝对路径。 5. **用户环境优先,缺失才创建**:解析顺序仍是显式 `venv` → 解释器路径推断 → 工作目录向上查找;都没有时在**保存任务**时用 uv 创建 `.venv`,运行期只校验、不再自动装依赖。 6. **托管环境**:`data/envs/<名称>` 预创建常用环境,Python 版本来自 `uv python install` 下载到平台的列表,可预装包、查看已装包。 ## 原因 - PATH 上的 uv 版本与可用性不可控;平台副本随包分发,行为可预期。 - 相对默认值让整个发布目录可以整体搬迁;注入前解析成绝对路径,是因为 uv 的 cwd 在调用间会变化(项目目录 / 环境目录),相对路径会漂。 - 把装依赖限制在保存任务阶段,问题能当场暴露;运行期保持"只运行、不改环境"。 - 单机场景下,用户自己调试好的虚拟环境就是最可信的运行环境,应当优先复用而不是覆盖。 ## 边界 - 托管环境不会自动升级依赖,也不跟随 `pyproject.toml` 变更重建。 - `uv python install` 走 uv 自己的 Python 发行源,不受 PyPI 镜像影响;必要时用 `UV_PYTHON_INSTALL_MIRROR`。 - 删除托管环境是直接删除目录,不可恢复。 - 自定义 uv 若版本过旧,`uv python list/envs` 等子命令可能与平台预期的参数不一致。