Что особенного в деплое агента

Прежде чем выбирать площадку, надо понять требования — они отличаются и от классического веб-приложения, и от «настоящего» ML-сервиса.

ТребованиеПочему у агента так
GPU не нуженИнференс — у провайдера LLM. Твой код только оркеструет
Мало CPU/RAMОсновное время процесс ждёт сеть, а не считает
Долгие запросы10–60 секунд на ответ; фоновые задачи — минуты
Много ждущих соединенийСтриминг/WebSocket держат соединение открытым
Критичные секретыУтёкший API-ключ = чужие счета на твоей карте
Исходящая сеть обязательнаБез доступа к API провайдера агент бесполезен
ℹ️ Агент — обычный I/O-bound веб-сервис, а не ML-сервис

Полезная переустановка ожиданий: разворачивать агента не сложнее, чем обычный FastAPI-бэкенд, и гораздо проще, чем модель на GPU. Не ищи ML-специфичные платформы и не закладывай дорогое железо. Главные вопросы при выборе площадки — не «сколько vCPU», а «какой максимальный таймаут запроса», «как хранятся секреты» и «переживёт ли фоновая задача».

База: Docker-образ

Docker — общий знаменатель почти всех площадок: собрал образ один раз, запускаешь где угодно. Для агента образ простой, но есть нюансы, которые отличают учебный Dockerfile от production-ready.

Dockerfile для агента (production-ready)
dockerfile
FROM python:3.12-slim

WORKDIR /app

# 1. Сначала ТОЛЬКО зависимости — слой закэшируется и не будет
#    пересобираться при каждом изменении кода
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 2. Потом код (меняется часто → отдельный слой)
COPY . .

# 3. Не root: если контейнер скомпрометируют, ущерб меньше
RUN useradd -m appuser && chown -R appuser /app
USER appuser

# 4. Health check — платформа должна знать, жив ли сервис
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s \
  CMD python -c "import httpx; httpx.get('http://localhost:8000/health').raise_for_status()"

EXPOSE 8000

# 5. Секреты НЕ в образ! Только через переменные окружения при запуске
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
🔒 Никогда не клади ключи в образ и в репозиторий

Самая дорогая ошибка деплоя. ENV OPENAI_API_KEY=sk-... в Dockerfile, ключ в .env, закоммиченном в git, или в слое образа — всё это утечка: образ можно скачать и распаковать, историю git — прочитать (удаление файла новым коммитом не убирает его из истории). Утёкший ключ находят боты за минуты, и счёт приходит тебе. Правильно: секреты передаются снаружи при запуске — через переменные окружения платформы или менеджер секретов. В репозитории — только .env.example без значений, а .env — в .gitignore.

Куда деплоить: четыре варианта

Площадки различаются по компромиссу «простота ↔ контроль» и — критично для агентов — по ограничению на длительность запроса.

100%
колёсико — масштаб  ·  зажать и тянуть — перемещение
Площадки: простота ↔ контроль проще, быстрее стартовать больше контроля Railway / Render PaaS: git push → работает ✓ минимум настройки ✓ UI для env-переменных ✓ процесс живёт постоянно ✓ ок для стриминга/WS ✗ дороже на масштабе ✗ меньше контроля MVP, пет-проекты, старт самый быстрый путь от кода к рабочему URL Modal serverless для Python/AI ✓ инфраструктура из кода ✓ автомасштабирование ✓ платишь за использование ✓ длинные задачи ок ✗ холодный старт ✗ привязка к платформе батчи, неравномерная нагрузка хорош для фоновых и «пиковых» задач AWS Lambda serverless-функции ✓ платишь только за вызовы ✓ масштаб «из коробки» ✓ вся экосистема AWS ✗ ЛИМИТ ВРЕМЕНИ запроса! ✗ холодный старт ✗ стриминг/WS — сложно короткие задачи, вебхуки ⚠️ долгий агент может не уложиться в лимит VPS / Kubernetes своя инфраструктура ✓ полный контроль ✓ дешевле на масштабе ✓ нет лимитов платформы ✓ приватность данных ✗ всё настраиваешь сам ✗ нужен DevOps-ресурс зрелый прод, комплаенс когда вырос из PaaS или нужен self-hosting Начни с простого (Railway) → переезжай, когда упрёшься в цену/контроль. Docker делает переезд дешёвым.
⚠️ Serverless и долгие агенты — главная несовместимость

Ключевой критерий выбора для агента: максимальная длительность запроса. У функций-as-a-service (в частности AWS Lambda) есть жёсткий потолок времени выполнения, и глубокий research на несколько минут в него может не влезть — функция будет убита на середине. Плюс на serverless сложнее стриминг и WebSocket (нужны отдельные механизмы), а холодный старт добавляет секунды к первому запросу — заметно для интерактивного чата. Вывод: короткие задачи и вебхуки — можно; долгий интерактивный агент — либо площадка с постоянно живущим процессом (Railway/VPS), либо job-паттерн (урок про FastAPI), где HTTP лишь ставит задачу. Конкретные лимиты и цены у всех платформ меняются — сверяйся с актуальной документацией.

