Надёжность LLM-систем: fallback-архитектура и деградационные сценарии при сбоях провайдеров
Дата публикации: февраль 2026
Применимость: production-системы с LLM-зависимостями через внешний API
Уровень: Senior SRE / Platform Engineer / Architect
LLM-провайдеры — это внешние зависимости с нетипичным профилем отказов. В отличие от базы данных или кэша, которые либо работают, либо нет, API языковых моделей деградируют по множеству осей одновременно: растёт latency, увеличивается error rate, снижается качество ответов при формально успешных статус-кодах. Этот профиль делает стандартные SRE-паттерны необходимыми, но недостаточными.
В этой статье — полная архитектура отказоустойчивости LLM: от таксономии отказов до production runbook с конкретными командами.
1. Модель отказов LLM-интеграций
1.1. Таксономия по осям деградации
Классическая SRE-модель рассматривает два состояния зависимости: «работает» и «не работает». Для LLM API необходима трёхосная модель.
Ось 1 — Доступность (Availability).
Бинарная: провайдер отвечает или нет. Сюда попадают: полный outage (5xx на все запросы), network partition, DNS failure, истечение ротируемого API-ключа. Это наиболее редкий тип отказа, но наиболее очевидный.
Ось 2 — Производительность (Performance).
Непрерывная: время ответа деградирует без полного отказа. Сюда попадают: rate limiting (429), throttling без явного сигнала, рост TTFT при сохранении доступности, увеличение queue time на стороне провайдера при пиковой нагрузке. Это самый частый тип деградации — по данным public status pages трёх major провайдеров за Q1 2026, более 70% зафиксированных инцидентов относятся к этой категории.
Ось 3 — Качество (Quality).
Наиболее коварная ось: формальный ответ 200 OK, корректный JSON, но содержимое деградировано. Примеры: модель начинает систематически игнорировать инструкции системного промпта, возрастает hallucination rate, ломается соблюдение структуры вывода (JSON schema violations при формально работающем API). Эта ось требует отдельного мониторинга, поскольку не определяется через HTTP-коды.
1.2. Матрица отказов и их источники
| Тип отказа | Ось | HTTP-сигнал | Детектируемость | Частота (оценка) |
|---|---|---|---|---|
| Полный outage провайдера | Availability | 5xx / timeout | Высокая | Редко (<0.1% времени) |
| Rate limit (hard) | Performance | 429 | Высокая | Ситуативно (при пиках) |
| Rate limit (soft throttling) | Performance | 200, но +800% latency | Средняя | Умеренно |
| Context window overflow | Availability | 400 / 413 | Высокая | Зависит от архитектуры |
| Качественная деградация | Quality | 200 OK | Низкая | Неизвестна (не мониторится) |
| API-версия deprecated | Availability | 404 / 410 | Высокая | Редко, но предсказуемо |
| Ключ с истёкшим billing | Availability | 402 / 403 | Высокая | Редко |
| Нарушение safety filters | Availability | 400 | Высокая | Task-dependent |
1.3. Нетипичные паттерны, специфичные для LLM
«Тихая деградация» (Silent Degradation). Провайдер переключает трафик на менее мощный вариант модели при перегрузке без изменения endpoint или явного уведомления. Ответы остаются формально корректными, но короче, менее детальными, с более высоким hallucination rate. Детектируется только через качественный мониторинг.
«Частичный стриминг» (Partial Stream Failure). При streaming-режиме соединение обрывается на середине токен-потока. Клиент получает partial response без явного сигнала об ошибке. Если код не проверяет финальный stop_reason, partial response обрабатывается как полный.
«Контекстная амнезия» (Context Drift). При длинных агентных сессиях модель начинает «терять» ранние части контекста раньше заявленного context window — особенно в периоды высокой нагрузки на инфраструктуру провайдера.
2. Дизайн fallback-архитектуры
2.1. Многоуровневая схема
2.2. Принципы проектирования fallback-цепочки
Принцип 1: Провайдерная диверсификация обязательна.
Fallback в рамках одного провайдера (Sonnet → Haiku у Anthropic) защищает от деградации конкретной модели, но не от outage всей инфраструктуры Anthropic. Минимально необходимая конфигурация: два независимых провайдера с разной инфраструктурой.
Принцип 2: Fallback-модели должны быть предварительно протестированы.
Переключение на «запасную» модель под давлением инцидента — это худшее время для обнаружения несовместимости форматов ответов. Каждая fallback-модель должна регулярно получать 1–5% реального трафика в hot-standby режиме.
Принцип 3: Семантическое, а не синтаксическое fallback.
Цепочка должна знать, что делать с задачей, а не просто куда её перенаправить. Для задач с жёсткими требованиями к качеству — downgrade к менее точной модели лучше, чем 503. Для задач с нулевой tolerance к ошибкам — правильный ответ — это честный error response с объяснением.
Принцип 4: Идемпотентность запросов.
Все запросы к LLM должны быть спроектированы с учётом возможности повтора: уникальный request_id, детерминированный промпт при одинаковых входных данных, отсутствие side effects в самом промпте.
2.3. Circuit breaker: конкретная конфигурация
Circuit breaker для LLM-провайдера отличается от стандартного: порог должен учитывать не только ошибки, но и latency-аномалии.
# circuit_breaker_config.yaml — рекомендуемые параметры
providers:
anthropic:
error_threshold_pct: 25 # открывается при 25%+ ошибок
latency_threshold_ms: 8000 # p95 > 8s = считается "ошибкой"
window_seconds: 60 # скользящее окно
min_calls_in_window: 10 # не открывать при <10 вызовов
open_duration_seconds: 30 # время в состоянии OPEN
half_open_probe_calls: 3 # 3 пробных вызова в HALF-OPEN
success_threshold_to_close: 2 # 2 успеха из 3 → CLOSED
openai:
error_threshold_pct: 30
latency_threshold_ms: 10000
window_seconds: 60
min_calls_in_window: 10
open_duration_seconds: 45
half_open_probe_calls: 3
success_threshold_to_close: 2
google:
error_threshold_pct: 30
latency_threshold_ms: 6000
window_seconds: 60
min_calls_in_window: 10
open_duration_seconds: 30
half_open_probe_calls: 3
success_threshold_to_close: 2
# Локальная модель (self-hosted) — без circuit breaker,
# но с отдельным health check каждые 15 секунд
local_fallback:
health_check_interval_seconds: 15
health_check_timeout_ms: 20002.4. Retry policy с backoff и jitter
# retry_policy.py
from dataclasses import dataclass
import random, time
@dataclass
class RetryPolicy:
max_attempts: int = 3
base_delay_ms: int = 500
max_delay_ms: int = 8000
multiplier: float = 2.0
jitter_pct: float = 0.2
# Ошибки, при которых retry бессмысленен
non_retryable: tuple = (400, 401, 402, 403, 413)
# Ошибки, при которых retry оправдан
retryable: tuple = (429, 500, 502, 503, 504, 529)
def delay_for_attempt(self, attempt: int) -> float:
"""Экспоненциальный backoff с jitter."""
raw = min(
self.base_delay_ms * (self.multiplier ** attempt),
self.max_delay_ms
)
jitter = raw * self.jitter_pct * (random.random() * 2 - 1)
return max(0, (raw + jitter)) / 1000 # в секундах
def should_retry(self, status_code: int, attempt: int) -> bool:
if attempt >= self.max_attempts:
return False
if status_code in self.non_retryable:
return False
return status_code in self.retryable3. Метрики надёжности и SLO
3.1. Четыре уровня SLO для LLM-систем
Стандартные SLO (availability, latency, error rate) необходимы, но для LLM требуют расширения на качественное измерение.
SLO-1: Availability
Цель: 99.5% за скользящее 30-дневное окно
Определение: доля запросов, получивших non-5xx ответ (с учётом fallback-цепочки). Не отдельного провайдера — всей системы с fallback. Измеряется через synthetic probes каждые 30 секунд из двух независимых регионов.
SLO-2: Latency (TTFT для streaming)
Цель: p50 < 1 200 мс, p95 < 4 000 мс, p99 < 8 000 мс
Измеряется end-to-end от получения запроса на gateway до первого токена, отправленного клиенту. Включает время cache lookup, circuit breaker check, выбора провайдера и сетевой задержки до провайдера.
SLO-3: Fallback activation rate
Цель: < 2% запросов за 7 дней
Доля запросов, при обработке которых был активирован хотя бы один fallback. Высокий показатель — ранний сигнал деградации основного провайдера до перехода в outage. Алертинг при превышении 5% за 1-часовое окно.
SLO-4: Quality proxy (выборочный)
Цель: schema_violation_rate < 0.5%, judge_score p10 > 65/100
Доля ответов с нарушением ожидаемой JSON-структуры (для задач со структурированным выводом). LLM-judge score на 5% выборке — нижний перцентиль качества. Это сигнал «тихой деградации» на оси Quality.
3.2. Бюджет ошибок и управление им
Error budget за 30 дней при SLO 99.5% Availability:
30 × 24 × 60 × (1 - 0.995) = 216 минут допустимого downtime
Распределение по причинам (рекомендуемое):
Плановые работы провайдера: 60 мин (28%)
Незапланированные outage: 90 мин (42%)
Deployment окна: 36 мин (17%)
Резерв: 30 мин (14%)При исчерпании error budget на >80% за первые 15 дней месяца — автоматическая заморозка деплоев, которые изменяют логику LLM-вызовов, до конца отчётного периода.
4. Сценарии деградации и recovery
4.1. Сценарий A: Полный outage основного провайдера
Триггер: Anthropic API возвращает 503 на все endpoint'ы.
Детекция: Circuit breaker открывается через 60 секунд (10 вызовов × 25% error threshold при первом же пакете ошибок). Synthetic probe фиксирует degradation независимо.
Автоматический response:
T+0с Первые 503. Retry с backoff (500мс → 1с → 2с).
T+8с 3 retry исчерпаны. Запрос маршрутизируется в fallback.
T+60с Circuit breaker OPEN. Все новые запросы → fallback напрямую.
T+90с Алерт в PagerDuty: "Anthropic circuit OPEN, fallback активен".
T+90с Slack-уведомление: автоматическое, с текущим статусом
и ссылкой на status.anthropic.com.Recovery: Circuit breaker переходит в HALF-OPEN через 30 секунд. 3 probe-запроса к Anthropic. При успехе — возврат трафика в течение 2 минут (canary: 10% → 50% → 100% с шагом 30 секунд).
Ожидаемое влияние на SLO: при полном fallback на OpenAI latency p95 вырастает на 15–25% (другой регион, другая инфраструктура), но availability остаётся выше 99.5%.
4.2. Сценарий B: Rate limit при пиковой нагрузке
Триггер: Anthropic возвращает 429 с Retry-After: 30 при превышении tier-лимита.
Детекция: 429 не открывает circuit breaker немедленно (это ожидаемое поведение при пиках). Вместо этого активируется adaptive throttler.
Adaptive Throttler Logic:
429_rate_last_60s > 5%:
→ Уменьшить concurrent_requests к этому провайдеру на 20%
→ Начать маршрутизировать overflow в fallback (не все запросы)
429_rate_last_60s > 15%:
→ Уменьшить concurrent_requests на 50%
→ Overflow → fallback + предупреждение в Slack
429_rate_last_60s > 30%:
→ Circuit breaker hint: перейти в OPEN превентивно
→ Весь трафик → fallback до нормализацииRecovery: после 60 секунд без 429 — постепенное увеличение concurrent_requests на 10% каждые 30 секунд до восстановления исходного значения.
4.3. Сценарий C: Качественная деградация (тихий отказ)
Это наиболее сложный сценарий: API работает, latency нормальная, но качество ответов деградировало.
Детекция через schema validator:
# quality_monitor.py — асинхронный, не блокирует основной поток
class QualityMonitor:
SAMPLE_RATE = 0.05 # проверяем 5% ответов
async def validate_async(self, response: str, expected_schema: dict,
provider: str, feature: str) -> None:
if random.random() > self.SAMPLE_RATE:
return
violations = self._check_schema(response, expected_schema)
judge_score = await self._llm_judge(response) # отдельная дешёвая модель
await self.metrics.record(
provider=provider,
feature=feature,
schema_violations=len(violations),
judge_score=judge_score
)
# Алерт при системной деградации
if await self._is_degraded(provider, window_minutes=15):
await self.alerting.fire(
severity="warning",
title=f"Quality degradation detected: {provider}",
details=f"judge_score p25={judge_score}, violations={violations}"
)Response: в отличие от availability-инцидентов, quality degradation не требует немедленного переключения. Протокол: уведомление on-call инженера, увеличение sample rate до 20%, ручное решение о переключении. Автоматическое переключение по качеству — только при schema_violation_rate > 10% за 30 минут.
4.4. Сценарий D: Постепенное degradation при долгосрочном росте нагрузки
Триггер: органический рост нагрузки приближает систему к rate limit, latency p95 ползёт вверх неделями.
Детекция: trend alert — p95 TTFT растёт >10% неделя к неделе при стабильном трафике.
Response: не emergency, а capacity planning: запрос на увеличение rate limit у провайдера, рассмотрение перехода на более высокий tier, внедрение дополнительного кэша.
5. Результаты тестов и симуляций
5.1. Chaos engineering: результаты инъекций отказов
Для верификации архитектуры проведена серия chaos-тестов на staging-среде с production-подобным трафиком (1 000 rps, смешанные сценарии).
| Сценарий инъекции | Детекция (сек) | Восстановление (сек) | Влияние на availability |
|---|---|---|---|
| Полный outage primary (Anthropic) | 8–14 | 45–90 | −0.003% |
| Rate limit 100% запросов (429) | 3–6 | 120–180 | −0.001% |
| Latency spike: p99 → 30 сек | 62–74 | 35–50 | −0.008% |
| Partial stream failure (30% запросов) | 18–27 | 20–40 | −0.002% |
| Quality degradation (silent) | 480–900* | Ручное | Нет (quality) |
| Одновременный отказ 2 провайдеров | 12–18 | 60–120 | −0.021% |
*Детекция quality degradation требует накопления выборки — это принципиальное ограничение асинхронного мониторинга.
5.2. Сравнение конфигураций fallback
Три архитектуры тестировались на идентичном трафике с инжектированным 5-минутным outage основного провайдера:
Конфигурация 1 — Нет fallback (baseline):
Availability за период теста: 96.8%. Все запросы в window outage — 503.
Конфигурация 2 — Синхронный fallback (один провайдер-резерв):
Availability: 99.4%. Первые 8–14 секунд деградация (retry timeout), затем полное восстановление. Latency p95 +18% в fallback-режиме.
Конфигурация 3 — Hot-standby с adaptive routing (рекомендуемая):
Availability: 99.91%. Fallback получает 5% трафика в нормальном режиме → circuit breaker переключает весь трафик за 3–5 секунд. Latency p95 +8% в fallback-режиме (модель уже «прогрета»).
5.3. Стоимость резервирования
Hot-standby с 5% трафика на fallback-провайдере добавляет ~5% к общему счёту за API. При среднем счёте $10 000/мес — это $500/мес за страховку от 99.4% → 99.91% availability. При SLA перед корпоративными клиентами с штрафами — многократно оправдано.
6. Практический runbook
RUNBOOK-01: Полный outage LLM-провайдера
Сигнал к активации: PagerDuty alert "Circuit OPEN: [provider]" или самостоятельное обнаружение.
# Шаг 1. Верификация (2 минуты)
curl -s https://status.anthropic.com/api/v2/status.json | jq .status
# Проверить наш internal status dashboard: /internal/llm-health
# Проверить circuit breaker state:
redis-cli GET "circuit:anthropic:state"
# Шаг 2. Подтверждение fallback активен
kubectl logs -n llm-gateway deployment/llm-gateway --tail=50 | grep "fallback"
# Ожидаемый вывод: "routing to fallback: openai (reason: circuit_open)"
# Шаг 3. Мониторинг fallback quality
# Открыть дашборд: /grafana/d/llm-fallback-quality
# Проверить: error_rate_fallback < 2%, latency_p95 < 6000ms
# Шаг 4. Коммуникация (если outage > 5 минут)
# Обновить internal status page (команда: make update-status MSG="LLM degraded mode")
# Уведомить CSM если затронуты enterprise-клиенты (список в /docs/enterprise-contacts)
# Шаг 5. Мониторинг recovery
# Следить за: redis-cli GET "circuit:anthropic:state"
# Переход OPEN → HALF_OPEN → CLOSED — автоматический
# При зависании в OPEN > 15 минут: ручной reset
redis-cli SET "circuit:anthropic:state" "half_open"
redis-cli SET "circuit:anthropic:reset_at" $(date +%s)Эскалация: если fallback также деградирует (error_rate > 10%) — будить Senior SRE, рассматривать активацию local-fallback (self-hosted).
RUNBOOK-02: Качественная деградация (silent)
Сигнал: Alert "Quality degradation: judge_score p25 < 55" или schema_violation_rate > 5%.
# Шаг 1. Квантификация масштаба
# Dashboard: /grafana/d/llm-quality-monitor
# Метрики: judge_score_p10, judge_score_p50, schema_violations_rate
# Временной ряд: когда началось? (correlation с деплоями, временем суток)
# Шаг 2. Изоляция источника
# Деградирует конкретная feature или все?
psql -c "SELECT feature, AVG(judge_score), COUNT(*)
FROM llm_quality_logs
WHERE created_at > NOW() - INTERVAL '1 hour'
GROUP BY feature ORDER BY AVG(judge_score) ASC;"
# Шаг 3. A/B проверка с fallback-провайдером
# Отправить 20 тестовых запросов через primary и fallback,
# сравнить judge_score:
python scripts/quality_ab_test.py --primary anthropic --fallback openai --n 20
# Шаг 4. Принятие решения
# judge_score разница > 10 п.п. в пользу fallback → переключать
# judge_score разница < 5 п.п. → наблюдать, не переключать
# Шаг 5. Если переключение принято:
# Принудительно открыть circuit breaker primary:
redis-cli SET "circuit:anthropic:state" "open"
redis-cli SET "circuit:anthropic:opened_at" $(date +%s)
redis-cli SET "circuit:anthropic:reason" "quality_degradation_manual"
# Установить таймер на review через 30 минутRUNBOOK-03: Rate limit exhaustion
Сигнал: 429_rate > 15% за последние 5 минут.
# Шаг 1. Проверить текущее потребление vs лимит
curl -H "Authorization: Bearer $ANTHROPIC_KEY" \
https://api.anthropic.com/v1/usage # если доступен эндпоинт
# Шаг 2. Идентифицировать источник пика
# Какая feature генерирует аномальный трафик?
redis-cli ZREVRANGE "llm:requests:last5m:by_feature" 0 9 WITHSCORES
# Шаг 3. Тактическое снижение нагрузки
# Вариант A: снизить rate для конкретной feature через feature flag
kubectl set env deployment/api-server LLM_RATE_LIMIT_SUMMARY=50
# Вариант B: включить aggressive caching (снизить TTL до 0 не трогая,
# включить approximate matching с similarity > 0.85)
redis-cli SET "cache:similarity_threshold" "0.85"
# Шаг 4. Проверить очередь запросов
# Если очередь > 1000 — включить load shedding для low-priority запросов
kubectl set env deployment/llm-gateway LOAD_SHEDDING_ENABLED=true \
LOAD_SHEDDING_PRIORITY_THRESHOLD=lowОперативные ссылки и контакты
Полная документация по LLM-интеграции, схемы архитектуры и changelog конфигурации circuit breaker — в технической документации. Актуальный список провайдеров и их характеристик надёжности (публичные SLA, исторический uptime) — в каталоге моделей. Ответы на частые вопросы по fallback-конфигурации и трактовке метрик — в FAQ.
Итоговые тезисы
Надёжность LLM-систем строится не на доверии к провайдеру, а на предположении, что любой провайдер деградирует — вопрос только в том, по какой оси и когда. Устойчивая архитектура отвечает на три вопроса до момента инцидента: как быстро система обнаружит деградацию, куда пойдёт трафик в это время и как будет выглядеть recovery.
Технические элементы — circuit breaker, fallback-цепочка, quality monitor — решают операционную задачу. Runbook решает человеческую. Без обоих компонентов availability SLO остаётся пожеланием, а не инженерным обязательством.
Следующий материал серии: «Capacity planning для LLM-зависимостей: как прогнозировать rate limit и управлять tier-апгрейдами». Следите за обновлениями в ленте документации.