← Модуль 4: Architect
4.5

Надёжность: эскалация, ошибки, multi-pass review

Цель: спроектировать паттерны, которые делают агентов **production-ready**. Это Домен 5 экзамена (15%), но встречается в каждом сценарии.

Эскалация — когда человек нужен

4 триггера эскалации

  1. Пользователь явно просит — "connect me to a human", "talk to someone real"
  2. Исключения/пробелы в политике — ситуация не предусмотрена правилами
  3. Невозможность продвинуться — агент застрял, не может завершить
  4. Критически неопределённый случай — ставки высоки, уверенность низкая

Плохо: оценки на основе самооценки уверенности

# НЕ ДЕЛАЙ
if model_confidence < 0.5:
    escalate()

LLM плохо калиброваны — они уверены когда не должны быть, и неуверены когда всё ок. Самооценка уверенности ненадёжна.

Плохо: анализ настроения

# НЕ ДЕЛАЙ
if customer_sentiment == "frustrated":
    escalate()

Фрустрация не коррелирует со сложностью случая. Счастливый клиент может иметь проблему которая вне политики. Расстроенный — может иметь простой запрос.

Хорошо: явные критерии + few-shot

ESCALATE when:
- Customer explicitly requests human
- Refund amount > $500 (policy limit)
- Account has been flagged for fraud review
- Multiple previous escalations (pattern indicator)
- Policy is ambiguous on this specific case type

Examples of WHEN to escalate:
[example 1: user asks "I want to speak to a manager"]
[example 2: damaged item, photo evidence, standard policy replacement — DO NOT escalate]
[example 3: damaged item, photo evidence, UNUSUAL case (product discontinued) — escalate]

Конкретные критерии + демонстрация на примерах. Это решение корневой причины — нечёткие границы принятия решений.

Немедленная эскалация на явный запрос

Если клиент говорит "I want to talk to a human" — не пытайся решить самостоятельно сначала. Эскалируй сразу.

Попытка решить когда пользователь явно попросил человека = ухудшение опыта.

Запрос дополнительных идентификаторов

Сценарий: клиент пишет "check my order", но в системе 3 заказа с его именем.

Плохо: эвристика (взять последний? первый? большой?) Хорошо: спросить

I see multiple orders associated with your account:
- Order #12345 (2026-04-10, $129)
- Order #12346 (2026-04-08, $45)
- Order #12340 (2026-03-22, $280)

Which one are you asking about?

Эвристика при множественных совпадениях ведёт к ошибкам которых можно было избежать простым уточнением.

Распространение ошибок в multi-agent системах

Антипаттерн: унифицированные статусы

# Все подагенты возвращают либо success, либо "search unavailable"
def search_agent():
    try:
        return search()
    except:
        return {"status": "search unavailable"}

Координатор теряет всю полезную информацию. Не может решить как восстанавливаться.

Антипаттерн: тихое подавление

# Плохо — ошибка пропадает, возвращается пустота
def search_agent():
    try:
        return search()
    except:
        return {"results": []}  # выглядит как успех с нулём результатов

Ещё хуже — координатор думает "результатов не нашлось, всё ок". А на самом деле сервис упал.

Антипаттерн: полное завершение процесса при единичном сбое

# Плохо — один подагент упал, всё отменяется
try:
    a_results = agent_a()
    b_results = agent_b()
    c_results = agent_c()
except:
    raise

Даже если 2 из 3 вернули полезные данные — теряем всё.

Паттерн: структурированный контекст ошибки

def search_agent():
    try:
        results = search()
        return {"success": True, "results": results}
    except TimeoutError as e:
        return {
            "success": False,
            "error_type": "timeout",
            "attempted_approach": "semantic search",
            "partial_results": partial,  # если есть
            "alternatives": ["try keyword search", "reduce scope"],
            "is_retryable": True
        }
    except ServiceUnavailable as e:
        return {
            "success": False,
            "error_type": "service_down",
            "retry_after": 30,
            "is_retryable": True
        }
    except ValidationError as e:
        return {
            "success": False,
            "error_type": "validation",
            "details": str(e),
            "is_retryable": False  # повтор не поможет
        }

