Почему это важно для AI-проектов

В AI-разработке проблема зависимостей острее, чем в обычном веб-проекте:

Тяжёлые пакеты

torch, transformers, langchain — гигабайты. Медленная установка без кэша убивает CI/CD

⚠️

Конфликты версий

langchain требует одну версию pydantic, а твой код — другую. Это реальная проблема

🔁

Воспроизводимость

Агент работал вчера — сегодня нет. Причина: обновилась зависимость третьего уровня

🌍

Разные окружения

Ноутбук разработчика, сервер prod, Docker-контейнер — должны быть идентичны

Типичная структура зависимостей AI-агента:

agent.py
    ├── openai            → httpx → certifi → h2 → ...
    ├── anthropic         → httpx → anyio → sniffio → ...
    ├── langgraph         → langchain-core → pydantic → ...
    ├── pydantic-settings → pydantic → ...
    ├── chromadb          → onnxruntime → numpy → ...
    └── tavily-python     → requests → urllib3 → ...

~150+ транзитивных зависимостей в реальном проекте

Виртуальные окружения: обязательная база

Прежде чем разбирать инструменты — нужно понять зачем нужны виртуальные окружения. Без них все пакеты устанавливаются глобально в системный Python — это хаос:

Проблема без venv и решение с venv
bash
# ❌ БЕЗ venv — всё глобально, конфликты неизбежны
pip install langchain       # устанавливает pydantic 2.5
pip install old-project     # требует pydantic 1.10 — КОНФЛИКТ!

# ✅ С venv — каждый проект изолирован

# Создать окружение
python -m venv .venv

# Активировать (Linux/macOS)
source .venv/bin/activate

# Активировать (Windows)
.venv\Scripts\activate

# Теперь pip устанавливает только в .venv
pip install langchain   # изолировано от других проектов

# Деактивировать
deactivate

# Проверить какой Python активен
which python    # должен указывать на .venv/bin/python
Соглашение по имени

Называй виртуальное окружение .venv (с точкой). Это стандарт, который понимают VS Code, PyCharm, GitHub Actions и большинство инструментов. Добавь .venv/ в .gitignore.

pip + requirements.txt: классика

Стандартный инструмент Python. Прост, везде установлен, но имеет ограничения для больших проектов:

Базовые команды

pip — основные команды
bash
# Установка пакета
pip install httpx
pip install "httpx>=0.27"           # Минимальная версия
pip install "httpx>=0.27,<1.0"      # Диапазон версий
pip install "httpx[http2]"          # С опциональными зависимостями

# Установка конкретной версии (для воспроизводимости)
pip install httpx==0.27.0

# Установка из файла
pip install -r requirements.txt

# Удаление
pip uninstall httpx

# Список установленных пакетов
pip list
pip show httpx   # Подробная информация о пакете

# Что зависит от пакета
pip show httpx | grep Requires-Dist

requirements.txt — два файла, не один

Хорошая практика — разделить прямые зависимости и заморозку версий:

requirements.in + requirements.txt — правильный паттерн
bash
# requirements.in — только ПРЯМЫЕ зависимости (коммитим в Git)
# Пишем сами, указываем ограничения если нужно
openai>=1.0
anthropic>=0.30
langchain>=0.3
pydantic>=2.0
httpx>=0.27
pydantic-settings
python-dotenv
tenacity
requirements.txt — полная заморозка со всеми транзитивными
bash
# requirements.txt — ГЕНЕРИРУЕМ командой (коммитим в Git)
pip freeze > requirements.txt

# Содержимое:
# annotated-types==0.7.0
# anyio==4.4.0
# certifi==2024.8.30
# h11==0.14.0
# httpcore==1.0.5
# httpx==0.27.0
# ...
# (все 150+ пакетов с точными версиями)

# Воспроизведение среды на другой машине
pip install -r requirements.txt
⚠️ Главный минус pip

Нет встроенного разрешения конфликтов при установке: pip может установить несовместимые версии и не предупредить. Также нет разделения dev/prod зависимостей без ручных ухищрений (requirements-dev.txt и т.п.).

uv — современный стандарт (рекомендован)

uv — инструмент от Astral (авторы ruff), написанный на Rust. В 2024–2025 годах стал новым стандартом для Python-проектов. Заменяет pip, venv, pip-tools и отчасти pyenv — один инструмент вместо пяти.

uv заменяет целый стек:

Раньше:  pyenv + python-build + venv + pip + pip-tools
Теперь:  uv  ← всё в одном, в 10–100x быстрее

Установка uv

Установка uv
bash
# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

