# Multi-provider LLM-архитектура: failover, fallback и роутинг между API

> Мульти-провайдерная LLM-архитектура на LiteLLM: автоматический failover, fallback chains, роутинг по задачам, балансировка стоимости. Circuit breaker и production-конфигурация.
> Author: Roman Belov · Published: 2026-02-24 · Source: https://futurecraft.pro/ru/blog/multi-provider-llm-architecture/

Статус-страницы OpenAI и Anthropic фиксируют десятки инцидентов в год у каждого — от повышенного error rate до многочасовых отказов API.

99.7% uptime звучит надёжно. В пересчёте - ~26 часов простоя в год. Для приложения, обрабатывающего тысячи LLM-запросов в день, один плохой месяц у одного провайдера означает потерю пользователей.

Статья о том, как построить LLM-инфраструктуру, которая переживает аварии, использует разницу в ценах и даёт менять модели без правок в коде.

## Зачем несколько провайдеров

Четыре причины. Любой одной хватает.

**Отказоустойчивость.** Провайдеры падают. Не "иногда" - регулярно. У обоих лидеров рынка — десятки инцидентов в год по их собственным статус-страницам. Когда единственный провайдер лежит, приложение лежит. Когда есть fallback - запросы уходят на другого провайдера, пользователь не замечает.

**Rate limits.** Провайдеры меняют лимиты в одностороннем порядке. Летом 2025 Anthropic ввёл еженедельные лимиты для активных пользователей Claude Code. OpenAI распределяет доступ по "тирам" расходов. С одним провайдером внезапное снижение лимита - каскадный сбой без запасного варианта.

**Стоимость.** Разброс цен - порядки, не проценты. DeepSeek-V3 стоит ~$0.27 за миллион входных токенов. GPT-5.4 - ~$2. Это разница ~7 раз на входе. Не каждая задача требует самой дорогой модели. Классификация, извлечение данных из текста, генерация эмбеддингов - всё это можно маршрутизировать на дешёвые модели без потери качества.

**Deprecation.** Модели снимают с поддержки. Snapshot `chatgpt-5.4-latest` удалён из API 17 февраля 2026, а из ChatGPT модель убрали 13 февраля - предупредили за три месяца. GPT-4.5, запущенный в феврале 2025 по цене $75/$150 за миллион токенов, тоже отправлен на пенсию. Цикл жизни флагманской модели - 12-24 месяца. Приложение, завязанное на конкретную модель, каждые 1-2 года попадает в вынужденную миграцию.

## LiteLLM: единая точка входа

LiteLLM - open-source proxy, который превращает вызовы к разным LLM-провайдерам в единый OpenAI-совместимый API. 36 700 звёзд на GitHub, поддержка 100+ провайдеров. Overhead самого прокси - P95 около 8 мс (по данным LiteLLM).

Вместо прямых вызовов к API провайдеров все запросы идут через LiteLLM. Он принимает стандартный `/v1/chat/completions`, маршрутизирует на нужного провайдера, возвращает ответ в едином формате.

```
Приложение
    │
    │  POST /v1/chat/completions
    │  model: "deepseek/deepseek-chat"
    ▼
┌──────────┐
│  LiteLLM │ → routing → DeepSeek API
│  Proxy   │ → fallback → Google Gemini API
│          │ → fallback → Anthropic API
└──────────┘
    │
    │  OpenAI-compatible response
    ▼
Приложение
```

На практике:

- **Смена модели - одна строка.** Поменять `deepseek/deepseek-chat` на `google/gemini-3.5-flash` - это изменение параметра `model` в запросе. Не рефакторинг, не миграция SDK.
- **Единый формат.** Независимо от провайдера, ответ приходит в формате OpenAI Chat Completion. Клиентский код не знает, какой провайдер обработал запрос.
- **Centralized auth.** API-ключи провайдеров хранятся в конфигурации LiteLLM, а не в каждой edge function. Один LiteLLM-ключ для клиента, десяток ключей провайдеров за кулисами.
- **Rate limiting на уровне прокси.** RPM/TPM лимиты, per-user квоты, бюджетные ограничения - всё в одном месте.

### Настройка

LiteLLM конфигурируется YAML-файлом. Минимальная конфигурация для двух провайдеров:

```yaml
model_list:
  - model_name: fast-chat
    litellm_params:
      model: google/gemini-3.5-flash
      api_key: os.environ/GOOGLE_API_KEY
  - model_name: fast-chat           # тот же model_name = fallback
    litellm_params:
      model: deepseek/deepseek-chat
      api_key: os.environ/DEEPSEEK_API_KEY
  - model_name: deep-analysis
    litellm_params:
      model: anthropic/claude-sonnet-4-6
      api_key: os.environ/ANTHROPIC_API_KEY

router_settings:
  routing_strategy: usage-based-routing
  enable_pre_call_checks: true       # проверка лимитов до вызова
```

