8.conda 与 uv 环境管理完全指南:从概念到实战避坑

conda 与 uv 环境管理完全指南:从概念到实战避坑

适用项目:LangChain-agent(后端 FastAPI + LangChain,前端 React + Vite) 一句话结论 :本项目是纯 Python 项目,用 uv 管理即可,不需要 conda 。 但理解三种组合(只用 conda / 只用 uv / conda + uv 配合)的启动命令差异,能避免"明明装了依赖却报 ModuleNotFoundError"这个经典坑。


一、关键命令(TL;DR)

管理方案 后端怎么起 前端怎么起 关键原则
只用 conda conda activate xxxpython -m uvicorn ... npm run dev 激活后 python 就是环境内的,裸跑即可
只用 uv uv syncuv run uvicorn ... npm run dev 必须用 uv runpython 会找不到依赖
conda + uv 配合 conda activate xxxuv run ...(uv 用 conda 解释器时)或 python -m ... npm run dev 确认 uv 的 .venv 用的是哪个解释器,别混

最坑的一点 :用系统 Python(python -m uvicorn)启动时,它既不属于 conda 也不属于 uv 的 .venv,所以读不到任何环境的依赖 → 一请求就 No module named 'xxx'。本项目就踩过这个坑(详见第五节实战记录)。


二、核心概念扫盲

在讲怎么用之前,先把几个最容易混淆的概念厘清。

2.1 conda 负责什么

conda 是一个跨语言的环境 + 包管理器

  • 创建隔离的 Python 环境(独立解释器 + 站点包)
  • 能装非 Python 的二进制依赖:CUDA、MKL、PyTorch GPU 版、R 语言包等
  • conda activate myenv 切换环境,激活后命令行里的 python / pip 都指向该环境
bash 复制代码
conda create -n langchain-agent python=3.11
conda activate langchain-agent
conda install numpy          # 或 pip install numpy

适用场景:需要 GPU / 系统级库、多语言项目、已有 conda 工作流。

2.2 uv 负责什么(重点:它不只是包管理器)

uv 是纯 Python 的极速环境 + 包管理器 (Rust 实现,可替代 pip + venv + pip-tools):

  • 创建虚拟环境(.venvuv sync 自动建)
  • 安装 Python 包,比 pip 快 10--100 倍
  • 依赖锁定:uv.lock 保证多机器可复现
  • 自带 Python 版本管理 :本机没有对应解释器时自动下载(如本项目自动用 F:\uv-python\cpython-3.13
bash 复制代码
uv sync                       # 按 pyproject.toml 建 .venv 并装依赖
uv run python -m app.main     # 在 .venv 里运行
uv add fastapi                # 加依赖并写入 pyproject.toml

⚠️ 常见误解纠正 :uv 不是"单纯的包管理器" ,它和 conda 一样也做环境隔离.venv 就是隔离出来的环境,只是默认放在项目目录内)。所以"uv 只是装包的"这个说法是错误的------uv venv 等价于 python -m vvenvuv run 等价于"激活 .venv 再执行"。

适用场景:纯 Python 项目、Web 服务、AI / LLM 应用(本项目就是)。

2.3 .venv 是什么

