Для AI-агентов: markdown этой страницы — /docs-content/ai/chat/rate-limits.md индекс документации — /llms.txt

Лимиты запросов и повторы

Обращения к моделям ограничены двухуровневой корзиной, а при пиковой нагрузке платформа может ненадолго отказывать в обслуживании. Оба сигнала — 429 и 503 — означают «повтори позже», а не «запрос неверен». Ни один из них не списывает квоту.

Два уровня корзины

  • На ключ — по умолчанию 600 запросов в минуту. Корзина привязана к ключу, а не к IP-адресу: клиент за NAT не делит её с другими ключами, а один и тот же ключ с разных адресов имеет общий счётчик.
  • На пользователя — по умолчанию 1500 запросов в минуту суммарно по всем ключам одного пользователя. Это защищает платформу, когда один аккаунт раздаёт десяток ключей агентам и каждый выбирает свой лимит.

Запрос проверяется сначала по ключу, затем по пользователю. Первый исчерпанный счётчик выдаёт 429.

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

Ответ `429`

JSON
{
  "error": {
    "type": "rate_limit_exceeded",
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded (per-key). Limit: 600 per minute. Retry after 12 seconds.",
    "scope": "per-key",
    "limit": 600,
    "retryAfter": 12
  }
}

Поле scope принимает одно из двух значений:

  • per-key — исчерпан лимит конкретного ключа. Снизьте число одновременных запросов этого ключа.
  • per-user — исчерпан общий лимит аккаунта. Снизьте суммарную нагрузку по всем ключам или попросите администратора платформы поднять лимит.

Вместе с 429 приходят заголовки:

  • Retry-After: <секунды> — сколько ждать перед следующей попыткой.
  • X-RateLimit-Scope: per-key | per-user — уровень, в который упёрлись. Полезно для логов и метрик клиента.

Лимит проверяется после проверки ключа, поэтому запросы с некорректным ключом (401) квоту не расходуют.

Транзитные `503 pool_exhausted`

Помимо 429, который означает превышение клиентской квоты, платформа может отдать 503 с кодом pool_exhausted, когда внутренний пул соединений временно исчерпан — например, при одновременном пике у нескольких клиентов. Это сигнал «попробуй ещё раз через несколько секунд», а не «инфраструктура сломана». Ответ всегда содержит заголовок Retry-After — целое число секунд от 3 до 7, со случайным разбросом на стороне сервера, чтобы массовое восстановление не било повторно в пул.

JSON
{
  "error": {
    "code": "pool_exhausted",
    "type": "server_error",
    "retryAfter": 5
  }
}

В потоковом режиме (stream: true) статус 200 уже отправлен до того, как платформа узнаёт о перегрузке, поэтому сигнал приходит последним событием потока: data: { "error": { "code": "pool_exhausted", "retryAfter": <число> } }, после чего идёт обычный data: [DONE]. Распознайте code === "pool_exhausted" и повторите запрос через retryAfter секунд.

Есть и третий сигнал перегрузки — 429 ai_congested. Он приходит, когда перегружен пул AI-кластера. Запрос при этом не выполнялся и списания нет. Отличить его от превышения квоты можно по заголовку X-AI-Admission: shed, которого нет у ответа 429 rate_limit_exceeded.

Ответ `429 ai_pacing_limited`

Четвёртый ответ со статусом 429 не связан с нагрузкой на платформу. Он приходит, когда администратор портала включил равномерное расходование AI-квоты и вызов пробил суточное или недельное окно. Тело такого ответа приходит в конверте { "success": false, "error": { ... } }, а не в сыром формате остальных ошибок этой страницы, и несёт поля reason, overageDenied и resetAt. Разбор полей и режимов — на странице AI-квота компании.

Ошибки

HTTP Код Описание
429 rate_limit_exceeded Превышен лимит запросов. Уровень — в поле scope и заголовке X-RateLimit-Scope
429 ai_congested Пул AI-кластера перегружен. Запрос не выполнялся, списания нет. Ответ несёт заголовок X-AI-Admission: shed
429 ai_pacing_limited Пробито суточное или недельное окно равномерного расходования квоты. Повторите запрос по заголовку Retry-After
503 pool_exhausted Платформа временно перегружена. Повторите запрос через число секунд из Retry-After

Полный список общих ошибок API — Ошибки.

Готовый рецепт повторов

javascript
async function callWithBackoff(makeRequest, { maxAttempts = 5 } = {}) {
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
    const res = await makeRequest()
    if (res.status === 429 || res.status === 503) {
      const retryAfterSec = Number(res.headers.get('retry-after')) || 0
      // Соблюдаем Retry-After и добавляем небольшой случайный разброс,
      // чтобы параллельные обработчики не возвращались синхронно.
      const baseMs = retryAfterSec * 1000 || Math.min(1000 * 2 ** attempt, 30000)
      const jitterMs = Math.floor(Math.random() * 1000)
      await new Promise(r => setTimeout(r, baseMs + jitterMs))
      continue
    }
    return res
  }
  throw new Error('Повторы исчерпаны')
}

Что важно:

  • Всегда соблюдайте Retry-After. Он соответствует ожидаемому времени восстановления, меньший интервал ничего не ускоряет, а только нагружает платформу.
  • Добавляйте собственный случайный разброс поверх серверного — задержка в 100-1000 мс разрывает синхронные циклы обработчиков.
  • Ограничивайте количество попыток. Пяти достаточно для большинства сценариев, дальше возвращайте ошибку наружу.
  • При 5xx без Retry-After, например при сбое на стороне провайдера, увеличивайте паузу по экспоненте: min(2^attempt × 1s, 30s) со случайным разбросом.
  • Не запускайте Promise.all поверх тысяч записей. Без пауз пакетная обработка упрётся в один из уровней корзины.

Смотрите также