Суть урока
"It works on my machine" — самая дорогая фраза индустрии. Ты задеплоил агента, он работает, клиенты пользуются. А потом приходит сообщение: "оно сломалось ещё вчера вечером". И ты понимаешь — узнал об этом не из своей системы, а от обиженного пользователя.
Production observability — это твои глаза и уши в работающую систему. Без них ты слепой пилот: двигатель работает, но ты не знаешь когда он перегреется, когда закончится топливо, когда отвалится крыло.
В этом уроке — 5 метрик которые ОБЯЗАН мониторить, 3 уровня alerting, 4 инструмента для AI-агентов (список на октябрь 2026). Без воды, с примерами цифр и dashboard mockup'ами. Пороги в уроке — отправная точка: со временем подбери свои по реальным данным.
🎯 Главный принцип: не logs, а signals
Logging ≠ observability. Можешь иметь гигабайты логов и не понимать что происходит. Observability — это способность отвечать на вопросы о системе не залезая в код.
Три классических столпа (per OpenTelemetry стандарт https://opentelemetry.io):
- Metrics — числа во времени (latency, cost, errors)
- Traces — путь одного запроса через всю систему
- Logs — события с контекстом
Для AI-агентов добавляется четвёртый:
- LLM-specific — prompts, completions, token usage, cache hits
Ключевые концепции
- 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
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 категории):
- API errors — 4xx, 5xx от Anthropic/OpenAI
- Tool failures — MCP timeouts, schema mismatches, tool exceptions
- Validation failures — LLM output не matches expected JSON schema
- 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 пересмотр |
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%, платишь полную ставку.
# 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
# Пример отправки 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-уведомлений и звонка на телефон
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
Дополнительно:
- OpenTelemetry standard (https://opentelemetry.io/) — если хочешь vendor-neutral approach
- Anthropic Console (https://platform.claude.com) — встроенный, минимальный, but free
Implementation pattern — прокси на примере Helicone
Один из самых быстрых способов получить observability — обернуть Anthropic SDK через прокси, например Helicone. Setup занимает 5 минут.
⚠️ На октябрь 2026 Helicone работает в режиме поддержки (см. выше), поэтому смотри на него как на пример подхода: прокси между кодом и API плюс метки в заголовках. Для нового проекта сравни с LangSmith (урок MLOps для indie) и со шлюзами вроде AI Gateway у Cloudflare. Адрес прокси и названия заголовков сверяй с документацией выбранного сервиса.
До (no observability):
from anthropic import Anthropic
client = Anthropic()
response = client.messages.create(
model="claude-sonnet-5-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Привет"}]
)После (Helicone wrapping):
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
- Минимальный fix
- Add test case в eval suite (см. урок Evals — самоулучшающиеся скиллы)
- Add alert rule если это повторяющийся pattern
- Document в runbook
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:
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 aggregatorAnti-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 обычно стоит ещё дороже.
Рекомендации по уровню зрелости
Новичок (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.
# 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# 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 минут)
# 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
# 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()# 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: Структурированное логирование
# 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 (опционально)
# 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)# Открываешь 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-стека.
Отметка хранится только в этом браузере и никуда не отправляется. Мой прогресс