Ошибка 429 говорит, что вы превысили лимит. Менее очевидно другое: лимитов несколько, и сработать может любой из них.
Какие бывают лимиты
Запросы в минуту. Как часто можно обращаться к API. Сюда обычно упираются те, кто параллелит много мелких задач.
Входные токены в минуту. Сколько текста вы отправляете. Сюда упирается любой, кто гоняет большой контекст: агенты, работа с репозиторием.
Выходные токены в минуту. Сколько генерирует модель. Лимит срабатывает при длинных ответах или при множестве одновременных генераций.
Лимит запросов редко бывает решающим. В агентных сценариях вы упрётесь во входные токены задолго до него.
Как правильно повторять запрос
Немедленный повтор делает только хуже: вы подбрасываете нагрузку именно тогда, когда её и так слишком много. Нужна растущая пауза со случайной добавкой.
import random, time
def call_with_retry(fn, attempts=5, base=1.0):
for i in range(attempts):
try:
return fn()
except RateLimitError:
if i == attempts - 1:
raise
delay = base * (2 ** i) + random.uniform(0, 0.5)
time.sleep(delay)
Случайная добавка нужна, чтобы десять воркеров не пошли на повтор в один и тот же момент. Без неё вместо ровной работы получатся волны отказов.
Что говорят заголовки ответа
API сообщает, сколько осталось до сброса лимита. Это надёжнее догадок: если сервер просит подождать двадцать секунд, ждите двадцать, а не те тридцать две, что насчитала ваша формула.
Как не упираться в лимит
Не отправляйте весь файл, когда нужен один метод. Входной лимит тратится на контекст, а в агентных запусках контекст накапливается.
Заводите именованные ключи для учёта. Отдельные ключи показывают расход фона и живой работы порознь, но независимых квот не создают. Нагрузкой управляют очередь и ограничитель частоты на стороне клиента.
Ставьте работу в очередь и ограничивайте частоту. Даже последовательные запросы могут превысить квоту провайдера. Нужны ограниченная очередь, клиентский ограничитель частоты и подсказки о повторе от провайдера, если он их возвращает.
Кэшируйте повторяющийся контекст. Если каждый запрос тянет за собой одну и ту же большую инструкцию, закэшируйте её на стороне провайдера.
Отдельные ключи: учёт, а не квоты
Называйте ключи по нагрузке (продакшен, фоновая работа, эксперименты): так расход учитывается раздельно. Квоты ключи не изолируют, каждую нагрузку сдерживают очередь и ограничитель частоты в клиенте.
codexkey показывает статистику расхода по каждому ключу. При создании ключа выбирайте Premium или Cheap, при необходимости задайте срок действия и резервный Premium для Cheap. Через API ключей личного кабинета нельзя задать RPM, TPM, параллелизм или бюджет для отдельного ключа.
Что запомнить
На нагрузку влияют число запросов, токены и параллелизм. Ограничивайте число повторов, добавляйте джиттер и учитывайте заголовки о повторе, если они есть. Фоновый и живой трафик разводят очередь и ограничитель частоты в клиенте. Именованные ключи дают раздельный учёт расхода, а не независимые квоты.