大模型应用开发者 Python 必修课(二):环境配置篇
2024-01-27·5 分钟阅读
大模型应用开发者 Python 必修课(二):环境配置篇
前言
在大模型应用开发中,良好的环境配置是项目成功的基础。不同的项目可能需要不同版本的依赖库,比如项目 A 使用 openai==1.0.0,而项目 B 需要 openai==1.20.0。如果没有合理的隔离机制,依赖冲突会让你焦头烂额。
本章将深入探讨 Python 环境管理的核心概念和最佳实践,帮助你建立专业级的开发环境。
虚拟环境:为什么需要它?
依赖隔离问题
假设你的系统中有两个项目:
系统 Python 环境:
├── openai 1.0.0 (全局安装)
项目 A 需要:
├── openai >= 1.0.0 ✓ 满足
项目 B 需要:
├── openai >= 1.20.0 ✗ 版本过低!
这就是典型的依赖冲突问题。虚拟环境通过为每个项目创建独立的 Python 环境来解决这个问题。
虚拟环境的原理
虚拟环境结构:
my-project/
├── .venv/ # 虚拟环境目录
│ ├── bin/ # Linux/macOS
│ │ ├── python -> /usr/bin/python3.10
│ │ ├── pip
│ │ └── activate
│ ├── Scripts/ # Windows
│ │ ├── python.exe
│ │ ├── pip.exe
│ │ └── activate.bat
│ ├── lib/
│ │ └── python3.10/
│ │ └── site-packages/ # 独立的包安装目录
│ └── pyvenv.cfg # 环境配置文件
├── src/
├── tests/
└── pyproject.toml
虚拟环境的关键特性:
- 独立的 site-packages:每个环境有自己的包安装目录
- Python 解释器链接:指向创建时使用的 Python 版本
- 隔离的 PATH:激活后,优先使用环境内的命令
创建虚拟环境的三种方式
1. venv(Python 内置)
Python 3.3+ 内置的虚拟环境工具,轻量且无需额外安装:
# 创建虚拟环境
python -m venv .venv
# 激活虚拟环境
# Linux/macOS
source .venv/bin/activate
# Windows (PowerShell)
.venv\Scripts\Activate.ps1
# Windows (CMD)
.venv\Scripts\activate.bat
# 退出虚拟环境
deactivate
优点:
- 内置工具,无需额外安装
- 轻量级,创建速度快
- 标准化,兼容性好
缺点:
- 不支持直接指定 Python 版本(使用创建时的 Python)
- 功能相对简单
2. virtualenv
功能更强大的第三方虚拟环境工具:
# 安装
pip install virtualenv
# 创建虚拟环境
virtualenv .venv
# 指定 Python 版本
virtualenv -p python3.10 .venv
virtualenv -p python3.11 .venv
优点:
- 支持指定任意 Python 版本
- 创建速度更快(使用缓存)
- 支持更多配置选项
缺点:
- 需要额外安装
- 对于简单项目可能过度
3. conda
适合数据科学和机器学习项目:
# 创建环境
conda create -n llm-project python=3.10
# 激活环境
conda activate llm-project
# 退出环境
conda deactivate
# 列出所有环境
conda env list
# 删除环境
conda env remove -n llm-project
优点:
- 可以管理不同版本的 Python 本身
- 支持非 Python 依赖(如 CUDA)
- 适合数据科学和机器学习项目
缺点:
- 安装体积大
- 与 pip 混用时可能产生问题
选择建议
| 场景 | 推荐工具 |
|---|---|
| 纯 Python 项目 | venv |
| 需要管理多个 Python 版本 | virtualenv 或 conda |
| 数据科学/机器学习项目 | conda |
| 大模型应用开发(API 调用) | venv + poetry |
| 需要安装 CUDA 等系统依赖 | conda |
依赖管理工具对比
pip + requirements.txt
传统的依赖管理方式:
# 安装依赖
pip install openai anthropic
# 导出依赖
pip freeze > requirements.txt
# 从文件安装
pip install -r requirements.txt
requirements.txt 示例:
openai==1.12.0
anthropic==0.18.0
httpx==0.27.0
pydantic==2.6.0
python-dotenv==1.0.0
问题:
- 无法区分开发依赖和生产依赖
- 没有依赖锁定机制(间接依赖版本不确定)
- 跨平台时可能有兼容性问题
pip-tools
pip 的增强工具,支持依赖锁定:
# 安装
pip install pip-tools
# 创建 requirements.in(直接依赖)
# requirements.in
openai>=1.0.0
anthropic>=0.18.0
pydantic>=2.0.0
# 编译生成 requirements.txt(包含所有依赖)
pip-compile requirements.in
# 安装
pip-sync
生成的 requirements.txt:
# This file is autogenerated by pip-compile
# Using the following versions:
# openai==1.12.0
# anthropic==0.18.0
# ...
openai==1.12.0
# via -r requirements.in
anthropic==0.18.0
# via -r requirements.in
httpx==0.27.0
# via
# anthropic
# openai
pydantic==2.6.0
# via
# anthropic
# openai
Poetry(推荐)
现代 Python 项目管理工具,集成了依赖管理、虚拟环境、打包发布:
# 安装
pip install poetry
# 创建新项目
poetry new llm-project
# 或在现有项目中初始化
poetry init
# 添加依赖
poetry add openai anthropic
# 添加开发依赖
poetry add --group dev pytest black ruff
# 安装所有依赖
poetry install
# 激活虚拟环境
poetry shell
pyproject.toml 示例:
[tool.poetry]
name = "llm-project"
version = "0.1.0"
description = "大模型应用项目"
authors = ["Your Name <your@email.com>"]
readme = "README.md"
packages = [{include = "llm_project"}]
[tool.poetry.dependencies]
python = "^3.10"
openai = "^1.12.0"
anthropic = "^0.18.0"
pydantic = "^2.6.0"
python-dotenv = "^1.0.0"
[tool.poetry.group.dev.dependencies]
pytest = "^8.0.0"
black = "^24.0.0"
ruff = "^0.2.0"
mypy = "^1.8.0"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
Poetry 优势:
- 依赖锁定:poetry.lock 确保跨环境一致性
- 分组管理:区分生产依赖和开发依赖
- 版本约束:语义化版本控制
- 虚拟环境集成:自动创建和管理虚拟环境
- 打包发布:内置构建和发布功能
uv(新一代工具)
由 Astral(Ruff 的开发者)推出的超快 Python 包管理器:
# 安装
pip install uv
# 创建虚拟环境
uv venv
# 安装依赖(比 pip 快 10-100 倍)
uv pip install openai anthropic
# 从 requirements.txt 安装
uv pip install -r requirements.txt
# 从 pyproject.toml 安装
uv pip install -e .
优势:
- 极快的依赖解析和安装速度
- 兼容 pip 命令
- 内存占用低
适用场景:
- CI/CD 环境中加速依赖安装
- 大型项目的快速环境搭建
工具对比总结
| 特性 | pip + requirements | pip-tools | Poetry | uv |
|---|---|---|---|---|
| 依赖锁定 | ✗ | ✓ | ✓ | ✓ |
| 开发依赖分离 | ✗ | ✗ | ✓ | ✓ |
| 虚拟环境管理 | ✗ | ✗ | ✓ | ✓ |
| 安装速度 | 慢 | 慢 | 中等 | 极快 |
| 学习成本 | 低 | 中 | 中 | 低 |
| 生产推荐 | ✗ | ✓ | ✓ | ✓ |
生产级项目结构
推荐的目录结构
llm-project/
├── .venv/ # 虚拟环境(不提交到 Git)
├── src/ # 源代码目录
│ └── llm_project/
│ ├── __init__.py
│ ├── config.py # 配置管理
│ ├── clients/ # API 客户端
│ │ ├── __init__.py
│ │ ├── openai_client.py
│ │ └── anthropic_client.py
│ ├── models/ # 数据模型
│ │ ├── __init__.py
│ │ └── schemas.py
│ ├── services/ # 业务逻辑
│ │ ├── __init__.py
│ │ └── chat_service.py
│ └── utils/ # 工具函数
│ ├── __init__.py
│ └── helpers.py
├── tests/ # 测试目录
│ ├── __init__.py
│ ├── conftest.py # pytest 配置
│ ├── test_clients/
│ └── test_services/
├── .env.example # 环境变量模板
├── .env # 环境变量(不提交)
├── .gitignore
├── pyproject.toml # 项目配置
├── poetry.lock # 依赖锁定
└── README.md
pyproject.toml 完整配置
[tool.poetry]
name = "llm-project"
version = "0.1.0"
description = "大模型应用项目"
authors = ["Your Name <your@email.com>"]
readme = "README.md"
packages = [{include = "llm_project", from = "src"}]
[tool.poetry.dependencies]
python = "^3.10"
openai = "^1.12.0"
anthropic = "^0.18.0"
pydantic = "^2.6.0"
pydantic-settings = "^2.1.0"
python-dotenv = "^1.0.0"
httpx = "^0.27.0"
tenacity = "^8.2.0" # 重试机制
[tool.poetry.group.dev.dependencies]
pytest = "^8.0.0"
pytest-asyncio = "^0.23.0"
pytest-cov = "^4.1.0"
black = "^24.0.0"
ruff = "^0.2.0"
mypy = "^1.8.0"
pre-commit = "^3.6.0"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
# Black 配置
[tool.black]
line-length = 88
target-version = ["py310"]
include = '\.pyi?$'
# Ruff 配置
[tool.ruff]
line-length = 88
target-version = "py310"
select = ["E", "F", "I", "N", "W", "UP"]
ignore = ["E501"]
[tool.ruff.per-file-ignores]
"__init__.py" = ["F401"]
# MyPy 配置
[tool.mypy]
python_version = "3.10"
strict = true
warn_return_any = true
warn_unused_configs = true
# Pytest 配置
[tool.pytest.ini_options]
testpaths = ["tests"]
asyncio_mode = "auto"
addopts = "-v --tb=short"
.gitignore 配置
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# Virtual environments
.venv/
venv/
ENV/
env/
# IDE
.idea/
.vscode/
*.swp
*.swo
*~
# Environment variables
.env
.env.local
.env.*.local
# Testing
.pytest_cache/
.coverage
htmlcov/
.tox/
.nox/
# MyPy
.mypy_cache/
.dmypy.json
dmypy.json
# Ruff
.ruff_cache/
# Jupyter
.ipynb_checkpoints/
环境变量管理
使用 python-dotenv
# .env 文件
OPENAI_API_KEY=sk-xxx
ANTHROPIC_API_KEY=sk-ant-xxx
MODEL_NAME=gpt-4
TEMPERATURE=0.7
MAX_TOKENS=4096
# config.py
from dotenv import load_dotenv
import os
# 加载 .env 文件
load_dotenv()
class Config:
OPENAI_API_KEY: str = os.getenv("OPENAI_API_KEY", "")
ANTHROPIC_API_KEY: str = os.getenv("ANTHROPIC_API_KEY", "")
MODEL_NAME: str = os.getenv("MODEL_NAME", "gpt-4")
TEMPERATURE: float = float(os.getenv("TEMPERATURE", "0.7"))
MAX_TOKENS: int = int(os.getenv("MAX_TOKENS", "4096"))
使用 pydantic-settings(推荐)
# config.py
from pydantic_settings import BaseSettings, SettingsConfigDict
from functools import lru_cache
class Settings(BaseSettings):
"""应用配置"""
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
case_sensitive=False,
)
# API 密钥
openai_api_key: str = ""
anthropic_api_key: str = ""
# 模型配置
model_name: str = "gpt-4"
temperature: float = 0.7
max_tokens: int = 4096
# 应用配置
debug: bool = False
log_level: str = "INFO"
@lru_cache
def get_settings() -> Settings:
"""获取配置单例"""
return Settings()
# 使用
settings = get_settings()
print(settings.model_name) # "gpt-4"
pydantic-settings 优势:
- 类型验证:自动转换和验证环境变量类型
- 嵌套配置:支持复杂的配置结构
- 环境变量前缀:避免命名冲突
- 默认值:支持必填项和默认值
环境变量最佳实践
# 生产环境配置示例
from pydantic_settings import BaseSettings
from pydantic import Field, validator
class Settings(BaseSettings):
"""生产级配置"""
# API 密钥(必填)
openai_api_key: str = Field(..., min_length=1)
anthropic_api_key: str = Field(..., min_length=1)
# 模型配置
model_name: str = Field(default="gpt-4")
temperature: float = Field(default=0.7, ge=0, le=2)
max_tokens: int = Field(default=4096, ge=1, le=128000)
# 并发配置
max_concurrent_requests: int = Field(default=10, ge=1, le=100)
request_timeout: float = Field(default=30.0, ge=1)
# 重试配置
max_retries: int = Field(default=3, ge=0)
retry_delay: float = Field(default=1.0, ge=0)
@validator("openai_api_key")
def validate_openai_key(cls, v: str) -> str:
if not v.startswith("sk-"):
raise ValueError("OpenAI API key should start with 'sk-'")
return v
class Config:
env_file = ".env"
env_file_encoding = "utf-8"
# 使用
try:
settings = Settings()
except Exception as e:
raise ValueError(f"Configuration error: {e}")
多环境配置
config/
├── .env.development # 开发环境
├── .env.staging # 测试环境
├── .env.production # 生产环境
└── .env.example # 模板文件
import os
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
# ... 配置项
class Config:
# 根据 ENV 环境变量选择配置文件
env = os.getenv("ENV", "development")
env_file = f"config/.env.{env}"
settings = Settings()
快速启动模板
创建新项目
# 使用 Poetry 创建项目
poetry new llm-project
cd llm-project
# 初始化 git
git init
# 创建目录结构
mkdir -p src/llm_project/{clients,models,services,utils}
mkdir -p tests/{test_clients,test_services}
# 创建配置文件
touch .env.example
touch src/llm_project/__init__.py
touch src/llm_project/config.py
touch tests/conftest.py
# 安装依赖
poetry add openai anthropic pydantic pydantic-settings python-dotenv httpx tenacity
poetry add --group dev pytest pytest-asyncio pytest-cov black ruff mypy pre-commit
一键脚本
创建 setup.sh(Linux/macOS):
#!/bin/bash
PROJECT_NAME=${1:-"llm-project"}
# 创建项目
poetry new $PROJECT_NAME
cd $PROJECT_NAME
# 创建目录结构
mkdir -p src/$PROJECT_NAME/{clients,models,services,utils}
mkdir -p tests/{test_clients,test_services}
# 创建文件
touch .env.example
touch src/$PROJECT_NAME/__init__.py
touch src/$PROJECT_NAME/config.py
touch tests/conftest.py
# 初始化 git
git init
echo "Project $PROJECT_NAME created successfully!"
echo "Next steps:"
echo " 1. cd $PROJECT_NAME"
echo " 2. poetry add openai anthropic pydantic"
echo " 3. Edit .env with your API keys"
创建 setup.ps1(Windows PowerShell):
param(
[string]$ProjectName = "llm-project"
)
# 创建项目
poetry new $ProjectName
Set-Location $ProjectName
# 创建目录结构
$Dirs = @(
"src/$ProjectName/clients",
"src/$ProjectName/models",
"src/$ProjectName/services",
"src/$ProjectName/utils",
"tests/test_clients",
"tests/test_services"
)
foreach ($Dir in $Dirs) {
New-Item -ItemType Directory -Path $Dir -Force | Out-Null
}
# 创建文件
New-Item -ItemType File -Path ".env.example" -Force | Out-Null
New-Item -ItemType File -Path "src/$ProjectName/__init__.py" -Force | Out-Null
New-Item -ItemType File -Path "src/$ProjectName/config.py" -Force | Out-Null
New-Item -ItemType File -Path "tests/conftest.py" -Force | Out-Null
# 初始化 git
git init
Write-Host "Project $ProjectName created successfully!"
Write-Host "Next steps:"
Write-Host " 1. cd $ProjectName"
Write-Host " 2. poetry add openai anthropic pydantic"
Write-Host " 3. Edit .env with your API keys"
小结
本章我们学习了:
- 虚拟环境原理:理解为什么需要虚拟环境和它的工作机制
- 虚拟环境工具:venv、virtualenv、conda 的选择策略
- 依赖管理工具:pip、pip-tools、Poetry、uv 的对比和推荐
- 项目结构:生产级 Python 项目的目录组织
- 环境变量管理:使用 pydantic-settings 进行类型安全的配置管理
参考资料
下一章预告
在下一章《核心语法篇》中,我们将深入学习:
- Python 数据结构的高级用法
- 列表推导、字典推导、生成器表达式
- 生成器与迭代器的原理
- 装饰器的实现与应用
- 上下文管理器与 with 语句
系列持续更新中,欢迎关注!