Библиотека · Надёжность: мониторинг, сбои, резервные копии

Production Observability — что мониторить когда агент в проде

Инженер60 минОбновлено: октябрь 2026
89 из 105 в библиотеке

Время: ~25 мин теории + 35 мин практики


Суть урока

"It works on my machine" — самая дорогая фраза индустрии. Ты задеплоил агента, он работает, клиенты пользуются. А потом приходит сообщение: "оно сломалось ещё вчера вечером". И ты понимаешь — узнал об этом не из своей системы, а от обиженного пользователя.

Production observability — это твои глаза и уши в работающую систему. Без них ты слепой пилот: двигатель работает, но ты не знаешь когда он перегреется, когда закончится топливо, когда отвалится крыло.

В этом уроке — 5 метрик которые ОБЯЗАН мониторить, 3 уровня alerting, 4 инструмента для AI-агентов (список на октябрь 2026). Без воды, с примерами цифр и dashboard mockup'ами. Пороги в уроке — отправная точка: со временем подбери свои по реальным данным.

🎨 Образ: самолёт без приборной панели. Двигатель работает, ты летишь. Но температура двигателя растёт. Топливо заканчивается. Высота снижается. Без панели приборов ты узнаешь только когда что-то загорится. Observability — приборная панель твоего AI-агента. Не роскошь, а условие что ты вообще можешь лететь.


🎯 Главный принцип: не logs, а signals

Logging ≠ observability. Можешь иметь гигабайты логов и не понимать что происходит. Observability — это способность отвечать на вопросы о системе не залезая в код.