Обязательный минимум прода

Развернуть — мало. Есть набор вещей, без которых деплой считается незавершённым.

  • Секреты через окружение. Ключи задаются в настройках платформы или менеджере секретов, не в коде и не в образе. В репозитории — только .env.example.
  • Health check. Эндпоинт /health, по которому платформа понимает, жив ли контейнер, и перезапускает при зависании.
  • Graceful shutdown. При деплое старый процесс должен доработать текущие запросы, а не оборвать их посреди ответа агента.
  • Конфиг через переменные. Модель, лимиты, таймауты, адреса — из окружения, чтобы менять без пересборки образа.
  • Логи в stdout. Пиши JSON-логи в stdout — платформа сама их соберёт (урок про логирование). Не пиши в файлы внутри контейнера: он эфемерен.
  • Observability включена. Трейсинг и метрики (первый раздел модуля) должны работать с первого дня в проде, а не «когда понадобится».
Health check и конфиг из окружения
python
import os
from fastapi import FastAPI

app = FastAPI()

# конфиг — из окружения, с разумными дефолтами (менять без пересборки)
MODEL       = os.environ["AGENT_MODEL"]                    # обязателен → упадём сразу
API_KEY     = os.environ["LLM_API_KEY"]                    # НИКОГДА не хардкодить
TIMEOUT_S   = float(os.getenv("AGENT_TIMEOUT_S", "60"))

@app.get("/health")
async def health():
    """Живой ли процесс — для платформы/оркестратора."""
    return {"status": "ok"}

@app.get("/ready")
async def ready():
    """Готов ли ОБСЛУЖИВАТЬ: проверяем зависимости (БД, кэш).
    Внешний LLM-провайдер здесь лучше НЕ дёргать на каждый чек —
    иначе его сбой начнёт перезапускать твои живые контейнеры."""
    return {"status": "ready" if await db.ping() else "degraded"}
✅ CI/CD: тесты и regression-гейт перед выкаткой

Автоматизируй выкатку так, чтобы в прод не мог попасть непроверенный агент: push → unit + integration тесты (раздел тестирования) → regression на golden dataset (раздел оценки) → сборка образа → деплой. Красный гейт блокирует релиз. И помни про поэтапную раскатку из урока A/B: canary → 10% → 100% с guardrail-метриками и возможностью быстрого отката. Именно связка «тесты в CI + постепенный rollout + мониторинг» превращает деплой из страшного события в рутину.

Синтез: что делает агента production-ready

Этим уроком закрывается модуль. Соберём всё, что мы построили вокруг агента, в одну картину:

          ┌─────────────── PRODUCTION-READY АГЕНТ ───────────────┐
          │                                                       │
 ①  OBSERVABILITY   трейсы (LangSmith/Langfuse/OTel) · structured логи · дашборды
     «я вижу, что происходит»
                              ↓
 ②  ОЦЕНКА КАЧЕСТВА  offline-метрики · human eval · LLM-judge · A/B · regression
     «я знаю, хорошо ли он работает, и не даю деградировать»
                              ↓
 ③  ТЕСТИРОВАНИЕ     unit (компоненты) · integration (стыки) · datasets · trajectory
     «код и стыки корректны, путь агента разумен»
                              ↓
 ④  НАДЁЖНОСТЬ       retry · fallback · rate limiting · timeouts · degradation
     «переживает сбои провайдера, лимиты и зависания»
                              ↓
 ⑤  ОПТИМИЗАЦИЯ      контекст · prompt caching · параллелизация · модель под задачу
     «быстро и по разумной цене»
                              ↓
 ⑥  ДЕПЛОЙ           Docker · площадка · секреты · health · CI/CD · rollout
     «работает в мире, выкатывается безопасно»
          │                                                       │
          └───────── разница между «работает у меня» и «работает у всех» ─────────┘
🎯 Прототип → продукт

Агент из модулей 03–05 умел решать задачу. Модуль 06 добавил всё, что превращает его в продукт: вы видите его работу, измеряете качество и не даёте ему деградировать, тестируете код, переживаете аварии, работаете быстро и экономно и выкатываете безопасно. Ни один из этих слоёв не про «умность» агента — все они про то, чтобы на него можно было положиться. Именно это отличает демо от системы, которой пользуются люди.

Типичные ошибки

❌ Ошибка 1: секреты в образе или репозитории

Ключ в Dockerfile/.env в git — утечка (образ распаковывается, история git читается). Боты находят за минуты, счёт приходит тебе. Только переменные окружения снаружи.

