Rate limiting и retry стратегии для LLM API: exponential backoff, circuit breaker, queue
Под нагрузкой LLM API падает. Не «всегда», а в худший момент — когда пользователей больше, чем обычно. Без правильной стратегии 429 («слишком много запросов») и 503 («провайдер перегружен») превращают временный пик в полный отказ сервиса: клиенты ретраят, нагрузка растёт лавиной, очередь разбухает, всё падает. Через единый шлюз provod.ai (Claude Opus 4.7 — 350/1790 ₽, GPT-5.5 — 350/2150 ₽, DeepSeek V4 Pro — 30/60 ₽) ошибки нормализованы под OpenAI-формат — одна и та же стратегия работает для всех моделей, что упрощает переключение между провайдерами при их деградации.
Этот гайд — production-стек защиты: Tenacity для exponential backoff с jitter, circuit breaker для быстрого обхода падшего провайдера, token bucket для собственного rate limiting, конкретные коды и таймауты для всех ключевых ошибок. С работающими примерами кода, конфигами retry policy и метриками для мониторинга. оплата в рублях по договору, полный пакет закрывающих документов.
TL;DR — три слоя защиты
- Token bucket на своей стороне — не отправляем больше N RPS, не дожидаясь 429 от провайдера.
- Exponential backoff с jitter через Tenacity — на редкие 429/503 ждём 1с±50%, 2с±50%, 4с±50%, 8с±50%, до 3 попыток.
- Circuit breaker — если 5 фейлов подряд за 30 сек, открываем «выключатель» на 60 сек и идём в fallback (другой провайдер или кэш). Эта статья — production-расширение нашего pillar-гида полный технический гид по LLM API на Python: токены, function calling, streaming, RAG, async/batch.
429 и 503: что говорят провайдеры
Реальные сообщения от OpenAI, Anthropic и Google:
К обоим прикладывается заголовок retry-after в секундах (но не всегда — OpenAI ставит, Anthropic иногда нет). Стратегия: сначала смотрим retry-after, потом считаем свой backoff.
Документация лимитов: OpenAI rate limits, Anthropic rate limits. У provod.ai лимиты выставляются на уровне шлюза и едины для всех моделей за одним ключом — это упрощает планирование емкости.
Tenacity: exponential backoff с jitter за 10 строк
Установка: pip install tenacity.
Минимальный декоратор для LLM-вызова:
Разберём параметры:
- wait_random_exponential(multiplier=1, max=60) — exponential backoff с jitter. Реальные задержки: 0.5–1с, 1–2с, 2–4с, 4–8с, 8–16с (но не больше 60).
- stop_after_attempt(5) — 5 попыток включая первую (то есть 4 retry).
- retry_if_exception_type — ретраим только на эти исключения. На 400/401/403 не ретраим (там APIStatusError, не входит в список).
- reraise=True — после 5 фейлов поднимаем последнее исключение, а не оборачиваем в RetryError.
Альтернатива — exponential без полного jitter (более предсказуемая):
Здесь начальная задержка 1с, удваивается до 60, jitter ±2с. Подходит когда вы хотите более предсказуемый минимум.
Уважение к retry-after
Если провайдер вернул retry-after, надо ждать ровно столько, а не своё. Tenacity поддерживает callback на пере-расчёт wait:
Этот паттерн критичен для production: если провайдер сказал «подожди 30 секунд», а вы ретраите через 1с — получите ещё один 429 и быстро попадёте в более строгий лимит.
Token bucket: собственный rate limiting
Tenacity лечит редкие 429, но если вы делаете 100 RPS на лимите 50 RPS — будете получать 429 на каждом втором запросе. Правильно — не доводить до 429, ограничивать себя.
Token bucket алгоритм: ведро на N запросов, пополняется со скоростью R/сек, каждый запрос забирает 1 токен. Простая реализация на asyncio:
Для распределённого приложения (несколько worker'ов) — Redis-based bucket через атомарный Lua-скрипт:
Lua-скрипт атомарен в Redis — никакого race condition между несколькими worker'ами. Для русского B2B на 10–50 RPS этого хватит с запасом. Подробнее про асинхронные batch-сценарии — Async и Batch API LLM: 50% скидка.
Circuit breaker: защита от каскадных фейлов
Сценарий: GPT-5.5 «лёг» на 5 минут. Без circuit breaker каждый запрос ждёт 30 секунд таймаута, ретраит 5 раз, итого 5 × 8 = 40 секунд на один запрос. 50 RPS × 40 сек = 2000 зависших задач. Очередь забивается, latency растёт, всё ложится.
Circuit breaker меняет это: после 5 фейлов подряд он «открывается» и следующие 60 секунд сразу отдаёт ошибку (или вызывает fallback), не пытаясь дозвониться. Состояния:
- closed — нормальная работа, запросы идут.
- open — фейлов слишком много, все запросы сразу падают/в fallback.
- half_open — пробный режим: один запрос идёт, успех → closed, фейл → опять open.
Реализация на pure Python (без зависимостей):
Для production — библиотеки pybreaker или circuitbreaker с готовыми декораторами и метриками. Через provod.ai fallback между моделями делается одной заменой model="..." — это снижает риск зависимости от одного провайдера. См. Сравнение цен LLM 2026 для выбора недорогих fallback-моделей.
Полный стек: token bucket + Tenacity + circuit breaker
Соединяем всё вместе — production-grade LLM-клиент:
Что здесь работает:
- Token bucket не даёт превысить 30 RPS — большая часть 429 не случается.
- Tenacity ретраит редкие 429/timeout с jitter, уважает retry-after.
- Circuit breaker ловит длительные деградации и быстро уходит в fallback.
- Fallback на Sonnet (в 1.7 раз дешевле) — деградация качества вместо полного отказа.
Это базовая структура. Для batch-задач добавьте Async и Batch API LLM с 50% скидкой. Для агентов с tool calling — Function calling tool use. Для отслеживания latency и cost — Логирование и observability LLM.
Метрики для мониторинга
Что собирать в Prometheus:
- Метрика: llm_requests_total{model,status} • Тип: Counter • Алерт: error_rate > 5% за 5 мин
- Метрика: llm_request_duration_seconds{model} • Тип: Histogram • Алерт: p99 > 60 сек
- Метрика: llm_retries_total{model,attempt} • Тип: Counter • Алерт: retry_rate > 20% — провайдер деградирует
- Метрика: llm_token_bucket_wait_seconds{model} • Тип: Histogram • Алерт: p95 > 2 сек — нужно увеличить лимит
- Метрика: llm_circuit_breaker_state{model} • Тип: Gauge • Алерт: state=open > 30 сек — алерт оператору
- Метрика: llm_fallback_total{from_model,to_model} • Тип: Counter • Алерт: резкий рост — фейл primary провайдера
- Метрика: llm_429_total{model} • Тип: Counter • Алерт: рост — token bucket не справляется
Точные пороги зависят от вашей нагрузки. Снимайте baseline в первую неделю, потом настраивайте алерты на отклонения. См. также B2B-чеклист 12 вопросов поставщику LLM API — раздел про SLA и согласованные RPM/TPM лимиты.
Антипаттерны: чего не делать
- Retry на 4xx ошибках (кроме 429). 400/401/403/422 не ретраятся — это баги в коде. Каждая попытка тратит лимит и деньги.
- Бесконечный retry без stop_after_attempt. Пользователь будет ждать вечность, очередь забьётся.
- Retry без jitter. 100 клиентов после 429 ретраят в одну миллисекунду — снова 429. Thundering herd.
- Игнорировать retry-after. Если провайдер сказал 30с — он знает что говорит. Ретрай через 1с попадёт в более жёсткий лимит.
- Circuit breaker без fallback. Если просто бросать CircuitOpenError, клиент получит фейл. Имеет смысл только когда есть план B (другая модель, кэш, деградированный режим).
- Token bucket с capacity=rate. Bucket нужен для burst — если capacity = rate, вы не получаете преимущества над fixed-window лимитом.
- Один circuit breaker на все модели. Если Opus упал, Sonnet ещё работает. Нужен per-model breaker.
- Retry на тимауте без сохранения partial state. Streaming-ответ уже частично оплачен — сохраняйте и используйте, не теряйте.
Production-чеклист
- [ ] Token bucket на своей стороне, rate = 80% от лимита провайдера.
- [ ] Tenacity с wait_random_exponential(max=60) и stop_after_attempt(5).
- [ ] Кастомный wait для уважения retry-after хедера.
- [ ] retry_if_exception_type только на 429/5xx/network. Никаких 4xx.
- [ ] Circuit breaker per-model с recovery_timeout=60 сек.
- [ ] Fallback на дешёвую модель (Sonnet вместо Opus, GPT-5.4 вместо GPT-5.5).
- [ ] timeout на HTTP-клиент: connect 5, read 120, write 10, pool 5.
- [ ] max_retries=0 в SDK — все ретраи через Tenacity, не дублировать.
- [ ] Метрики Prometheus: requests_total, duration, retries, 429, bucket_wait, breaker_state.
- [ ] Алерты: error_rate > 5%, retry_rate > 20%, breaker_state=open > 30 сек.
- [ ] Логи retry с trace_id для отслеживания флапов.
- [ ] Распределённый bucket через Redis Lua для multi-worker setup.
Через provod.ai fallback между моделями делается одной заменой model="...". Цены прозрачны 1-в-1 с провайдером по курсу ЦБ — для дешёвых fallback подходят DeepSeek V4 Pro (30/60 ₽) и Qwen 3.6 Plus (20/130 ₽). Полное руководство по выбору модели для конкретной задачи — в Сравнении цен LLM 2026.
FAQ
Чем отличаются rate limit, retry и circuit breaker?
Rate limit — собственный лимит запросов (не больше N RPS). Retry — попытки повтора при временной ошибке (429/503/timeout). Circuit breaker — защита от каскадных фейлов: если провайдер «лёг», временно перестаём ходить и идём в fallback. Три слоя дополняют, не заменяют друг друга.
Почему jitter обязателен?
Без jitter все клиенты после 429 ретраят ровно через 1, 2, 4 секунды — снова создают пик. Thundering herd. Jitter — случайная добавка ±25–50% размазывает нагрузку. Tenacity делает через wait_random_exponential. Без jitter retry лечит одного клиента, но ломает 100.
Какие ошибки retry'ить?
Retry: 429, 500/502/503/504, сетевые (ConnectionError, Timeout). НЕ retry: 400, 401, 403, 404, 422, 413, content_filter. На 429 — обязательно читать retry-after хедер и использовать вместо своего backoff.
Что такое token bucket?
Алгоритм собственного rate limiting: ведро на N токенов, пополняется со скоростью R/сек, каждый вызов забирает 1. Если пусто — ждём. Даёт burst-friendly поведение: 30 быстрых запросов подряд, потом ожидание. Нужен когда несколько типов задач делят один лимит провайдера.
Когда нужен circuit breaker?
Когда есть fallback-сценарий (другой провайдер, кэш, деградированный режим). Если Opus 4.7 не отвечает 30 сек, circuit открывается, следующие 60 сек запросы идут в fallback без попыток дозвониться. Без breaker один сбой утопит весь сервис.
Tenacity или backoff?
Tenacity — более популярна, активно поддерживается, гибче. backoff проще, но менее гибка. Для production — Tenacity: больше функций, лучше asyncio интеграция, легко комбинируется с circuit breaker. pip install tenacity без зависимостей.
provod.ai — российский LLM API-агрегатор
Один OpenAI-совместимый endpoint ко всем флагманам: OpenAI (GPT-5.5, GPT-5.4), Anthropic (Claude Opus 4.7, Sonnet 4.6), Google (Gemini 3.1 Pro, 3.5 Flash), DeepSeek V4 Pro, Qwen 3.6 Plus.
Цены 1-в-1 с провайдером по курсу ЦБ — без наценки на токены. Оплата в рублях по договору, полный пакет закрывающих документов (договор-оферта, счёт, акт, счёт-фактура, УПД 5.03 через ЭДО). Без VPN — легальный B2B-сервис в России.
Если статья была полезной — попробуйте provod.ai: главная страница · каталог моделей · документация