Два deployment с одним `model_name` - LiteLLM автоматически маршрутизирует между ними и использует второй как fallback при сбое первого.

### Стратегии маршрутизации

LiteLLM поддерживает четыре стратегии:

| Стратегия | Как работает | Когда использовать |
|-----------|-------------|-------------------|
| `simple-shuffle` | Случайный выбор | По умолчанию, когда всё равно |
| `least-busy` | На наименее загруженный | Балансировка нагрузки |
| `usage-based-routing` | Фильтрует по TPM/RPM лимитам | Не превышать квоты провайдера |
| `latency-based-routing` | На самый быстрый | Минимизация времени ответа |

`usage-based-routing` - самая полезная для production. LiteLLM отслеживает текущий расход TPM/RPM через Redis и исключает deployment, который близок к лимиту. Запрос уходит на deployment с наименьшим текущим потреблением.

## Fallback chains: primary → secondary → emergency

Fallback chain - цепочка провайдеров, которая срабатывает автоматически при сбое. Первый провайдер упал - запрос уходит на второй. Второй перегружен - на третий.

Какие ошибки триггерят fallback:

- **429** - rate limit exceeded (провайдер перегружен)
- **500, 502, 503, 504** - серверные ошибки (провайдер лежит)

Что НЕ триггерит:

- **400** - невалидный запрос (проблема в нашем коде, не в провайдере)
- **401, 403** - проблема с ключом (fallback не поможет)

В LiteLLM это работает автоматически: несколько deployment с одним `model_name` - встроенный fallback. Для разных `model_name` можно настроить fallback-список:

```yaml
router_settings:
  fallbacks: [
    {"fast-chat": ["backup-chat"]},
    {"deep-analysis": ["backup-analysis"]}
  ]
```

### Практический пример

Три уровня fallback для чат-бота:

1. **Primary:** `google/gemini-3.5-flash` - быстрый, дешёвый, хорошее качество
2. **Secondary:** `deepseek/deepseek-chat` - дешевле, чуть медленнее
3. **Emergency:** `anthropic/claude-haiku-4-5` - дороже, но стабильный

Gemini вернул 503 - запрос ушёл на DeepSeek. DeepSeek вернул 429 (rate limit) - запрос ушёл на Claude Haiku. Пользователь получил ответ, возможно чуть медленнее.

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

## Task-based routing: разные задачи → разные модели

Не все задачи одинаковы. Генерация маршрута путешествия требует рассуждений и большого контекста. Генерация заголовка для чата - 10 токенов на входе, 5 на выходе. Обогащение POI-данных - парсинг структурированного текста.

Отправлять всё на одну модель - переплата или потеря качества.

Паттерн: определить тип задачи → выбрать оптимальную модель.

| Задача | Модель | Почему |
|--------|--------|--------|
| AI-чат (быстрые ответы) | Gemini 3.5 Flash | Быстрый, дешёвый, хороший для диалога |
| Анализ поездки, извлечение данных | DeepSeek Chat | Дёшево, хорошо работает со структурированным выводом |
| Генерация маршрута (пайплайн) | DeepSeek Chat + валидация | Сложная задача, но DeepSeek справляется при правильных промптах |
| Генерация заголовков | Gemini 3.5 Flash | Тривиальная задача, не стоит дорогой модели |
| Оркестрация (мульти-шаговые агенты) | Claude Haiku 4.5 | Хорошо следует инструкциям, предсказуемый |

Модель указывается в каждом запросе через параметр `model`. Поскольку все вызовы идут через LiteLLM, переключение модели - замена строки.

### Управление моделями через Langfuse

Модель можно вынести из кода в конфигурацию промпта. В Langfuse каждый промпт хранит `config.model`:

```json
{
  "name": "ai-chat-travel-assistant",
  "config": {
    "model": "google/gemini-3.5-flash",
    "temperature": 0.7,
    "max_tokens": 4096
  }
}
```

Edge function получает промпт из Langfuse, берёт модель из конфига и передаёт в LiteLLM:

```typescript
const promptTemplate = await getLangfusePrompt('ai-chat-travel-assistant', langfuseConfig);
const model = promptTemplate.config?.model || 'google/gemini-3.5-flash';

const response = await fetch(`${LITELLM_URL}/v1/chat/completions`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${LITELLM_KEY}`,
  },
  body: JSON.stringify({
    model,
    messages: compiledMessages,
    temperature: promptTemplate.config?.temperature ?? 0.7,
  }),
});
```

Смена модели для любого промпта - через UI Langfuse, без деплоя кода. Промпт тоже можно отредактировать и сразу пометить как `production`.

Подробнее о Langfuse - в отдельной [статье про LLM observability](/ru/blog/llm-observability-langfuse/).

## Стоимость: порядок имеет значение

Разница в ценах между провайдерами - на порядки.

| Модель | Вход ($/1M) | Выход ($/1M) | Относительно GPT-5.4 |
|--------|------------|-------------|---------------------|
| DeepSeek-V3 | ~$0.27 | ~$1.10 | ~7x дешевле |
| Mistral Medium 3 | ~$0.40 | ~$2.00 | ~5x дешевле |
| Gemini 3.1 Pro | ~$2.00 | ~$12.00 | ≈ паритет |
| GPT-5.4 | ~$2 | ~$8 | baseline |
| Claude Sonnet 4.6 | ~$3 | ~$15 | ~1.5x дороже |
| Claude Opus 4.8 | $5 | $25 | ~2.5x дороже |

> **Примечание:** Цены приблизительные и часто меняются. Проверяйте актуальные тарифы на официальных страницах провайдеров перед расчётами.

Исследователи из LMSYS (RouteLLM) показали, что грамотная маршрутизация сокращает расходы на 85%+ на бенчмарке MT Bench без заметной потери качества. Суть подхода: 90% "простых" запросов обрабатываются дешёвой моделью, 10% "сложных" - дорогой.

В production это выглядит проще: выбор модели по типу задачи. Чат, генерация заголовков, извлечение данных - дешёвые модели. Сложный анализ, рассуждения, мульти-шаговые агенты - дорогие.

## Мониторинг: как понять, что провайдер деградирует

Провайдер может деградировать без полного падения. Латентность растёт с 200 мс до 5 секунд. Процент ошибок поднимается с 0.1% до 3%. Качество ответов падает (модель начинает "галлюцинировать" чаще).

Что мониторить:

| Метрика | Порог тревоги | Что делать |
|---------|--------------|-----------|
| P95 латентность | > 2x от baseline | Включить fallback |
| Error rate | > 2% | Включить fallback |
| Timeout rate | > 1% | Снизить timeout, включить fallback |
| Token cost | Выход за бюджет | Переключить на дешёвую модель |

LiteLLM пишет логи каждого вызова: провайдер, модель, латентность, статус, количество токенов. Для визуализации - любой стек: Grafana, Datadog, собственный дашборд. Langfuse добавляет трейсинг на уровне промптов: какой промпт, какая версия, какой результат.

Самая полезная метрика - **отношение fallback-вызовов к общему количеству**. Если больше 10% запросов уходят на fallback - основной провайдер деградирует. Если больше 30% - пора менять primary.

## Circuit Breaker для LLM-вызовов

Circuit Breaker - паттерн, который предотвращает каскадные сбои. Когда внешний сервис начинает стабильно отвечать ошибками, circuit breaker "размыкает цепь" и перестаёт отправлять запросы. Вместо того чтобы ждать timeout по 60 секунд на каждый запрос к лежащему провайдеру, система моментально отвечает ошибкой.

Три состояния:

```
CLOSED (норма)          OPEN (сервис лежит)       HALF-OPEN (проверка)
    │                       │                          │
    │  3 ошибки подряд      │  60 секунд прошло        │  1 успех
    │─────────────────►     │──────────────────►       │──────────────►  CLOSED
    │                       │                          │
    │                       │  запросы отклоняются     │  1 ошибка
    │                       │  мгновенно               │──────────────►  OPEN