❌ Ошибка 2: serverless с жёстким лимитом для долгого агента

Функцию убивают на середине research'а, стриминг и WebSocket работают плохо, холодный старт бьёт по TTFT. Проверяй максимальную длительность запроса до выбора площадки.

❌ Ошибка 3: нет health check и graceful shutdown

Зависший контейнер не перезапустится, а деплой оборвёт ответы пользователей на середине. Оба механизма — обязательный минимум.

❌ Ошибка 4: логи в файл внутри контейнера

Контейнер эфемерен — логи исчезнут при рестарте и не попадут в агрегатор. Пиши JSON в stdout.

❌ Ошибка 5: деплой без тестов и постепенной раскатки

Выкатка сразу на 100% без regression-гейта — способ узнать о поломке от пользователей. CI-гейт + canary + мониторинг + быстрый откат.

Шпаргалка

Деплой агента — всё в одном месте
text
АГЕНТ = обычный I/O-bound веб-сервис (НЕ ML-сервис!): GPU не нужен, CPU/RAM мало
  главные вопросы к площадке: МАКС. ДЛИТЕЛЬНОСТЬ ЗАПРОСА · секреты · фоновые задачи
  специфика: долгие запросы (10–60с) · много ждущих соединений · критичные ключи

DOCKER (общий знаменатель):
  зависимости ОТДЕЛЬНЫМ слоем (кэш) → потом код · non-root · HEALTHCHECK · EXPOSE
  🔒 СЕКРЕТЫ НЕ В ОБРАЗ И НЕ В GIT (образ распаковывается, история git читается!)
     только env снаружи · в репо — .env.example, .env в .gitignore

ПЛОЩАДКИ (простота → контроль):
  Railway/Render — PaaS, git push, процесс живёт постоянно, ок стриминг/WS
    → MVP, старт · ✗ дороже на масштабе
  Modal — serverless для Python/AI, инфра из кода, автомасштаб, длинные задачи ок
    → батчи, неравномерная нагрузка · ✗ холодный старт, lock-in
  AWS Lambda — платишь за вызовы, масштаб из коробки
    ⚠️ ЖЁСТКИЙ ЛИМИТ ВРЕМЕНИ · стриминг/WS сложно · холодный старт
    → короткие задачи, вебхуки · долгий агент МОЖЕТ НЕ ВЛЕЗТЬ
  VPS/Kubernetes — полный контроль, дешевле на масштабе, приватность
    → зрелый прод, комплаенс · ✗ нужен DevOps
  СТРАТЕГИЯ: начни с простого → переезжай при упоре в цену/контроль (Docker удешевляет переезд)

МИНИМУМ ПРОДА: секреты через env · /health + /ready · graceful shutdown ·
  конфиг из переменных · логи JSON в STDOUT (не в файл — контейнер эфемерен) ·
  observability с первого дня
  ⚠️ в /ready не дёргать LLM-провайдер — его сбой начнёт рестартить твои живые контейнеры

CI/CD: push → unit+integration → REGRESSION на golden → образ → деплой
  + canary → 10% → 100% с guardrails и быстрым откатом

ГРАБЛИ: секреты в образе/git · serverless-лимит для долгого агента ·
        нет health/graceful shutdown · логи в файл · деплой без тестов и canary

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

Задание: разверни агента

  1. Напиши Dockerfile для агента из модулей 03–05: отдельный слой зависимостей, non-root, healthcheck. Собери образ и запусти локально, передав ключи через -e.
  2. Проверь на утечки: нет ли ключей в Dockerfile, в слоях образа, в истории git? Есть ли .env в .gitignore и .env.example в репозитории?
  3. Замерь максимальное время ответа своего агента. Влезет ли оно в лимит выбранной serverless-платформы? Если нет — какой паттерн применишь (job-паттерн или другая площадка)?
  4. Выбери площадку под свой сценарий и обоснуй по таблице: что важнее — скорость старта, цена, контроль, приватность?
  5. Добавь /health и /ready. Что проверяешь в ready, а что намеренно НЕ проверяешь и почему?
  6. Разверни агента на выбранной площадке. Убедись, что: секреты заданы снаружи, логи видны в панели, трейсинг работает в проде.
  7. Со звёздочкой: собери CI/CD-пайплайн: тесты → regression-гейт на golden dataset → сборка → деплой. Проверь, что сломанный regression блокирует выкатку.

Что дальше

Раздел «Оптимизация и деплой» закрыт, а с ним — вся теория модуля 06. Твой агент теперь наблюдаем, измерим, протестирован, надёжен, оптимизирован и развёрнут. Остался финальный аккорд — проект модуля: взять агента из модуля 03 и довести его до настоящего прода — с полным мониторингом, тестами и CI/CD-пайплайном, собрав все шесть слоёв воедино.