# Windows (PowerShell)
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

# Через pip (если уже есть)
pip install uv

# Проверка
uv --version   # uv 0.5.x

Создание нового AI-проекта

uv init — новый проект за секунды
bash
# Создать новый проект
uv init my-agent
cd my-agent

# Структура после init:
# my-agent/
# ├── .python-version   ← версия Python для проекта
# ├── pyproject.toml    ← конфигурация проекта и зависимости
# ├── README.md
# └── src/
#     └── my_agent/
#         └── __init__.py

# Добавить Python нужной версии (uv скачает сам если нет!)
uv python install 3.12
uv python pin 3.12        # Записывает в .python-version

# Создать venv и установить зависимости
uv sync                   # Читает pyproject.toml, создаёт .venv

Управление зависимостями

uv add / remove — управление пакетами
bash
# Добавить зависимость (обновляет pyproject.toml и uv.lock)
uv add openai
uv add "anthropic>=0.30"
uv add "httpx[http2]"

# Добавить dev-зависимость (только для разработки)
uv add --dev pytest pytest-asyncio ruff mypy

# Добавить зависимость для конкретной группы
uv add --group notebooks jupyter ipykernel

# Удалить пакет
uv remove langchain

# Обновить пакет до последней версии
uv add openai --upgrade

# Обновить все пакеты
uv lock --upgrade

# Установить зависимости из pyproject.toml (после git clone)
uv sync

# Только prod зависимости (без dev, для Docker)
uv sync --no-dev

Запуск кода и скриптов

uv run — запуск в изолированном окружении
bash
# Запустить скрипт в venv проекта (не нужно активировать!)
uv run python agent.py
uv run python -m pytest
uv run ruff check .

# Запустить инструмент без установки в проект (как npx)
uvx ruff check .           # Запускает ruff во временном окружении
uvx mypy src/

# Запустить скрипт с inline зависимостями (uv script)
# В начале скрипта:
# /// script
# requires-python = ">=3.11"
# dependencies = ["httpx", "pydantic"]
# ///
uv run my_script.py        # uv сам установит зависимости!

pyproject.toml — конфиг AI-проекта

pyproject.toml для типичного AI-агента
toml
[project]
name = "my-agent"
version = "0.1.0"
description = "AI Agent with LangGraph and RAG"
requires-python = ">=3.11"
dependencies = [
    # LLM провайдеры
    "openai>=1.50",
    "anthropic>=0.40",
    # Фреймворки агентов
    "langgraph>=0.2",
    "langchain-core>=0.3",
    # Данные и валидация
    "pydantic>=2.9",
    "pydantic-settings>=2.5",
    # HTTP и утилиты
    "httpx>=0.27",
    "python-dotenv>=1.0",
    "tenacity>=9.0",
    # Vector DB
    "chromadb>=0.5",
]

[dependency-groups]
dev = [
    "pytest>=8.0",
    "pytest-asyncio>=0.24",
    "pytest-cov>=5.0",
    "ruff>=0.7",
    "mypy>=1.11",
    "ipykernel",
]

[tool.uv]
# Пакеты которые не хотим случайно обновить
constraint-dependencies = [
    "pydantic>=2.0,<3.0",
]

# Настройки линтера ruff (бонус — раз уж мы в pyproject.toml)
[tool.ruff]
line-length = 100
target-version = "py311"

[tool.ruff.lint]
select = ["E", "F", "I", "UP"]   # pycodestyle, pyflakes, isort, pyupgrade

# Настройки pytest
[tool.pytest.ini_options]
asyncio_mode = "auto"             # pytest-asyncio: автоматический режим
testpaths = ["tests"]

# Настройки mypy
[tool.mypy]
python_version = "3.11"
strict = true
ignore_missing_imports = true

uv.lock — воспроизводимые сборки

uv.lock — файл заморозки зависимостей
bash
# uv.lock создаётся автоматически при uv add / uv sync
# Содержит точные версии ВСЕХ зависимостей (включая транзитивные)
# Кроссплатформенный — один файл для Linux/macOS/Windows

# ✅ КОММИТИМ в Git (в отличие от requirements.txt с pip freeze)
git add uv.lock

# Установить точно те же версии что в lock-файле
uv sync --frozen     # Не обновляет lock, использует как есть

# Проверить что lock актуален (в CI)
uv lock --check      # Выходит с ошибкой если pyproject.toml изменился
uv.lock vs requirements.txt

uv.lock — кроссплатформенный, машиночитаемый, понимает разные ОС и архитектуры. pip freeze — платформоспецифичный снэпшот текущей среды. Для нового проекта всегда предпочитай uv.lock.