项目私有的 Python 环境文件夹,含:

  • 独立的 Python 解释器副本(项目/.venv/Scripts/python.exe
  • 独立的 site-packages/
  • Scripts/activate(Windows 激活脚本)

它与全局 Python 完全隔离 ,通常放进 .gitignore(不提交,靠 uv sync 重建),作用和 conda 的 envs/myenv 相同,但更轻更快。

验证你跑在哪个环境(隔离的本质):

powershell 复制代码
uv run python -c "import sys; print(sys.executable)"
# 输出: ...\项目\backend\.venv\Scripts\python.exe  ← 证明跑在 .venv 隔离环境

一句话uv run / 激活 .venv 后跑的所有 python 命令只在 .venv 这个"小房间"里生效,装错包、版本冲突都被关在里面。换项目前务必确认激活的是哪个环境。

2.4 .env 是什么(与 .venv 完全不同!)

.venv .env
是什么 隔离的 Python 环境(文件夹) 配置文件(文本)
存什么 解释器 + 依赖包 环境变量 / 密钥:OPENAI_API_KEY=xxx
谁读 uv / Python 解释器 代码(python-dotenv
提交 git ❌ 忽略 ❌ 忽略(含密钥!)
模板 .env.example 提交,.env 不提交

示例(本项目 backend/.env):

env 复制代码
OPENAI_API_KEY=sk-xxxx
OPENAI_BASE_URL=https://api.deepseek.com
MODEL_NAME=deepseek-chat

代码通过 python-dotenvload_dotenv() 读取(backend/app/config.py)。


三、怎么选:conda 还是 uv?

情况 用哪个
纯 Python 后端 / Web / Agent uv(推荐)
需要 CUDA、PyTorch GPU、MKL conda
多语言 / 科研复现 conda
追求安装速度 + lock 文件 uv
已有 conda 基础环境 conda 内用 uv(见下)

结论很清晰:纯 Python 项目优先 uv,需要系统级二进制依赖再上 conda。


四、四种使用模式与对应启动命令

下面按实际组合给出可直接抄的启动命令 。前端都是 Node 项目,与 Python 环境无关,统一用 npm run dev

模式 A:只用 conda

依赖装进名为 myenv 的 conda 环境,没有 .venv

powershell 复制代码
conda activate myenv
cd backend
python -m uvicorn app.main:app --host 0.0.0.0 --port 8000

为什么conda activatepython 直接指向 envs/myenv/python.exe,依赖都在那里,裸 python 即可,不需要 uv,也没有 .venv

模式 B:只用 uv(本项目采用)

uv syncpyproject.toml.venv 装依赖,uv run 确保命令在 .venv 内执行。

powershell 复制代码
cd backend
uv sync                              # 建 .venv 并装依赖(首次需联网)
cp .env.example .env                 # 第一次需创建 .env 并填 API Key
uv run uvicorn app.main:app --host 0.0.0.0 --port 8000

为什么 :uv 自己管理一切。注意 必须写 uv run ,不能写 python -m uvicorn------后者调用的是系统 Python,读不到 .venv 里的包(见第五节实战坑)。本项目入口是 app.main:app(FastAPI 实例),故用 uv run uvicorn app.main:app

模式 C:conda + uv 配合(conda 管解释器,uv 管依赖)

conda 提供基础解释器,uv 在其上用 requirements.txt / pyproject.toml 装依赖到 .venv 并运行。

powershell 复制代码
conda activate myenv
cd backend
uv run python -m uvicorn app.main:app --reload --host 127.0.0.1 --port 8000

为什么 :「conda 管解释器 + uv 管包」的组合。uv run 默认会创建自己的 .venv;若想让它直接用 conda 环境需加 --system 或先 uv venv --python $(which python),否则可能装了两份依赖。

让 uv 用当前 conda 解释器:

bash 复制代码
conda activate myenv
uv venv --python $(which python)    # .venv 基于 conda 解释器
uv sync

风险点:

  • 一般无冲突:uv 装到自己的 .venv,conda 装到 envs/myenv,互不干扰
  • 最大风险 :忘了激活正确环境装错地方;或 conda 激活了但 uv 又自建了 .venv,运行时必须用 uv run 才能用对那个环境
  • 推荐:二选一,不要混。混用仅在「conda 管 Python 版本 + uv 管 Python 包」时才值得

模式 D:系统 Python(❌ 不推荐,最易踩坑)

直接用 F:\software download\Python\python.exe 这种系统解释器跑,不激活任何环境。

powershell 复制代码
python -m uvicorn app.main:app --port 8000   # ❌ 容易缺依赖

为什么危险 :系统 Python 的 site-packages 通常没装项目依赖(conda / uv 都没往里装),一运行就 ModuleNotFoundError本项目就因此踩过坑(见下)。


五、实战:本项目标准启动流程

powershell 复制代码
# 终端 1:后端(uv 环境)
cd backend
uv sync                         # ① pyproject.toml + uv.lock → 建 .venv 并装依赖
cp .env.example .env            # ② 创建 .env(若已存在可跳过),填入真实 API Key
uv run uvicorn app.main:app --host 0.0.0.0 --port 8000

# 终端 2:前端(Node,与 Python 环境无关)
cd frontend
npm install                     # 首次
npm run dev                     # Vite 启动,默认 5173,代理 /api → localhost:8000

关系链:

scss 复制代码
pyproject.toml ──uv sync──▶ .venv (运行环境 + 锁定版本)
.env          ──load_dotenv()──▶ 代码读取配置 / 密钥
frontend(5173) ──Vite proxy /api──▶ backend(8000)

三种真实项目对比

项目 环境 / 依赖管理 依赖声明文件 启动核心差异
RAG-agent 只用 conda 无(手动 pip 装) conda activate + 裸 python
LangChain-agent 只用 uv pyproject.toml + uv.lock uv sync + uv run
Agent-project conda + uv 混用 requirements.txt conda activate + uv run

运行时解释器位置对照(隔离层在哪一目了然):

项目 运行时解释器位置
RAG-agent(conda) F:\Miniconda\envs\rag-agent\python.exe(conda 即隔离层,无 .venv
LangChain-agent(uv) 项目/backend/.venv/Scripts/python.exe
Agent-project(conda+uv) 项目/Backend/.venv/Scripts/python.exe

六、实战踩坑记录:为什么必须用 uv run

现象 :用户用 F:\software download\Python\python.exe 直接 python -m uvicorn app.main:app --port 8000,后端启动正常,但前端一提问就"没输出"。

排查 :用 uv run python 直接 POST /api/chat 抓原始 SSE 字节,发现后端返回:

vbnet 复制代码
event: error
data: {"code": "STREAM_ERROR", "message": "No module named 'langchain_mcp_adapters'"}

模型调用需要 MCP 适配器,而系统 Python 的 site-packages 里没有(依赖只在 uv 的 .venv 中)。

根因 :裸 python -m uvicorn 用的是系统 Python,既非 conda 也非 uv 的 .venv,读不到任何项目依赖。

解决:改用 uv 环境启动:

powershell 复制代码
cd backend
uv run uvicorn app.main:app --host 0.0.0.0 --port 8000

重启后 SSE 正常返回 deltadone,前端恢复输出。

教训 :本项目后端必须用 uv run 启动,不能裸 python -m uvicorn。这也印证了模式 B 的原则。


七、常见错误速查

现象 原因 解决
ModuleNotFoundError: xxx 用系统 Python / 没激活环境跑 改用 uv run 或先 conda activate
WinError 10048 端口占用 上次进程没退出 / 残留子进程 见第八节,杀真实持有进程
前端提问"没输出" 后端 SSE 返回 event: error,前端没显示错误 看后端日志,多半是 No module named ... → 用了错环境
uv run 很慢 首次解析 / 下载解释器 正常,后续快
conda activate 不生效 没初始化 shell conda init powershell 后重开终端

八、端口冲突排查(Windows 实战)

联调时常遇到 OSError: [WinError 10048] 通常每个套接字地址只允许使用一次

诊断谁占了端口(PowerShell):

powershell 复制代码
netstat -ano | findstr ":8000"                          # 看占用 PID
Get-NetTCPConnection -LocalPort 8000 -State Listen      # 精确查监听进程
taskkill /PID <pid> /F                                  # 强杀

⚠️ 坑:Get-NetTCPConnection 有时会显示已退出父进程的 PID(socket 残留),taskkill 报"找不到进程"。这时真正持有 socket 的是它的子进程(multiprocessing fork 出来的)。用下面命令找真实持有者:

powershell 复制代码
Get-CimInstance Win32_Process -Filter "ProcessId=<显示出的pid>" | Select-Object CommandLine
# 若 CommandLine 含 "multiprocessing.spawn ... parent_pid=xxx",则去查那个子进程并杀掉它

本项目曾因 uv run python xxx 的父进程残留子进程占着 8000,导致重启 uvicorn 失败,杀掉残留子进程后端口才释放。


九、一句话总结

  • .venv = 隔离的运行环境(装包的地方,含独立解释器副本 + site-packages
  • uv sync = 把依赖装进 .venv 的命令
  • uv.lock = 保证依赖版本可复现的锁文件
  • uv run = "在 .venv 里执行命令"的快捷方式(替代手动激活)
  • conda activate = 切换到 conda 隔离环境,之后裸 python 即用该环境
  • .env = 放密钥 / 配置的文件,跟环境无关,只被代码读取
  • 铁律 :跑项目前先确认"此刻的 python 到底属于哪个环境",否则就是下一个 ModuleNotFoundError
相关推荐
是小李呀1 小时前
Spring Boot 配置加载机制解析:Docker 部署中 `spring.profiles.active` 与 `spring.config.location` 的本质区别
后端
步行cgn1 小时前
MyBatis 多参数绑定错误:Parameter 'name' not found 详解与解决方案
后端
步行cgn1 小时前
MyBatis 对单个简单类型参数的默认处理详解
后端
吃饱了得干活1 小时前
Java并发安全:看这一篇就懂了!
java·后端·面试
早点睡9751 小时前
向量检索原理入门:从 ANN 到 HNSW
后端·面试
Augustzero1 小时前
为什么高性能调度器都在“偷任务”?从无锁队列看懂工作窃取
c++·后端
Leo2821 小时前
异步任务链路如何不断链:基于 OpenTelemetry 的 Trace 设计
后端
技术长镜头2 小时前
别再死记 Record、Gap、Next-Key:沿一条 SQL 看懂 InnoDB 锁
后端·mysql
晚安code2 小时前
Java四大函数式接口一篇讲透:配上Stream流式计算处理集合
后端