Координатор получает контекст для интеллектуального восстановления:

  • Временная ошибка? Повтори
  • Нет доступа? Эскалируй
  • Валидация? Не повторяй

Локальное восстановление vs эскалация

# В подагенте — локальный retry для transient
if error_type == "transient" and attempt < 3:
    return retry_with_backoff()
 
# Если не разрешилось за 3 попытки — пропагируй координатору
return structured_error_context

Transient ошибки лечатся локально. Пропагируются только неразрешимые.

Multi-pass review

Проблема однопроходного ревью больших PR

14 файлов в PR. Single-pass review:

  • Детальная обратная связь по одним файлам
  • Поверхностная по другим
  • Пропуск явных багов
  • Противоречивые замечания (паттерн помечен как проблема в одном файле, одобрен в другом)

Корневая причина: размытие внимания. Модель не может одинаково глубоко обработать все 14 файлов за раз.

Паттерн: разделить на проходы

Pass 1: Per-file local analysis
  → File A: issues specific to File A
  → File B: issues specific to File B
  → ...

Pass 2: Cross-file integration analysis
  → Data flow between files
  → Interface contracts
  → Shared state mutations

Пофайловый анализ глубокий (фокус узкий). Интеграционный — отдельный проход с другим вопросом ("как эти файлы взаимодействуют?").

Это НЕ о контекстном окне

Переключение на модель с большим контекстным окном (1M) не решает проблему размытия внимания. Дело не в том сколько текста помещается, а в том как глубоко модель его обрабатывает.

Multi-instance review (независимые проходы)

Для критических решений:

review_a = claude.call(task, system="You are reviewer A")
review_b = claude.call(task, system="You are reviewer B")  # новая сессия, чистый контекст
 
merged = synthesize(review_a, review_b)

Независимые инстансы (без предшествующего контекста рассуждений) эффективнее ловят тонкие ошибки, чем самопроверка. Модель сохраняет контекст рассуждений от генерации — это снижает вероятность оспорить собственное решение.

Антипаттерн: консенсус как критерий

# Плохо — пропустим реальные баги где только один reviewer заметил
if not (reviewer_a_found and reviewer_b_found):
    skip_issue

Ищи объединение (flag if any reviewer found), не пересечение.

Human-in-the-loop калибровка

Риск: агрегированная метрика маскирует слабые места

97% точности на извлечении из документов — отлично? Проверь разбивку:

  • 99% на invoices
  • 99% на receipts
  • 75% на рукописных документах

Общая точность 97% маскирует слабость на рукописных. В проде ты получишь взрывной рост ошибок когда 30% твоих документов окажутся рукописными.

Паттерн: стратифицированная валидация

Периодически сэмплируй высокоуверенные извлечения по каждому типу документа и полю, вручную проверяй. Если точность по типу падает — направляй этот тип на human review.

Confidence per field

{
  "invoice_number": {"value": "INV-12345", "confidence": 0.99},
  "total_amount": {"value": 129.00, "confidence": 0.98},
  "tax_amount": {"value": 12.90, "confidence": 0.72}
}

Поле-level uncertainty → маршрутизация только неуверенных полей на human review. Уверенные — автообработка.

Практика (30 минут)

Задача 1. Audit текущей системы

Если у тебя есть agent-система в проде:

  • Что она делает при таймауте подагента? (шанс что ответ — "тихо проглатывает")
  • Какие триггеры эскалации? (шанс что ответ — "нет формальных")
  • Есть ли multi-pass для критичных ревью?

Задача 2. Спроектировать эскалацию

Для твоего use-case (поддержка/ревью/extract) напиши:

  • 5+ явных триггеров эскалации
  • 3+ few-shot примера "escalate vs handle"
  • Политика "immediate escalation" на явный запрос

Задача 3. Структурированные ошибки

Перепиши один подагент чтобы возвращал структурированный контекст ошибок (error_type, retryable, partial_results, alternatives).

Что дальше

Последний урок — подготовка к Claude Certified Architect. Разбираем формат экзамена, 5 доменов, рекомендации по подготовке.