Урок курса

Ошибки LLM API: timeout, rate limit и retry

LLM API с нуля: первый AI-сервис на Python

Вызов LLM API может завершиться timeout, rate limit, временной ошибкой провайдера, отказом авторизации или невалидным запросом. Retry нужен не для всех классов. Ошибку ключа, неизвестную модель или превышение контекстного окна повтор обычно не исправит; 429 и часть 5xx могут быть временными.

У запроса должны быть конечный timeout и общий deadline операции. Иначе зависшее соединение удерживает worker и пользователь не понимает состояние. Отдельно полезны connect timeout и read timeout, если SDK их поддерживает.

Классифицируйте исключения по стабильному типу или HTTP-статусу, а не по тексту сообщения. Не показывайте пользователю сырой provider error с внутренними деталями.

Exponential backoff и jitter

Повторяйте ограниченное число раз с растущей задержкой: например, 0,5; 1; 2; 4 секунды. Jitter добавляет случайность и не позволяет тысячам клиентов синхронно повторить запрос после сбоя. Учитывайте заголовок Retry-After, если провайдер его возвращает.

delay = 0.5
for attempt in range(max_attempts):
    try:
        return call_model()
    except RetryableError:
        if attempt == max_attempts - 1:
            raise
        sleep(random.uniform(0, delay))
        delay = min(delay * 2, 8.0)

Retry имеет бюджет времени и попыток. После его исчерпания сервис возвращает контролируемую ошибку или fallback, а не продолжает бесконечно тратить токены.

Идемпотентность, лимиты и наблюдаемость

Повтор текстовой генерации может дать другой результат и дважды списать стоимость. Если после ответа происходит внешнее действие, отделите генерацию от commit и используйте idempotency key на своей стороне. Никогда не повторяйте оплату, письмо или запись без проверки, был ли эффект уже применён.

Rate limit решается не только backoff: ограничивайте concurrency, ставьте очередь, кэшируйте допустимые ответы и распределяйте бюджет между пользователями. Circuit breaker временно прекращает запросы к явно деградировавшему провайдеру, защищая собственный сервис.

Логи содержат request id, модель, latency, attempts, класс ошибки и token usage, но не API-ключ и не полный чувствительный prompt. Метрики p50/p95, доля 429 и стоимость на успешный ответ показывают проблему раньше жалоб.

Повтор запроса и повтор бизнес-действия — разные вещи

Клиент не дождался ответа модели. Из timeout нельзя заключить, что сервер не принял запрос. Повтор может создать второе списание за генерацию. Если полученный tool call запускает платёж или письмо, его повторное исполнение может породить уже бизнес-дубль.

Для генерации задайте максимальное число попыток, общий deadline и интервалы с jitter. Ответ 429 может содержать указание времени ожидания; бесконечные быстрые повторы ухудшают перегрузку. Ошибка аутентификации не исправляется ожиданием. Проверка схемы не должна повторять неизменный неправильный запрос сколько угодно раз.

Для внешнего действия храните отдельный идентификатор операции и её состояние. Один запрос пользователя может содержать несколько вызовов LLM, а один tool call — одну бизнес-операцию. Их идентификаторы не стоит смешивать. Проверьте сценарий: действие завершилось, но ответ клиенту потерялся. После повтора должны читаться прежний результат и статус, а не выполняться ещё одна оплата. В учебном API можно начать с функции без побочных эффектов, затем отдельно добавить такой контракт.

Продолжите разбор: Structured Output: JSON и Pydantic для LLM.

Задача 1

Какая ошибка обычно не исправляется автоматическим retry без изменения запроса?

Выберите один вариант
Без регистрации · результат не сохраняется

Продолжить с сохранением прогресса

Перейдите к уроку в учебном кабинете.

Перейти к интерактивному уроку