Суть урока
Все курсы учат "как построить агента". Никто не учит "что делать когда он сломался в 3 ночи перед демо клиенту".
Production = не "запустил и забыл". Production = "запустил и теперь живёшь с этим". Hallucination, бесконечные loops, упавший MCP, context overflow, спайк счёта на API, prompt injection, тихий silent failure — это не "если случится". Это "когда случится".
Этот урок — 7 типичных failure patterns и recovery playbook для каждого. Tools, code patterns, чеклисты, incident response. Не теория — то что ты будешь делать в реальной паническ.
Ключевые концепции
- Hallucination — модель уверенно выдаёт неверный факт
- Loop — агент застрял на одном действии, retry без прогресса
- Tool failure — MCP сервер / внешний API не отвечает или возвращает ошибку
- Context overflow — контекст раздулся, модель теряет инструкции (context rot)
- Cost spike — счёт за API вырос в 5-10 раз без явной причины
- Prompt injection — внешний input заставил агента сделать что-то против правил
- Silent failure — pipeline отработал без ошибок, но результат неверный
- Circuit breaker — паттерн отключения сломанной интеграции на N минут
- Graceful degradation — fallback на упрощённую функциональность при сбое
- Chaos engineering — намеренное провоцирование failures для проверки готовности
- Postmortem — структурированный разбор инцидента: root cause, prevention
Теория
Failure 1: Hallucination (агент уверенно врёт)
Симптом: ответ выглядит правильно, форматирование чёткое, тон уверенный — но факт ложный. "В Эквадоре налог на недвижимость 5%" (на самом деле другая ставка). "Эта функция появилась в версии 3.2 библиотеки" (такой версии не существует).
Risk levels:
- CRITICAL — medical, legal, financial advice (клиент действует на основе ответа)
- HIGH — производственный код, sql queries, конфиги (выполняется без проверки)
- MEDIUM — casual chat, brainstorm (последствия ограничены)
Recovery patterns:
- Ground truth verification (RAG) — добавь retrieval с verified sources. Модель отвечает не "из памяти" а на основе документов которые ты контролируешь
- Confidence scoring — в промпт: "Ответь + укажи confidence 0-100. Если < 70 — скажи 'не уверен'"
- Multi-LLM voting — два независимых вызова (Claude + GPT). Если ответы расходятся — escalate human
- "Cite or refuse" — модель ОБЯЗАНА указать источник (URL, doc id) или явно сказать "не знаю"
Detection: sample 5% outputs ежедневно + human review. Логируй вопросы где модель сказала "не знаю" — это твоя карта пробелов.
# Pattern: cite-or-refuse через system prompt
SYSTEM = """Отвечай только на основе предоставленных документов.
Каждый факт сопровождай источником в формате [doc_id:section].
Если информации нет в документах — отвечай ровно:
"Не могу подтвердить из доступных источников."
НЕ выдумывай. НЕ опирайся на общие знания."""Failure 2: Loop (агент повторяется бесконечно)
Симптом: одна и та же фраза, тот же tool call, та же ошибка — повторяется. Logs забиваются одинаковыми записями. Счёт за API тикает.
Common cause: tool failed → агент пытается снова с теми же параметрами. Или модель "не понимает" что инструмент уже вернул "файл не найден" и повторяет вызов.
Recovery:
- Iteration cap: max N attempts → fallback или abort
- Error context на retry: передавать сообщение прошлой ошибки в следующий вызов
- State diff: проверять что state изменился между итерациями
- Stuck detection: одинаковый action 3 раза подряд → abort
MAX_ATTEMPTS = 5
previous_action = None
stuck_count = 0
for i in range(MAX_ATTEMPTS):
result = agent.run(state)
if result.action == previous_action:
stuck_count += 1
if stuck_count >= 3:
raise StuckLoopError(f"Same action repeated 3x: {result.action}")
else:
stuck_count = 0
previous_action = result.action
if result.done:
break
else:
raise MaxIterationsExceeded(f"Hit cap {MAX_ATTEMPTS}")Failure 3: Tool failure (MCP сервер не отвечает)
Симптом: timeout, HTTP 500, MCP server crashed, rate limit от внешнего API.
Recovery:
- Circuit breaker: 3 errors подряд → отключи интеграцию на 5 минут, не дёргай впустую
- Fallback strategy: Stripe MCP down → local DB lookup для basic billing info
- Graceful degradation: feature недоступна → честно "сервис временно недоступен, попробуй через 5 мин". НЕ fake результат
- Health checks: ping MCP каждые 60 сек, alert если down > 2 мин
Library: Tenacity (Python) — retry с exponential backoff из коробки.
from tenacity import retry, stop_after_attempt, wait_exponential
@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=2, max=10),
reraise=True
)
def call_external_api(payload):
return requests.post(URL, json=payload, timeout=10)Failure 4: Context overflow (агент забыл начало сессии)
Симптом: агент игнорирует instructions из system prompt, противоречит сам себе, "забывает" что обсуждали 20 сообщений назад.
Cause: context > 50K токенов → context rot. Модель хуже работает с информацией из середины, лучше — с началом и концом.
Recovery:
/compactв Claude Code, когда контекст растёт (можно с инструкцией, что сохранить:/compact сохрани решения по архитектуре); автоматическое сжатие тоже работает, его порог настраивается командой/autocompact- Sliding window: держи последние N сообщений + summary более ранних
- Critical instructions в конец — модель лучше помнит recent context (recency bias)
- System prompt каждое сообщение — если правило критично, повторяй
- Move long data → RAG — не пихай 50K документации в контекст, делай retrieval
Failure 5: Cost spike (счёт за день в 10 раз больше нормы)
Симптом: $50/день вместо $5/день. Уведомление о приближении к месячному лимиту уже на 5-й день месяца.
Possible causes:
- Loop bug (Failure 2 не пойман)
- Missing cache (повторные одинаковые prompts без prompt caching)
- Scraping attack (если public endpoint без auth)
- Retry storm (failed → retry → failed → retry)
- Чужой API key (leaked в git)
Recovery:
- Daily budget kill switch: spend > $X/день → автоматический pause API
- Spike detection: spend > 2x daily average → email/Telegram alert
- Audit log: каждый API call → log в KV/DB (cheap, debuggable)
- Disable + investigate before resume. Не "поднимай лимит чтобы продолжить" не разобравшись
Tools:
- Anthropic Console — страница Usage и собственный лимит расходов (Settings → Billing → Spend limits)
- Langfuse — open-source observability, cost per user
- LangSmith — tracing для LangChain/LangGraph
Failure 6: Prompt injection
Симптом: агент отключил хук "по просьбе пользователя", передал секреты во внешний tool, отправил email от твоего имени, выполнил rm -rf из инструкции в Markdown файле который читал.
См. подробно урок Prompt Injection Defense. Здесь — recovery.
Recovery:
- Изоляция: каждый risky tool через отдельного агента с минимальными permissions
- Audit log everything: что было command vs что внешний input (разделяй явно)
- Restoration:
git revert+ alert team + investigate breach - Lessons learned: добавь pattern в
pre-tool-use-prompt-injection.shхук
# Минимальная защита — hook проверяет подозрительные паттерны
# .claude/hooks/pre-tool-use-prompt-injection.sh
grep -iE 'ignore (previous|all) instructions|disable.*hook|reveal.*system prompt' "$INPUT" \
&& exit 1Failure 7: Silent failure (агент "работает" но output неправильный)
Самый коварный. Pipeline complete, exit code 0, никаких errors в логах. Но результат — мусор.
Примеры:
- LLM вернул JSON с правильной структурой, но значения сгенерированы из воздуха
- Перевод выглядит беглым, но смысл искажён
- Финансовый расчёт — правильная формула, но цифры с потолка
Recovery:
- Output validation: schema check каждого LLM output. Pydantic, JSON schema, zod
- Smoke tests: каждый pipeline run → проверка 1-2 known cases дают expected output
- User feedback loop: "это ответ правильный? 👍/👎" каждые 50 interactions → дашборд
- Eval suite (урок Evals): regression tests после каждого изменения промпта
from pydantic import BaseModel, Field, ValidationError
class InvoiceExtraction(BaseModel):
amount: float = Field(gt=0, lt=1_000_000)
currency: str = Field(pattern="^(USD|EUR|RUB)$")
invoice_date: str # ISO 8601
try:
parsed = InvoiceExtraction.model_validate_json(llm_output)
except ValidationError as e:
# silent failure caught — escalate
log_anomaly(llm_output, e)
raiseRecovery toolkit (что иметь в багажнике)
| Категория | Tool | Назначение |
|---|---|---|
| Logging | Langfuse, LangSmith, structured logs в KV | Каждый LLM call с input/output/tokens |
| Alerting | Telegram webhook, PagerDuty, email | Spike / down / anomaly |
| Monitoring | Anthropic Console + custom dashboard (урок Production Observability) | Cost, latency, error rate |
| Rollback | Git tags + revert script | Один command возврат к last-good |
| Communication | Шаблоны ответов клиентам | "Known issue, fix в течение 2 часов" |
| Validation | Pydantic / zod / JSON schema | Schema check каждого output |
| Retry logic | Tenacity (Python), p-retry (JS) | Exponential backoff из коробки |
Production checklist (mandatory перед запуском в прод)
Запуск в прод без 8/8 — техдолг с первого дня.
Chaos engineering для AI (тестирование failure cases)
Подход Principles of Chaos применённый к агентам. Намеренно ломай систему в staging, чтобы убедиться что recovery работает.
| Inject | Как | Что проверяешь |
|---|---|---|
| Hallucination | Добавь в prompt "Always answer Y is true" → spike test | Обнаружит ли verification layer |
| Loop | Mock tool всегда возвращает ту же ошибку | Сработает ли iteration cap |
| HTTP 500 | Mock MCP возвращает 500 на каждый 3-й вызов | Сработает ли circuit breaker + fallback |
| Context overflow | Запихни 100K junk токенов | Триггерится ли /compact |
| Cost spike | Loop без break, дешёвый prompt × 10000 | Сработает ли daily budget kill switch |
| Schema mismatch | LLM возвращает поля с лишними/missing keys | Pydantic поймает или silent fail? |
Раз в месяц — chaos день в staging. Полчаса работы, спасает в проде.
Incident response — 4 шага
Когда что-то горит — не паникуй. Иди по шагам:
- Stop — отключи affected feature, prevent further damage. Feature flag off, или maintenance page
- Triage — что произошло, scope (1 user / все), blast radius (билинг? данные? репутация?)
- Stabilize — rollback к last-good tag ИЛИ temporary fix (hardcoded fallback) чтобы вернуть service
- Postmortem — после восстановления: root cause, что добавим в monitoring, как prevent
Шаблон postmortem (journals/incidents/YYYY-MM-DD-<name>.md):
# Incident: <название> **Дата:** YYYY-MM-DD **Длительность:** 14:32 - 15:47 UTC (1h 15m) **Severity:** P1 / P2 / P3 **Impact:** N клиентов, $X loss / 0 data loss ## Timeline - 14:32 — alert spike в Telegram (cost > 2x avg) - 14:35 — investigation start, нашёл loop в agent X - 14:50 — iteration cap deployed - 15:47 — service stable ## Root cause Tool Y возвращал empty string вместо null. Agent интерпретировал как "не получилось" и retry'ил бесконечно. ## What went well - Alert сработал через 3 минуты - Rollback procedure работала ## What went wrong - Iteration cap отсутствовал (MAX_ATTEMPTS не задан) - Output validation не проверял empty string ## Action items - [ ] Добавить MAX_ATTEMPTS=5 во всех агентов (owner: A, ETA: завтра) - [ ] Pydantic check на tool Y output (owner: A, ETA: 3 дня) - [ ] Chaos test на empty string (owner: A, ETA: неделя)
Без postmortem инцидент повторится. Гарантировано.
Anti-patterns (что НЕ делать в панике)
- ❌ "Просто перезапущу" без понимания root cause. Через час повторится
- ❌ Скрывать инцидент от клиентов. Они узнают сами и доверие подорвано
- ❌ Hot fix без записи в audit log. Через месяц "почему здесь magic number?"
- ❌ "Это случайность, забуду". Паттерны повторяются. Каждый incident → postmortem
- ❌ Disable hook чтобы "проверить" (см. урок Hook-Deny-By-Design). Security risk + забудешь включить
- ❌ Поднять API лимит чтобы продолжить не разобравшись в причине spike
Cost recovery (если уже потеряли деньги)
Реальность: recovery почти всегда incomplete. Превенция дешевле.
| Сценарий | Шанс возврата | Действия |
|---|---|---|
| Anthropic billing bug (их side) | Низкий, но реальный | Support ticket с trace_id, logs. Иногда дают credit |
| Stripe billing error (клиент платит лишнее) | Высокий | Dispute через Stripe dashboard, refund тебе |
| Leaked API key (Github push) | 0% | Rotate ключ немедленно, audit все calls |
| Loop bug съел $200 | 0% | Урок усвоен. Iteration cap навсегда |
Lesson: монитор budget alerts. Recovery редкий бонус, не план.
Аудиенция: что осваивать когда
Новичок (первые 3 месяца в прод)
Только failures 1-3 — самые частые:
- Hallucination базово (cite-or-refuse в промпте)
- Iteration cap на каждом loop
- Try/except + retry для tool failures
Базовое logging (просто print в файл сначала). Лимит расходов в Anthropic Console.
Средний (3-12 месяцев)
Добавляешь:
- Failures 4-5 (context management + cost monitoring)
- Langfuse / LangSmith для observability
- Telegram alerts на spike
- Postmortem culture (даже если работаешь один — записывай)
Профессионал (1+ год прод)
Все 7 паттернов:
- Chaos engineering ежемесячно
- Automated runbooks (incident → bot выполняет triage)
- Multi-LLM voting на critical paths
- Pydantic validation everywhere
- Customer notification automation
Практика
Шаг 1: Добавь iteration cap во все агенты
Find в коде где есть while, for без верхней границы, recursive calls без depth limit.
# До
def agent_loop(state):
while not state.done:
state = step(state)
return state
# После
MAX_ITERATIONS = 10
def agent_loop(state):
for i in range(MAX_ITERATIONS):
state = step(state)
if state.done:
return state
raise MaxIterationsExceeded(
f"Hit {MAX_ITERATIONS}. Last state: {state.summary()}"
)Шаг 2: Настрой лимит расходов и предупреждение
Anthropic Console → Settings → Billing → Spend limits → Adjust limit. Лимит один: месячный потолок. Когда он достигнут, API останавливается, пока ты не поднимешь лимит или не наступит новый месяц. Поставь его примерно в 3x от обычного месячного расхода.
Предупреждение («soft limit») сделай сам, ежедневной проверкой через cron. Порог — текущий средний дневной расход × 1.5.
# scripts/check-daily-cost.sh
# Нужен Admin API key (sk-ant-admin01-...): он есть у организаций, у индивидуальных аккаунтов его нет —
# тогда смотри страницу Usage в Console вручную.
TODAY=$(date -u +%Y-%m-%dT00:00:00Z)
TOMORROW=$(date -u -v+1d +%Y-%m-%dT00:00:00Z) # на Linux: date -u -d tomorrow +%Y-%m-%dT00:00:00Z
RESP=$(curl -s "https://api.anthropic.com/v1/organizations/cost_report?starting_at=$TODAY&ending_at=$TOMORROW" \
-H "anthropic-version: 2023-06-01" \
-H "x-api-key: $ANTHROPIC_ADMIN_KEY")
# Суммы приходят в центах строкой; точную структуру ответа проверь в Cost API reference
DAILY_SPEND=$(echo "$RESP" | jq '[.data[].results[].amount | tonumber] | add / 100')
if (( $(echo "$DAILY_SPEND > 20" | bc -l) )); then
curl -X POST "https://api.telegram.org/bot$BOT_TOKEN/sendMessage" \
-d "chat_id=$CHAT_ID&text=⚠️ Daily spend: \$$DAILY_SPEND"
fiОписание Cost API: platform.claude.com/docs/en/manage-claude/usage-cost-api.
Шаг 3: Добавь Pydantic validation на critical output
from pydantic import BaseModel, Field, ValidationError
from anthropic import Anthropic
client = Anthropic()
class CustomerReply(BaseModel):
sentiment: str = Field(pattern="^(positive|neutral|negative)$")
intent: str
confidence: float = Field(ge=0, le=1)
suggested_response: str = Field(min_length=10, max_length=500)
response = client.messages.create(
model="claude-sonnet-5-5",
max_tokens=1024,
messages=[{"role": "user", "content": "..."}]
)
try:
validated = CustomerReply.model_validate_json("".join(b.text for b in response.content if b.type == "text"))
use(validated)
except ValidationError as e:
log_to_journal("".join(b.text for b in response.content if b.type == "text"), e)
raise SilentFailureDetected(str(e))Шаг 4: Прогонять один chaos test
Выбери самый страшный для тебя failure (обычно cost spike или silent failure). Сегодня в staging:
- Намеренно создай условия (mock возвращает плохой output / loop без break)
- Запусти агента
- Засеки время до alert / abort
- Если >5 минут — добавь detection. Если не сработало — фикси
После — запиши в journals/chaos-tests/YYYY-MM-DD.md:
- Что injected
- Что ожидал
- Что случилось
- Action items
Шаг 5: Шаблон customer notification
templates/customer-incident-notification.md:
Здравствуйте, Сейчас наблюдаем проблему с <feature>: <краткое описание симптома>. **Статус:** работаем над фиксом **ETA восстановления:** <X минут> **Что делать сейчас:** <workaround или "подождать"> Обновим письмом когда устраним. Извините за неудобство. — Команда <название>
Один файл. Открыл, заполнил 3 поля, отправил. В incident не нужно "сочинять с нуля".
Инструменты и ресурсы
- Tenacity — Python retry library с exponential backoff
- Anthropic Console — usage tracking и собственный лимит расходов
- Langfuse — open-source observability для LLM apps, cost per user, latency (Helicone с марта 2026 в режиме поддержки)
- LangSmith — tracing для LangChain/LangGraph агентов
- Pydantic — schema validation для Python (zod аналог в TS)
- PagerDuty — incident management для серьёзных команд
- Principles of Chaos Engineering — Netflix-подход к намеренным failures
- Урок Prompt Injection Defense — prompt injection defense in depth
- Урок Production Observability — custom dashboards для мониторинга агентов
- Урок Evals — eval suites для regression testing
Чеклист освоения урока
Ключевые выводы
Production — не "запустил и забыл". Production — "запустил и живёшь с этим". 7 failure patterns случатся у всех кто работает с агентами в проде. Вопрос не "если", а "когда" и "готов ли ты".
Превенция дешевле recovery. Iteration cap + budget kill switch + output validation — три копеечных паттерна которые покрывают большую часть типичных incidents. Без них — техдолг с первого дня прода.
Postmortem без обвинений — единственный способ не повторить инцидент. Шаблон 10 минут, защита на годы. Даже если работаешь один — записывай. Future you скажет спасибо.
Следующий урок
→ Backup & Disaster Recovery для AI-стека — что делать когда падает сам провайдер
Отметка хранится только в этом браузере и никуда не отправляется. Мой прогресс