Все статьи
4 мин чтения

Устойчивость AI-агента к сбоям LLM-провайдеров: fallback-цепочки и Circuit Breaker в CodeLab

Что делать агенту, когда LLM-провайдер отвечает 429, падает по таймауту или перегружен: классификация ошибок, последовательный fallback и Circuit Breaker на примере CodeLab.

CodeLabAI-агентыLLM

Контекст

AI-агент зависит от внешнего LLM API так же, как любой сервис зависит от своей базы данных. Только это API живёт в чужой инфраструктуре: провайдер может упереться в лимит запросов, ответить по таймауту, вернуть внутреннюю ошибку или сообщить, что модель перегружена.

Для чат-бота сбой — это одно неудачное сообщение. Для агента, который выполняет план из многих шагов, — потерянная работа. В CodeLab агент в одном цикле может сделать до 10 итераций вызовов инструментов, создавая и редактируя файлы проекта. Если провайдер упал на седьмом шаге, пользователь не должен начинать всё сначала.

Поэтому в CodeLab встроена fallback-система: при ошибке основного провайдера запрос автоматически уходит резервному.

Шаг 1: не все ошибки одинаковые

Первое решение — разделить ошибки на те, которые имеет смысл повторить у другого провайдера, и те, которые не имеет.

Retryable — переключаемся на следующего провайдера:

Тип Что случилось Пример
rate_limit Превышен лимит запросов HTTP 429
timeout Таймаут запроса Connection timeout
internal_error Внутренняя ошибка провайдера HTTP 500
service_unavailable Сервис недоступен HTTP 503
model_unavailable Модель временно недоступна Model overloaded

Non-retryable — сразу возвращаем ошибку:

Тип Что случилось
auth_error Ошибка аутентификации
invalid_request Некорректный запрос

Логика простая: временная перегрузка у одного провайдера никак не говорит о состоянии другого, поэтому переключение имеет смысл. А неверный ключ или некорректный запрос — проблема конфигурации, которую нужно показать пользователю, а не прятать за перебором провайдеров.

Шаг 2: последовательный fallback

Базовая стратегия — sequential: провайдеры перебираются в заданном порядке, пока один не обработает запрос успешно.

[llm.fallback]
enabled = true
strategy = "sequential"
order = ["openai", "openrouter", "ollama"]
max_attempts = 3
retry_on = ["rate_limit", "timeout", "internal_error"]
  1. Запрос уходит первому провайдеру.
  2. При retryable-ошибке — следующему по списку.
  3. При успехе ответ возвращается агенту.
  4. Если не справился никто — агент получает явную ошибку AllProvidersFailed.

Параметр retry_on позволяет сузить набор ошибок, на которые реагирует fallback. Если переключение «не срабатывает», первое, что стоит проверить, — есть ли этот тип ошибки в списке.

Шаг 3: Circuit Breaker

Одного fallback недостаточно. Представьте, что основной провайдер лёг надолго. Тогда каждый запрос сначала ждёт таймаут у него и только потом уходит резервному — агент становится медленным, хотя рабочий провайдер есть.

Circuit Breaker решает это: он отслеживает ошибки каждого провайдера и временно исключает сбойного из цепочки.

Состояние Что значит
Closed Провайдер работает нормально
Open Слишком много ошибок — провайдер исключён из цепочки
HalfOpen После паузы провайдер получает тестовый вызов
circuit_breaker = CircuitBreaker(
    failure_threshold=5,    # ошибок до открытия цепи
    reset_timeout=60,       # секунд до попытки восстановления
    half_open_max_calls=1,  # тестовых вызовов в HalfOpen
)

После failure_threshold ошибок провайдер перестаёт получать запросы. Через reset_timeout секунд он переходит в HalfOpen и получает пробный вызов: успех возвращает его в строй, ошибка — снова исключает.

Шаг 4: наблюдаемость

Автоматическое переключение не должно быть незаметным — иначе вы узнаете о проблемах с основным провайдером только из счёта. В CodeLab есть шина событий провайдеров, и на событие FallbackTriggered можно подписаться:

from codelab.server.llm.events import event_bus, FallbackTriggered

async def on_fallback(event: FallbackTriggered) -> None:
    print(f"Fallback: {event.from_provider} → {event.to_provider}")

event_bus.subscribe(FallbackTriggered, on_fallback)

Рецепты цепочек

  • Надёжность: openai → openrouter → ollama. Облачный провайдер основной, агрегатор — резерв, локальная модель через Ollama — последний рубеж, который работает даже без интернета.
  • Экономия: ollama → openrouter → openai. Сначала бесплатная локальная модель, облако — только когда она не справилась.
  • Разработка: провайдер mock с выключенным fallback — предсказуемые ответы без трат на API.

Что дальше

Сейчас в CodeLab реализована последовательная стратегия. Архитектура оставляет точки расширения для стратегий выбора провайдера по стоимости, по задержке и «умного» выбора на основе ML — их можно подключить, не меняя остальной код агента.

Выводы

  1. Классифицируйте ошибки. Повторять имеет смысл только временные сбои; ошибки конфигурации нужно показывать сразу.
  2. Fallback без Circuit Breaker медленный. Не давайте лежащему провайдеру съедать таймаут на каждом запросе.
  3. Держите локальную модель в конце цепочки. Это единственный провайдер, который не зависит от чужой инфраструктуры.
  4. Делайте переключения видимыми. Событие о fallback должно попадать в логи и мониторинг.

Документация по настройке fallback и LLM-провайдеров — на сайте CodeLab.