```

Конфигурация для LLM-вызовов отличается от обычных API. Модели отвечают медленнее - timeout 60 секунд вместо 10. Порог ошибок ниже - 3 сбоя вместо 5, потому что каждый LLM-запрос дорогой. Период восстановления длиннее - 60 секунд вместо 30.

```typescript
const LLM_CIRCUIT_CONFIG = {
  failureThreshold: 3,       // 3 сбоя → circuit open
  resetTimeoutMs: 60_000,    // 60 секунд в состоянии open
  successThreshold: 1,       // 1 успех в half-open → closed
  ignoredStatusCodes: [400, 404],  // клиентские ошибки не считаются
};
```

В serverless-окружении (Deno Edge Functions, AWS Lambda) каждый вызов потенциально запускается в новом изоляте. Circuit breaker, хранящий состояние в памяти, теряет его при создании нового изолята. Для распределённого circuit breaking нужно внешнее хранилище - Redis или таблица в базе.

Подробнее о реализации - в [статье про Circuit Breaker в Edge Functions](/ru/blog/circuit-breaker-deno-edge-functions/).

## Альтернативы LiteLLM

LiteLLM - не единственный вариант. Выбор зависит от приоритетов.

| Инструмент | Фокус | Модели | Цена | Подходит для |
|-----------|-------|--------|------|-------------|
| LiteLLM | SDK + proxy | 100+ | Open source | Разработчики, self-hosted |
| OpenRouter | Managed API | 500+ | 5.5% комиссия | Быстрый старт, доступ ко всем моделям |
| Portkey | Enterprise gateway | 1600+ | от $49/мес | Compliance, governance, команды |
| Helicone | Observability | Любые | Free tier / $49 | Мониторинг, кеширование |

**OpenRouter** - managed-альтернатива. Не нужно поднимать свой прокси. 500+ моделей от 60+ провайдеров. Комиссия 5.5% при покупке кредитов, цены моделей - pass-through без наценки. Привлёк $40 млн инвестиций в июне 2025, run-rate расходов клиентов на инференс превысил $100 млн. Удобен для прототипирования и проектов, где self-hosted инфраструктура избыточна.

**Portkey** - для команд с требованиями compliance. PII-редакция, обнаружение jailbreak, аудит-трейлы, SSO. Если в проекте нужна корпоративная безопасность - стоит смотреть сюда.

**Helicone** - open-source, фокус на observability. Gateway на Rust с P50 латентностью 8 мс. Встроенное кеширование ответов снижает расходы на повторных запросах. Хорош как дополнение к LiteLLM, не как замена.

LiteLLM выигрывает по контролю: self-hosted, полный доступ к конфигурации, бесплатный. Для production-приложения с несколькими провайдерами - лучшее соотношение контроля и трудозатрат.

## Где это не работает

Multi-provider не бесплатен. За гибкость приходится платить.

**Prompt caching ломается при fallback.** Anthropic и OpenAI кешируют промпты для ускорения повторных вызовов. Если запрос ушёл на fallback-провайдера, кеш первого не используется. Для длинных system-промптов это заметная потеря в латентности и стоимости. Продвинутые реализации используют project-level affinity - запросы одного проекта по возможности идут на одного провайдера.

**Консистентность ответов.** Разные модели генерируют разный текст. Для чат-бота это нормально. Для пайплайна со строгой JSON-схемой - риск. DeepSeek может вернуть `"rating": 4.5`, а Gemini - `"rating": "4.5"`. Валидация на выходе обязательна.

**Дополнительная инфраструктура.** LiteLLM - это сервер, который нужно поднять, мониторить и обновлять. Для одного провайдера достаточно API-ключа. Для пяти провайдеров через LiteLLM - Docker-контейнер, Redis для rate limiting, мониторинг. Операционная сложность растёт.

**Отладка усложняется.** "Запрос упал" - на каком провайдере? На каком fallback-уровне? С какой ошибкой? Логирование каждого шага обязательно: провайдер, модель, латентность, статус, attempt number. Без этого - отладка вслепую.

**Не все API одинаковы.** OpenAI-совместимый формат покрывает `/chat/completions`. Специфичные фичи провайдеров (vision API, function calling с конкретными форматами, streaming с tool use) могут работать по-разному через прокси. Перед включением нового провайдера в fallback chain - тестирование конкретных сценариев.

## С чего начать

Если приложение сейчас работает с одним провайдером, миграция на multi-provider не требует переписывания.

**Шаг 1: LiteLLM proxy.** Поднять Docker-контейнер. Подключить текущего провайдера. Все вызовы перенаправить через прокси. На этом этапе ничего не меняется - тот же провайдер, тот же результат. Но появляется единая точка, через которую проходят все LLM-вызовы.

**Шаг 2: Второй провайдер как fallback.** Добавить DeepSeek или Gemini Flash как второй deployment с тем же `model_name`. LiteLLM автоматически переключит на него при сбое основного. Протестировать fallback - вручную отключить основной провайдер.

**Шаг 3: Task-based routing.** Проанализировать вызовы: какие задачи дорогие, какие дешёвые. Перевести дешёвые задачи на дешёвую модель. Генерация заголовков, классификация, извлечение данных - DeepSeek. Чат, рассуждения - Gemini или Claude.

**Шаг 4: Мониторинг.** Подключить Langfuse или аналог. Трейсить каждый вызов: провайдер, модель, латентность, стоимость. Настроить алерты на деградацию.

Весь процесс - от нуля до production multi-provider - занимает пару дней. LiteLLM proxy поднимается за 30 минут. Добавление провайдера - строка в конфиге. Основные затраты - тестирование fallback-сценариев и настройка мониторинга.

---

*Нужна помощь с построением мульти-провайдерной LLM-инфраструктуры? Я помогаю стартапам внедрять AI-решения и строить продукты — [belov.works](https://belov.works).*