poetry — альтернатива с богатой экосистемой

poetry появился раньше uv и до сих пор широко используется. Если видишь в проекте pyproject.toml с секцией [tool.poetry] — это poetry-проект.

Установка и создание проекта

poetry — установка и базовые команды
bash
# Установка
curl -sSL https://install.python-poetry.org | python3 -

# Создание нового проекта
poetry new my-agent
cd my-agent

# Или инициализация в существующей директории
poetry init

# Добавить зависимость
poetry add openai
poetry add anthropic langchain pydantic-settings
poetry add --group dev pytest ruff mypy

# Установить все зависимости (создаёт venv автоматически)
poetry install

# Запустить в окружении проекта
poetry run python agent.py
poetry run pytest

# Активировать shell окружения
poetry shell

# Показать дерево зависимостей
poetry show --tree

# Обновить пакет
poetry update openai

pyproject.toml в стиле poetry

pyproject.toml с poetry-секцией
toml
[tool.poetry]
name = "my-agent"
version = "0.1.0"
description = "AI Agent"
authors = ["Your Name "]

[tool.poetry.dependencies]
python = "^3.11"
openai = "^1.50"
anthropic = "^0.40"
langgraph = "^0.2"
pydantic = "^2.9"
pydantic-settings = "^2.5"
httpx = "^0.27"
python-dotenv = "^1.0"
tenacity = "^9.0"

[tool.poetry.group.dev.dependencies]
pytest = "^8.0"
pytest-asyncio = "^0.24"
ruff = "^0.7"
mypy = "^1.11"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
Критерий uv poetry pip + venv
Скорость установки ⚡ 10–100x быстрее 🐢 Медленнее pip Базовая
Lock-файл ✅ uv.lock (кроссплатформ.) ✅ poetry.lock ⚠️ pip freeze вручную
Dev/prod группы ❌ вручную
Управление версиями Python ✅ встроено ⚠️ нужен pyenv ❌ нужен pyenv
Совместимость с pip ✅ полная ✅ полная ✅ нативно
Publish в PyPI ✅ встроено ⚠️ twine отдельно
Рекомендован для новых проектов ✅ 2025 Существующие проекты Простые скрипты

Структура AI-проекта: полный шаблон

my-agent/
├── .python-version       ← "3.12" (для uv)
├── pyproject.toml        ← конфиг, зависимости, инструменты
├── uv.lock               ← заморозка (коммитим!)
├── .env.example          ← шаблон конфига (коммитим)
├── .gitignore            ← .venv, .env, __pycache__, ...
│
├── src/
│   └── agent/
│       ├── __init__.py
│       ├── main.py           ← точка входа
│       ├── config.py         ← Settings(BaseSettings)
│       ├── tools.py          ← инструменты агента
│       └── http_client.py    ← AgentHttpClient
│
├── tests/
│   ├── conftest.py
│   └── test_tools.py
│
└── Makefile              ← shortcuts: make install, make test, make lint

Makefile — удобные команды

Makefile для AI-проекта на uv
makefile
.PHONY: install sync run test lint fmt typecheck clean

# Установить всё (первый запуск)
install:
	uv sync --all-groups

# Синхронизировать зависимости (после git pull)
sync:
	uv sync

# Запустить агента
run:
	uv run python src/agent/main.py

# Запустить тесты
test:
	uv run pytest tests/ -v

# Запустить тесты с покрытием
test-cov:
	uv run pytest tests/ --cov=src --cov-report=html

# Проверить стиль кода
lint:
	uv run ruff check src/ tests/

# Автоисправить стиль
fmt:
	uv run ruff format src/ tests/
	uv run ruff check --fix src/ tests/

# Проверить типы
typecheck:
	uv run mypy src/

# Очистить кэш
clean:
	find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null; true
	find . -type d -name .pytest_cache -exec rm -rf {} + 2>/dev/null; true

Docker и зависимости

При деплое агента в Docker важно правильно кэшировать слои — установка зависимостей не должна повторяться при каждом изменении кода:

Dockerfile с uv — оптимальное кэширование слоёв
dockerfile
FROM python:3.12-slim

# Устанавливаем uv
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv

WORKDIR /app

# Копируем ТОЛЬКО файлы зависимостей — слой кэшируется
# пока pyproject.toml и uv.lock не изменились
COPY pyproject.toml uv.lock ./

# Устанавливаем зависимости (без dev-группы для prod)
RUN uv sync --frozen --no-dev

# Копируем исходный код — этот слой инвалидируется при каждом изменении
COPY src/ ./src/