Три классических столпа (per OpenTelemetry стандарт https://opentelemetry.io):

  1. Metrics — числа во времени (latency, cost, errors)
  2. Traces — путь одного запроса через всю систему
  3. Logs — события с контекстом

Для AI-агентов добавляется четвёртый:

  1. LLM-specific — prompts, completions, token usage, cache hits

🎨 Образ: Metrics — это пульс и температура пациента (общее состояние). Traces — это рентген конкретной кости (детальный путь одной проблемы). Logs — это карточка с историей болезни. LLM-specific — это анализ крови на специфические маркеры именно для AI-пациента.


Ключевые концепции

  • p50 / p95 / p99 — перцентили latency: половина запросов быстрее p50, 95% быстрее p95, 99% быстрее p99. p99 показывает worst case который видят твои хуже обслуженные пользователи
  • Cardinality — количество уникальных значений в метрике. High-cardinality метрики (per-user) дорогие в хранении
  • Sampling — записывать не 100% трейсов, а 1-10% для нормальных + 100% для ошибок
  • Alert fatigue — состояние когда алертов столько что игнорируешь всё. Опаснее чем отсутствие алертов
  • SLI / SLO / SLA — Service Level Indicator (метрика), Objective (внутренняя цель), Agreement (контракт с клиентом)
  • Anomaly detection — отклонение от baseline (вчерашнее среднее × 2 = подозрительно)
  • Trace ID — уникальный идентификатор запроса проходящий через все компоненты для correlation
  • Cache hit ratio — % запросов попавших в prompt cache. Прямой влияет на cost

Теория

5 mandatory metrics

Это минимум. Без них ты не понимаешь что происходит с твоим агентом в проде.


Metric 1: Latency (время отклика)

Что мерить: p50, p95, p99 response time per request

Targets 2026:

Тип агента p50 p95 p99
Chat (text) <3s <8s <15s
Voice (real-time) <500ms <1s <2s
Batch (background) OK 1-24h OK 1-24h OK 1-24h
API (B2B integration) <1s <3s <5s

Почему p99 критичнее p50: если у тебя 1000 запросов в день и p99 = 30s, это значит 10 пользователей в день ждут полминуты. Они уходят. p50 = 2s выглядит красиво в отчёте, но скрывает проблему.

Tools для отслеживания:

  • LangSmith (https://www.langchain.com/langsmith) — трейсинг LLM-вызовов, есть бесплатный тариф (лимиты на сайте)
  • Helicone (https://www.helicone.ai/) — LLM-прокси с метриками; в марте 2026 компанию купила Mintlify, сервис работает в режиме поддержки без новых функций
  • Custom Prometheus/Grafana — self-hosted, бесплатно но time-sink на setup

🎨 Образ: p50 — это среднее время в пробке для большинства водителей. p99 — это сколько ждёт самый невезучий. Если в среднем 5 минут, но 1% водителей стоит час — это сломанный светофор который тебе никто не докладывает потому что "в целом нормально".


Metric 2: Cost per interaction

Что мерить:

  • $/conversation (одна сессия пользователя)
  • $/user (накопительно за месяц)
  • $/feature (где деньги уходят)
  • Total monthly burn (общий счёт)

Anomaly threshold: spike >2x daily average → alert. Если вчера тратил $20, а сегодня к обеду уже $80 — что-то не так. Возможно:

  • Багой ввели infinite loop вызовов
  • Кто-то нашёл способ abuse (prompt injection, repeated requests)
  • Switched model в коде с Haiku на Opus случайно

Tools:

  • Anthropic Console (https://platform.claude.com) — встроенный billing dashboard
  • LangSmith / Helicone — стоимость каждого вызова с разбивкой по пользователю и функции
  • Custom KV logger — самописный счётчик в Cloudflare KV / Redis

Cost-saving signals которые видны через мониторинг:

  • Cache hit ratio низкий (<30%) → пересмотри prompt structure
  • Output tokens растут быстрее input → агент стал болтливее (пересмотри system prompt)
  • Opus calls >20% от total → проверь не используешь ли Opus там где хватит Sonnet

Metric 3: Error rate

Что мерить (4 категории):

  1. API errors — 4xx, 5xx от Anthropic/OpenAI
  2. Tool failures — MCP timeouts, schema mismatches, tool exceptions
  3. Validation failures — LLM output не matches expected JSON schema
  4. User-reported errors — explicit feedback "не работает"

Target: <1% error rate в steady state, <5% при spike

Alert thresholds:

  • Error rate >5% за 5 минут → page on-call (что-то сломалось сейчас)
  • Error rate >2% за 1 час → warning (degradation тренд)
  • Single error code >50 events/час → investigate (системная проблема)

Категоризация важна: разные ошибки требуют разной реакции:

Error type Action
529 overloaded_error (Anthropic) Retry с backoff, не наша вина
400 invalid_request_error Bug в коде, fix immediately
429 rate_limit_error Поднять tier или throttle
tool_use schema mismatch LLM нестабилен, добавить validation
JSON parse error System prompt пересмотр

🎨 Образ: error rate — это температура у больного. 37° (1%) — норма. 38° (2%) — насморк. 39° (5%) — везти к врачу немедленно. И важно не только цифру видеть, но и понять — это грипп, аллергия или аппендицит.


Metric 4: Token usage

Что мерить:

  • Input tokens / Output tokens (per request + aggregate)
  • Cache hit ratio (% попавших в prompt cache)
  • Per-model breakdown (% Haiku / % Sonnet / % Opus)
  • Context length distribution (видишь когда люди упираются в limit)

Anomaly signals:

Signal Что значит
Input tokens >5x avg для one user Loop bug, scraping, prompt injection attack
Cache hit <20% Prompt structure не оптимизирован
Avg output tokens растут неделю System prompt деградирует, агент стал болтливее
Context >150K на постоянной основе Time для compaction strategy

Cache hit ratio — критическая метрика: чтение из prompt cache стоит около 10% от обычной цены входных токенов (на октябрь 2026; актуальные условия: Актуальное сейчас). Если cache hit высокий, большая часть входа обходится в разы дешевле. Если cache hit = 0%, платишь полную ставку.

python
# Tracking cache hit ratio
def log_request(response):
    cache_tokens = response.usage.cache_read_input_tokens or 0
    total_input = response.usage.input_tokens + cache_tokens
    cache_ratio = cache_tokens / total_input if total_input > 0 else 0

    metrics.record("cache.hit_ratio", cache_ratio)
    metrics.record("tokens.input", response.usage.input_tokens)
    metrics.record("tokens.output", response.usage.output_tokens)

Metric 5: Business metrics

Технические метрики показывают что система работает. Business metrics показывают что система работает на бизнес.

Что мерить:

Метрика Описание Target
Conversation completion rate % сессий достигнувших цели >70%
CSAT (customer satisfaction) Explicit feedback 1-5 stars >4.0
Escalation rate % случаев "позвать человека" <15%
Conversion rate Для sales/marketing AI Variable
Time-to-resolution Сколько ходов до решения <5
Retention % вернувшихся пользователей >30% week-2

Tools:

  • PostHog (https://posthog.com) — product analytics, есть бесплатный месячный лимит (текущий размер — на странице тарифов)
  • Mixpanel (https://mixpanel.com) — анализ воронок, тарифы на сайте

Почему business metrics важнее technical: ты можешь иметь p95 = 1s и error rate 0.5% — но если conversation completion = 20%, твой агент не помогает пользователям. Технически здоров — фактически бесполезен.


3 уровня alerting

Алерты — самая частая причина ошибок production AI-систем. Либо слишком много (alert fatigue), либо слишком мало (узнал от клиента).


Level 1: Info (Slack channel, не paging)

Что: daily summary, weekly reports, общая телеметрия Канал: #ai-prod-info или email digest Response time: когда придёт время

Примеры:

  • Daily 09:00: "Вчера: 1247 запросов, $12.40 spend, 0.3% error rate, p95 = 4.2s"
  • Weekly Monday: "За неделю: cost trend +12%, top error: tool timeout (43 events)"
  • Monthly: "Месячный отчёт по pricing optimization"

Цель: контекст и тренды, не реактивный мониторинг.


Level 2: Warning (Slack mention, response within 1 hour)

Что: degradation сигналы, проблемы которые могут стать критическими Канал: #ai-prod-alerts + @here Response time: 1 час

Примеры:

  • Cost spike 2x daily avg
  • Error rate >2% за 15 минут
  • Latency p95 >2x SLA
  • Cache hit ratio упал ниже 30%
  • Single user >100 requests за час (potential abuse)

Tool: Slack incoming webhook + structured message

python
# Пример отправки warning
def send_warning(metric, value, threshold):
    slack_webhook = os.getenv("SLACK_WARNING_WEBHOOK")
    payload = {
        "text": f"@here Warning: {metric} = {value} (threshold: {threshold})",
        "attachments": [{
            "color": "warning",
            "fields": [
                {"title": "Metric", "value": metric, "short": True},
                {"title": "Current", "value": str(value), "short": True},
                {"title": "Threshold", "value": str(threshold), "short": True},
                {"title": "Dashboard", "value": "https://ссылка-на-твой-dashboard", "short": True}
            ]
        }]
    }
    requests.post(slack_webhook, json=payload)

Level 3: Critical (page on-call, response within 5 min)

Что: customer-impacting, system down, security incidents Канал: PagerDuty / phone call / SMS Response time: 5 минут

Примеры:

  • System down (>50% errors)
  • Cost spike >5x daily (potential breach или infinite loop)
  • Security alert (unusual access pattern, leaked key suspected)
  • Customer-reported outage с подтверждением метриками
  • Critical SLA breach

Tool:

  • PagerDuty (https://www.pagerduty.com/) — индустриальный стандарт, платно (цены на сайте)
  • Grafana Cloud IRM (https://grafana.com/docs/grafana-cloud/alerting-and-irm/irm/) — продолжение Grafana OnCall: версия OnCall с открытым кодом заморожена и в марте 2026 архивирована. Для одиночки на старте хватает Slack-уведомлений и звонка на телефон

🎨 Образ: три уровня — как пожарная сигнализация. Дымок на кухне (Info) — знать, не паниковать. Запах гари в коридоре (Warning) — проверить и потушить. Огонь на этаже (Critical) — звонить 911, эвакуация. Если каждый дымок будит пожарную команду, к настоящему пожару они приедут уставшие и злые.


4 observability tools 2026 — сравнение

Tool Бесплатный тариф Лучше для
LangSmith Есть, лимиты смотри на сайте Advanced tracing, prompt comparison
Helicone Есть; с марта 2026 сервис в режиме поддержки (компанию купила Mintlify), новых функций нет LLM-specific, cost tracking, быстрый setup
Sentry Есть, лимиты смотри на сайте Error tracking, не LLM-specific
PostHog Есть месячный лимит для аналитики продукта (текущий размер — на сайте) User analytics, не traces

Цены платных тарифов у всех четырёх меняются, смотри на сайтах сервисов.

Рекомендация по этапам:

  • Personal / starter (<1K users): бесплатный тариф LangSmith или PostHog плюс Anthropic Console — этого хватает на первые месяцы
  • Team (1K-10K users): LangSmith + Sentry
  • Production (есть выручка): LangSmith + Sentry + PostHog + инструмент для on-call (PagerDuty или аналог)
  • Enterprise: Datadog (https://www.datadoghq.com/) + custom dashboards

Дополнительно:


Implementation pattern — прокси на примере Helicone

Один из самых быстрых способов получить observability — обернуть Anthropic SDK через прокси, например Helicone. Setup занимает 5 минут.

⚠️ На октябрь 2026 Helicone работает в режиме поддержки (см. выше), поэтому смотри на него как на пример подхода: прокси между кодом и API плюс метки в заголовках. Для нового проекта сравни с LangSmith (урок MLOps для indie) и со шлюзами вроде AI Gateway у Cloudflare. Адрес прокси и названия заголовков сверяй с документацией выбранного сервиса.

До (no observability):

python
from anthropic import Anthropic

client = Anthropic()
response = client.messages.create(
    model="claude-sonnet-5-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Привет"}]
)

После (Helicone wrapping):

python
from anthropic import Anthropic
import os

client = Anthropic(
    base_url="https://anthropic.helicone.ai",  # Proxy через Helicone
    default_headers={
        "Helicone-Auth": f"Bearer {os.getenv('HELICONE_KEY')}",
        "Helicone-User-Id": user_id,                    # Per-user tracking
        "Helicone-Property-Feature": "chat-bot",        # Feature breakdown
        "Helicone-Property-Environment": "production",  # Env tagging
        "Helicone-Cache-Enabled": "true",               # Bonus: caching
        "Helicone-Property-Tier": user_tier             # Custom dimension
    }
)

response = client.messages.create(
    model="claude-sonnet-5-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Привет"}]
)
# Теперь видно в dashboard: latency, cost, tokens, user, feature, environment

Что появляется в dashboard сразу:

  • Каждый request с trace ID
  • Cost per request с breakdown
  • Latency p50/p95/p99
  • Top users by spend
  • Top features by usage
  • Cache hit ratio

Dashboard structure — что должно быть на главном экране

Хороший production dashboard ты смотришь раз в день, 30 секунд, понимаешь всё.

Код
┌──────────────────────────────────────────────────────────┐
│ My App Production Dashboard             [Last 24h ▼]     │
├──────────────────────────────────────────────────────────┤
│                                                           │
│  📊 LAST 24H OVERVIEW                                     │
│  ┌─────────┬─────────┬─────────┬─────────┐               │
│  │ 1,247   │ $12.40  │  0.3%   │  4.2s   │               │
│  │ requests│  spend  │ errors  │   p95   │               │
│  └─────────┴─────────┴─────────┴─────────┘               │
│                                                           │
│  📈 TREND (7 days)                                        │
│  Cost:    ▁▂▃▃▄▅▆  +12% wow                              │
│  Errors:  ▁▁▂▁▁▁▁  stable                                │
│  p95:     ▃▃▃▃▃▃▃  stable                                │
│                                                           │
│  🚨 ACTIVE ALERTS                                         │
│  • [WARN] Cache hit ratio 24% (target >30%)              │
│                                                           │
│  🐢 TOP ISSUES                                            │
│  1. Slowest endpoint: /api/research (p95 = 18s)          │
│  2. Most errors: tool_timeout (43 events)                │
│  3. Biggest spender: user_42 ($3.20 today, 25% of total) │
│                                                           │
│  😊 USER SATISFACTION                                     │
│  CSAT: 4.3 / 5.0  (n=87)                                 │
│  Escalation rate: 12%                                     │
│                                                           │
└──────────────────────────────────────────────────────────┘

Правила хорошего dashboard:

  • Главные числа сверху, на одном экране, без скролла
  • Тренды визуально (sparkline), не таблицами
  • Active alerts видны сразу — красным
  • Top issues подсказывают где копать
  • Business metric (CSAT) равноправно с техническими

Debugging workflow — от жалобы до фикса

Сценарий: пользователь пишет "AI ответил неправильно в 14:30"

Step 1: Locate — найди в logs traces around 14:30 для этого user

Напиши в чат
# В дашборде трейсинга: фильтр user_id = user_42, время 14:25 — 14:35

Step 2: Reproduce — что был input, что был context, что output

  • Возьми exact prompt из trace
  • Запусти в Anthropic Console playground с теми же параметрами
  • Получи тот же (или другой) результат

Step 3: Correlate — с system metrics в это время

  • Был ли latency spike? (медленный = меньше времени думать)
  • Был ли error spike в API? (degraded service)
  • Был ли cost spike? (loop bug в этот период)
  • Был ли cache miss? (cold cache → разное поведение)

Step 4: Hypothesize cause — варианты:

  • Context overflow (>180K tokens)? → compaction strategy
  • Bad data (corrupt input)? → input validation
  • Bug в системе (race condition)? → unit test
  • LLM degradation (model update)? → eval suite check
  • Prompt drift (что-то изменилось)? → version control prompts

Step 5: Fix + prevent

🎨 Образ: debugging — это медицинский диагноз. Симптом (жалоба) → анамнез (traces) → анализы (metrics) → диагноз (cause) → лечение (fix) + рекомендации (prevention). Без observability ты как врач без анализов — гадаешь.


Logging best practices

✅ Что логировать:

  • All LLM requests/responses (input, output, tokens, latency, cost)
  • All tool calls (name, args, result, duration)
  • All errors с full stack trace
  • User actions (без PII — pseudonymize)
  • System events (deploy, config change, restart)

❌ Что НЕ логировать:

  • Plain passwords / API keys
  • Full PII (емейлы → hash, name → "User_42")
  • Credit card numbers
  • Health data в full content
  • Internal IPs / system paths (security)

Sampling strategy:

  • 100% errors (always)
  • 5-10% normal traces (cost balance)
  • 100% slow requests (>2x p95)
  • 100% high-cost requests (>$0.50)

Retention policy:

Тип лога Хранить
Errors 90 days
Normal traces 30 days
Sampled traces (для trends) 1 year
Audit logs (compliance) 7 лет (пример: срок зависит от страны и отрасли, уточни у юриста)

Structured logging — обязательно JSON:

python
import json
import time

def log_llm_call(request, response, duration_ms):
    log_entry = {
        "ts": time.time(),
        "level": "INFO",
        "event": "llm_call",
        "trace_id": request.headers.get("X-Trace-ID"),
        "user_id_hash": hash_user_id(request.user_id),
        "model": response.model,
        "tokens_input": response.usage.input_tokens,
        "tokens_output": response.usage.output_tokens,
        "cache_read_tokens": response.usage.cache_read_input_tokens or 0,
        "duration_ms": duration_ms,
        "cost_usd": calculate_cost(response.usage, response.model),
        "feature": request.feature_tag,
        "success": True
    }
    print(json.dumps(log_entry))  # → stdout → log aggregator

Anti-patterns (чего не делать)

❌ Logging добавляем "потом" — usually когда уже что-то сломалось. К этому моменту нет данных чтобы дебажить incident который произошёл вчера.

❌ Алерт на каждый error — noise, alert fatigue. Через неделю команда mutes канал. Filter by severity и frequency.

❌ Только error tracking без cost tracking — wake up к surprise bill в $5000. Cost monitoring критичнее чем error monitoring на ранних этапах.

❌ Логирование без user_id — невозможно debug user reports. "У меня не работает" → ты не можешь найти его trace.

❌ "У меня всё в console.log" — не persistent, не searchable, не correlated. Logs должны быть в aggregator (Helicone / Datadog / самописный).

❌ 100% sampling всегда — платишь за хранение всего. Sample wisely: errors 100%, normal 5%.

❌ Alerts без runbook — алерт сработал, on-call не знает что делать. Каждый critical alert должен ссылаться на runbook.

❌ Dashboard который никто не смотрит — если открываешь раз в месяц, ты узнаёшь о проблемах с задержкой в месяц. Daily ritual важен.


Cost of observability

Самый частый вопрос — "а сколько это стоит?". Честный ответ:

Категория Cost
Tools (starter) Часто хватает бесплатных тарифов (LangSmith, Sentry, PostHog)
Tools (production) Платные тарифы нескольких сервисов: посчитай по их текущим ценам
Setup time (initial) 4-8 часов
Maintenance 1-2 часа/мес (update alerts, tune thresholds)
Storage (если self-hosted) Зависит от объёма логов и тарифа хранилища (S3, R2)

ROI расчёт: один пропущенный cost spike (например, бесконечный цикл вызовов) может стоить дороже, чем все инструменты наблюдения за год. Один пропущенный customer-facing outage обычно стоит ещё дороже.

🎨 Образ: observability — это страховка машины. Не платишь — пока всё хорошо, кажется лишним. Один accident — окупает 10 лет премий. Только в отличие от страховки, ты можешь предотвратить accident видя проблему заранее.


Рекомендации по уровню зрелости

Новичок (no revenue, learning):

  • Только Anthropic Console (built-in) + manual checks weekly
  • Без extra tools
  • Logs в console / file
  • Goal: понять что вообще происходит

Средний (early users, free tier):

  • Бесплатный тариф LangSmith или PostHog
  • Slack webhook для критичных алертов
  • Weekly review dashboard
  • Goal: catch problems до пользователей

Профессионал (production with revenue):

  • LangSmith (платный тариф) + Sentry + PostHog
  • PagerDuty или аналог для critical alerts
  • Custom dashboards с business metrics
  • Daily review ritual
  • Goal: SLA compliance, proactive optimization

Enterprise (scale, compliance):

  • Datadog или New Relic full stack
  • Custom OpenTelemetry pipeline
  • Multi-region observability
  • Goal: вообще не узнавать о проблемах от клиентов

Quarterly observability review

Раз в квартал — выделить 2 часа на review своей observability системы.

Что добавить:

  • Новые endpoints / features → новые метрики
  • Новые SLO от клиентов → новые alerts
  • Новые типы ошибок появились → categorize и track

Что убрать:

  • Unused dashboards (никто не смотрел 90 дней)
  • False-positive alerts (срабатывает но не критично)
  • Метрики которые никогда не использовались для решений

Что оптимизировать:

  • Noisiest alerts → tune thresholds
  • Cost trend reversal opportunities (где можно сэкономить)
  • Slow queries / endpoints

Что rotated:

  • Access keys (API tokens к observability tools)
  • Sub-processor list (compliance)
  • Runbook URLs (если что-то переехало)

Практика

Шаг 1: Setup Helicone (5 минут)

Helicone здесь как пример прокси-подхода: с марта 2026 он в режиме поддержки. Если не хочешь привязываться к такому сервису, замени этот шаг интеграцией LangSmith из урока MLOps для indie.

bash
# 1. Регистрация на helicone.ai (есть бесплатный тариф)
# 2. Получаем API key из dashboard
# 3. Сохраняем в .env

echo "HELICONE_API_KEY=sk-helicone-xxx" >> .env
echo "ANTHROPIC_API_KEY=sk-ant-xxx" >> .env
python
# helicone_setup.py — минимальная интеграция
import os
from dotenv import load_dotenv
from anthropic import Anthropic

load_dotenv()

# Клиент через Helicone proxy
client = Anthropic(
    api_key=os.getenv("ANTHROPIC_API_KEY"),
    base_url="https://anthropic.helicone.ai",
    default_headers={
        "Helicone-Auth": f"Bearer {os.getenv('HELICONE_API_KEY')}",
        "Helicone-Property-Environment": "production",
        "Helicone-Property-App": "my-agent"
    }
)

# Тестовый запрос
response = client.messages.create(
    model="claude-haiku-4-5",
    max_tokens=100,
    messages=[{"role": "user", "content": "Скажи привет"}],
    extra_headers={
        "Helicone-User-Id": "test_user_001",
        "Helicone-Property-Feature": "greeting"
    }
)

print("".join(b.text for b in response.content if b.type == "text"))
print(f"\nПроверь dashboard: https://www.helicone.ai/dashboard")
print(f"Стоимость: видна в реальном времени")

Шаг 2: Setup Slack alerts (15 минут)

python
# alerts.py — three-level alerting
import os
import requests
from enum import Enum

class AlertLevel(Enum):
    INFO = "good"        # зелёный
    WARNING = "warning"  # жёлтый
    CRITICAL = "danger"  # красный

def send_alert(level: AlertLevel, title: str, message: str, dashboard_url: str = None):
    """Отправка алерта в Slack по уровню severity."""

    webhook_map = {
        AlertLevel.INFO: os.getenv("SLACK_INFO_WEBHOOK"),
        AlertLevel.WARNING: os.getenv("SLACK_WARNING_WEBHOOK"),
        AlertLevel.CRITICAL: os.getenv("SLACK_CRITICAL_WEBHOOK"),
    }

    webhook = webhook_map[level]
    mention = "@here" if level == AlertLevel.WARNING else ("@channel" if level == AlertLevel.CRITICAL else "")

    payload = {
        "text": f"{mention} *{title}*",
        "attachments": [{
            "color": level.value,
            "text": message,
            "fields": [
                {"title": "Severity", "value": level.name, "short": True},
                {"title": "Dashboard", "value": dashboard_url or "N/A", "short": True}
            ]
        }]
    }

    response = requests.post(webhook, json=payload)
    response.raise_for_status()

# Примеры использования
send_alert(
    AlertLevel.INFO,
    "Daily Summary",
    "Вчера: 1247 requests, $12.40 spend, 0.3% errors"
)

send_alert(
    AlertLevel.WARNING,
    "Cost spike detected",
    "Сегодня уже $40 (2x вчерашнего $20). Проверь logs за последний час.",
    "https://ссылка-на-твой-dashboard"
)

send_alert(
    AlertLevel.CRITICAL,
    "System degradation",
    "Error rate 12% за последние 5 минут. p99 latency 30s.",
    "https://ссылка-на-твой-dashboard"
)

Шаг 3: Cost monitoring daemon

python
# cost_monitor.py — проверка cost anomalies
import os
import time
from datetime import datetime, timedelta
from anthropic import Anthropic

# Допустим у тебя есть функция get_daily_cost() которая читает из API твоего сервиса трейсинга
def get_daily_cost(date):
    """Возвращает $ потраченных за день. Заглушка — подключи API своего сервиса трейсинга."""
    # Реальная реализация: запрос к API сервиса трейсинга за нужную дату
    return 12.40  # placeholder

def get_baseline(days_back=7):
    """Средний cost за последние N дней."""
    costs = []
    for i in range(1, days_back + 1):
        date = datetime.now() - timedelta(days=i)
        costs.append(get_daily_cost(date))
    return sum(costs) / len(costs)

def check_cost_anomaly():
    today_cost = get_daily_cost(datetime.now())
    baseline = get_baseline(days_back=7)

    ratio = today_cost / baseline if baseline > 0 else 0

    if ratio > 5.0:
        send_alert(
            AlertLevel.CRITICAL,
            "🚨 Cost spike >5x baseline",
            f"Today: ${today_cost:.2f}, baseline: ${baseline:.2f} ({ratio:.1f}x)"
        )
    elif ratio > 2.0:
        send_alert(
            AlertLevel.WARNING,
            "⚠️ Cost spike 2x baseline",
            f"Today: ${today_cost:.2f}, baseline: ${baseline:.2f} ({ratio:.1f}x)"
        )

# Запускается через cron каждый час
if __name__ == "__main__":
    check_cost_anomaly()
bash
# crontab -e
# Каждый час проверять cost anomalies
0 * * * * cd /path/to/project && python cost_monitor.py

# Daily summary в 09:00
0 9 * * * cd /path/to/project && python daily_summary.py

Шаг 4: Структурированное логирование

python
# structured_logging.py — JSON logs готовые для aggregation
import json
import time
import hashlib
from contextlib import contextmanager

def hash_user_id(user_id: str) -> str:
    """Pseudonymize user_id для logs."""
    return hashlib.sha256(user_id.encode()).hexdigest()[:16]

@contextmanager
def trace_llm_call(user_id: str, feature: str, model: str):
    """Context manager который логирует LLM call в structured JSON."""
    trace_id = f"trace_{int(time.time()*1000)}"
    start = time.time()

    log_data = {
        "ts": time.time(),
        "trace_id": trace_id,
        "user_id_hash": hash_user_id(user_id),
        "feature": feature,
        "model": model,
    }

    try:
        yield log_data
        log_data["success"] = True
    except Exception as e:
        log_data["success"] = False
        log_data["error"] = str(e)
        log_data["error_type"] = type(e).__name__
        raise
    finally:
        log_data["duration_ms"] = int((time.time() - start) * 1000)
        print(json.dumps(log_data))  # → stdout → лог aggregator

# Использование
with trace_llm_call(user_id="user_42", feature="chat", model="claude-sonnet-5-5") as log:
    response = client.messages.create(
        model="claude-sonnet-5-5",
        max_tokens=1024,
        messages=[{"role": "user", "content": "Привет"}]
    )
    log["tokens_input"] = response.usage.input_tokens
    log["tokens_output"] = response.usage.output_tokens
    # Цены за 1 млн токенов на октябрь 2026 (Sonnet 5.5), актуальные: ../actual.html
    PRICE_IN, PRICE_OUT = 2.0, 10.0
    log["cost_usd"] = response.usage.input_tokens * PRICE_IN / 1_000_000 + \
                     response.usage.output_tokens * PRICE_OUT / 1_000_000

Шаг 5: Создание собственного dashboard (опционально)

python
# simple_dashboard.py — минимальный HTML dashboard
from flask import Flask, render_template_string
import time

flask_app = Flask(__name__)

DASHBOARD_TEMPLATE = """
<!DOCTYPE html>
<html>
<head>
    <title>AI Agent Dashboard</title>
    <meta http-equiv="refresh" content="60">
    <style>
        body { font-family: monospace; background: #1a1a1a; color: #00ff00; padding: 20px; }
        .metric { display: inline-block; padding: 20px; border: 1px solid #00ff00; margin: 10px; }
        .big { font-size: 32px; }
        .alert { color: #ff0000; }
        .warn { color: #ffaa00; }
        .ok { color: #00ff00; }
    </style>
</head>
<body>
    <h1>📊 AI Agent Production Dashboard</h1>
    <p>Last refresh: {{ ts }}</p>

    <div>
        <div class="metric">
            <div>Requests (24h)</div>
            <div class="big">{{ requests }}</div>
        </div>
        <div class="metric">
            <div>Cost (24h)</div>
            <div class="big ok">${{ cost }}</div>
        </div>
        <div class="metric">
            <div>Error rate</div>
            <div class="big {{ 'alert' if error_rate > 5 else 'warn' if error_rate > 1 else 'ok' }}">{{ error_rate }}%</div>
        </div>
        <div class="metric">
            <div>p95 latency</div>
            <div class="big">{{ p95 }}s</div>
        </div>
    </div>

    {% if alerts %}
    <h2>🚨 Active alerts</h2>
    <ul>{% for a in alerts %}<li class="warn">{{ a }}</li>{% endfor %}</ul>
    {% endif %}
</body>
</html>
"""

# Регистрируем route через add_url_rule чтобы dashboard рендерил данные
def render_dashboard():
    # Подставь реальные данные из Helicone API / своей DB
    return render_template_string(
        DASHBOARD_TEMPLATE,
        ts=time.strftime("%Y-%m-%d %H:%M:%S"),
        requests=1247,
        cost="12.40",
        error_rate=0.3,
        p95=4.2,
        alerts=["Cache hit ratio 24% (target >30%)"]
    )

flask_app.add_url_rule("/", "dashboard", render_dashboard)

if __name__ == "__main__":
    flask_app.run(port=8080)
bash
# Открываешь http://localhost:8080 и видишь dashboard
python simple_dashboard.py

Чеклист готовности к production (✅)

Перед тем как пустить агента к реальным пользователям:

Если меньше 7 галочек — ты не готов к production. Доделай.


Инструменты и ресурсы

  • LangSmith — observability от LangChain, advanced tracing, есть бесплатный тариф
  • Helicone — LLM-прокси с метриками (на октябрь 2026 в режиме поддержки)
  • Sentry — error tracking, general-purpose
  • PostHog — product analytics, business metrics
  • PagerDuty — on-call alerts, индустриальный стандарт
  • Datadog — enterprise full-stack observability
  • Grafana Cloud IRM — on-call и инциденты (версия OnCall с открытым кодом архивирована в марте 2026)
  • Anthropic Console — built-in usage tracking
  • OpenTelemetry — vendor-neutral observability standard

Ключевые выводы

Observability — это не "потом когда вырастем". Это условие что ты вообще можешь работать в проде. Один пропущенный cost spike может стоить больше чем годовая подписка на сервис наблюдения. Поставь хоть что-то — даже простой Slack webhook лучше чем "узнаю от клиентов".

5 mandatory metrics: latency (p95!), cost (spike detection), error rate (categorized), token usage (cache ratio), business (conversation completion). Без любой из пяти — слепое пятно которое тебя укусит.

3 уровня alerting спасают от alert fatigue. Info — daily summary. Warning — Slack mention. Critical — page on-call. Если каждая ошибка будит ночью — через неделю команда mutes канал и пропустит настоящий инцидент.

Debugging workflow всегда одинаковый: locate trace → reproduce → correlate с metrics → hypothesize → fix + add eval test. Без observability ты гадаешь. С ней — диагностируешь.


Следующий урок

→ Финальная архитектура — полный AI-стек бизнеса

О том что делать когда всё сломалось, смотри урок Backup & Disaster Recovery для AI-стека.

Отметка хранится только в этом браузере и никуда не отправляется. Мой прогресс