# Запускаем через uv run (не нужно активировать venv)
CMD ["uv", "run", "python", "src/agent/main.py"]
ℹ️ Порядок слоёв важен

Docker кэширует слои последовательно. Если сначала скопировать весь код, а потом установить зависимости — при каждом изменении кода Docker будет переустанавливать все пакеты. Правильный порядок: сначала файлы зависимостей → установка → потом исходный код.

CI/CD: GitHub Actions

.github/workflows/test.yml — тесты с uv
yaml
name: Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      # Устанавливаем uv (быстро, ~2 секунды)
      - name: Install uv
        uses: astral-sh/setup-uv@v3
        with:
          version: "latest"
          enable-cache: true        # Кэшировать .venv между запусками

      # Python версия из .python-version
      - name: Set up Python
        run: uv python install

      # Установить зависимости (используется uv.lock)
      - name: Install dependencies
        run: uv sync --frozen --all-groups

      # Линтер
      - name: Lint
        run: uv run ruff check src/ tests/

      # Типы
      - name: Type check
        run: uv run mypy src/

      # Тесты
      - name: Run tests
        run: uv run pytest tests/ -v --cov=src
        env:
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

Полный .gitignore для AI-проекта

.gitignore — что никогда не попадает в репозиторий
bash
# Виртуальные окружения
.venv/
venv/
env/
.env/

# Секреты — НИКОГДА не коммитим!
.env
.env.local
.env.*.local

# Python кэш
__pycache__/
*.py[cod]
*.pyo
.pytest_cache/
.mypy_cache/
.ruff_cache/

# Данные и состояние агента (обычно не нужны в Git)
data/
*.json
!.env.example   # Исключение: шаблон конфига коммитим

# Jupyter
.ipynb_checkpoints/
*.ipynb         # Решай сам — бывает нужно коммитить ноутбуки

# Coverage
htmlcov/
.coverage
coverage.xml

# IDE
.idea/
.vscode/        # Или добавь только .vscode/settings.json
*.swp

# OS
.DS_Store
Thumbs.db

# Сборка
dist/
build/
*.egg-info/

Шпаргалка

Dependency management cheatsheet
bash
# ── uv (рекомендован для новых проектов) ─────────────
uv init my-agent           # Новый проект
uv python install 3.12     # Установить Python
uv python pin 3.12         # Зафиксировать версию

uv add openai              # Добавить зависимость
uv add --dev pytest ruff   # Dev-зависимость
uv remove langchain        # Удалить

uv sync                    # Установить все зависимости
uv sync --frozen           # Строго по lock-файлу (CI)
uv sync --no-dev           # Без dev (Docker prod)

uv run python agent.py     # Запустить (без активации venv)
uv run pytest              # Запустить тесты
uvx ruff check .           # Запустить инструмент без установки

uv lock --upgrade          # Обновить все пакеты
uv lock --check            # Проверить что lock актуален

# ── poetry (существующие проекты) ─────────────────────
poetry add openai          # Добавить
poetry add --group dev ruff
poetry install             # Установить всё
poetry run python agent.py # Запустить
poetry shell               # Активировать venv
poetry show --tree         # Дерево зависимостей

# ── pip + venv (скрипты и legacy) ─────────────────────
python -m venv .venv       # Создать venv
source .venv/bin/activate  # Активировать (Linux/macOS)
.venv\Scripts\activate     # Активировать (Windows)

pip install httpx          # Установить
pip install -r requirements.txt
pip freeze > requirements.txt

# ── .gitignore must-have ──────────────────────────────
# .venv/   .env   __pycache__/   .pytest_cache/

Практическое задание

Задание: настрой AI-проект с нуля

  1. Установи uv и создай новый проект командой uv init my-agent. Зафиксируй Python 3.12
  2. Добавь зависимости из этого модуля: openai, anthropic, pydantic-settings, httpx, python-dotenv, tenacity
  3. Добавь dev-зависимости: pytest, pytest-asyncio, ruff, mypy
  4. Создай .env.example с шаблоном переменных и правильный .gitignore
  5. Напиши Makefile с командами install, run, test, lint, fmt
  6. Напиши простой Dockerfile с правильным порядком слоёв для кэширования зависимостей

Модуль 01 завершён!

🎉 Подраздел «Python для AI Engineers» пройден

Ты изучил все инструменты Python-фундамента: асинхронность (asyncio), типизацию и валидацию (Pydantic), конфигурацию (JSON/ENV/.env), HTTP-запросы (httpx) и организацию проекта (uv). Теперь — к ядру AI-агентов.