5 ошибок при вызове LLM на Python, которые стоят сотни долларов в продакшене
Вызов языковой модели на Python давно превратился в рутину: импорт клиента, промпт (запрос к модели на естественном языке), response.choices[0].message.content, но именно за этой простотой прячутся пять ошибок, которые в продакшене обходятся в сотни долларов и часы отладки.

Туториалы по Python LLM показывают, как получить один ответ, но молчат о том, что происходит, когда ответов нужно пятьсот тысяч: провайдер отвечает кодом 429, клиент падает по таймауту, а деньги за генерацию списываются дважды.
Ситуация знакомая: с обычными HTTP-зависимостями разработчик ставит таймаут, вешает повторы, помнит про кеш. А клиент для языковой модели попадает в код так, будто это локальная функция: без ограничения параллельности, без оглядки на то, что вызов платный, медленный и недетерминированный. Ниже разбираем пять конкретных мест, где это ломается, и что с каждым делать.
Что понадобится
- Python 3.10+ и установленный клиент OpenAI (
pip install openai) или аналогичный SDK - Действующий API-ключ любого LLM-провайдера с известными лимитами по RPM (запросы в минуту) и TPM (токены (единицы текста, на которые модель разбивает ввод и вывод) в минуту)
- Библиотека
tenacityдля управления повторами (pip install tenacity) - Около 30 минут на разбор и правку существующего кода
Как устранить каждую из пяти ошибок?
1. asyncio.gather запускает все запросы разом и выжигает квоту
Типичный первый подход к пакетной обработке: десять тысяч отзывов, каждый надо классифицировать, синхронный цикл работает до вечера. Разработчик пишет:
results = await asyncio.gather(*[classify(t) for t in texts])
gather запускает все корутины почти одновременно. Провайдер отвечает лавиной 429 (ошибка «слишком много запросов»). Неудачные запросы тоже расходуют лимит, и задача на десять минут не заканчивается никогда.
Решение: семафор для потолка параллельности.
sem = asyncio.Semaphore(20)
async def classify(text: str) -> str:
async with sem:
resp = await client.chat.completions.create(...)
return resp.choices[0].message.content
Двадцать одновременных запросов вместо десяти тысяч. Число подбирайте не по RPM, а по TPM: с длинными промптами вы упрётесь в токены задолго до лимита по запросам, а семафор по числу корутин про токены ничего не знает.
Ещё один приём: читайте заголовки ответа. В каждом ответе едут x-ratelimit-remaining-*, а вместе с 429 приходит retry-after-ms, сервер сообщает, через сколько миллисекунд бюджет восстановится. Слепой sleep(5) вместо этого числа означает либо лишнее ожидание, либо повторный 429.
2. Встроенные повторы SDK работают не так, как вы думаете
Клиент OpenAI по умолчанию повторяет запрос дважды с нарастающей задержкой. Для случайного всплеска этого хватает. При устойчивой перегрузке два повтора кончатся, и исключение всё равно прилетит, просто на несколько секунд позже. Настраивается это на уровне клиента:
client = AsyncOpenAI(max_retries=5, timeout=60.0)
3. Ретрай, который платит дважды
Вот распространённый паттерн:
@retry(stop=stop_after_attempt(5), wait=wait_exponential(min=1, max=60))
async def classify(text: str) -> str:
resp = await client.chat.completions.create(..., timeout=10.0)
return resp.choices[0].message.content
Таймаут в десять секунд срабатывает на клиенте. Модель об этом не знает: она продолжает генерировать, дописывает ответ до конца, и все токены вам посчитают. Клиент уже отвалился и пошёл на второй круг. При длинных ответах вы платите за четыре генерации, из которых используете одну.
Решение: ставьте таймаут по реальному времени генерации. Ответ на две тысячи токенов физически не появится за десять секунд. Если хотите рано понимать, что запрос завис, включайте стриминг и следите за временем до первого токена: это честный признак затыка.
Повторять тоже нужно с разбором:
- 429 и 5xx: повторяем
- 400 (невалидная схема, контекст не влез): повторять нечего, ответ будет тот же, а попытки оплатятся
- Отказ модели по содержанию: повтором не лечится
Обёрнутый в @retry вызов без фильтра по типу исключения просто аккуратно оплачивает одинаковые неудачи.
4. Заведите счётчик токенов прямо сейчас
В каждом ответе есть поле usage. Десять строк кода складывают prompt_tokens и completion_tokens в метрику. Скачок расхода будет виден в тот же день, а не в конце месяца в счёте.
5. temperature=0 не делает вызов детерминированным
Все знают: нулевая температура убирает сэмплирование, декодирование становится жадным, функция «чистая». Отправьте один и тот же промпт с temperature=0 десять раз подряд: байт в байт совпадут далеко не все ответы.
Причина: запрос собирается на сервере в батч (пакет) вместе с чужими. Размер и состав батча зависят от того, кто в эту секунду ещё обращается к API. При разном размере батча ядра складывают числа с плавающей запятой в разном порядке, и это меняет последние биты, а вслед за ними выбор следующего токена. Тест на равенство строк в CI будет мигать красным без видимой причины.
Решение: тест не на точное совпадение, а на семантическую близость или структурное соответствие. Кеширование по хешу промпта работает только при сохранении первого полученного ответа, а не при расчёте на воспроизводимость.
Задача не интерактивная? Используйте батч-режим
Отдельно стоит сказать о задачах, которые не требуют мгновенного ответа: ночная разметка, переразметка исторических данных, генерация описаний для каталога. Им онлайн-эндпоинт не нужен. У крупных провайдеров есть пакетный режим: отправляете файл с запросами, забираете результат в течение суток, платите примерно вдвое меньше. Ни 429, ни семафоров, ни борьбы за квоту. Половина кода с повторами существует только потому, что задачу засунули в синхронный API, где ей не место.
Что делать с этим прямо сейчас, по ролям
Разработчику на Python LLM. Откройте текущий код вызова модели и проверьте три вещи: есть ли семафор или иной потолок параллельности, фильтруются ли повторы по типу ошибки, логируется ли usage. Если нет хотя бы одного, правка займёт полчаса, а экономию увидите в первом же счёте.
Автору Дзена или копирайтеру, который использует API для генерации текстов. Если вы гоняете сотни запросов через скрипт, пакетный режим провайдера сэкономит деньги и нервы. Спросите у разработчика, поддерживает ли ваш провайдер batch-эндпоинт.
Предпринимателю в РФ и СНГ. Для российских провайдеров (YandexGPT, GigaChat) принципы те же: лимиты, таймауты, платные повторы. Конкретные заголовки и параметры SDK отличаются, но архитектура ошибок идентична.
Было: скрипт на asyncio.gather отправлял 10 000 запросов на классификацию отзывов. За ночь обработал 800, остальное утонуло в 429. Счёт за неудачные повторы превысил счёт за успешные.
Стало: добавлен asyncio.Semaphore(20), ретрай отфильтрован по коду ошибки (429 и 5xx повторяются, 400 нет), таймаут поднят с 10 до 45 секунд, подключён логгер usage. Те же 10 000 запросов прошли за 40 минут, расход упал вдвое.
Ставить timeout=10 на запрос, который физически генерирует ответ 30 секунд: вы платите за каждую оборванную генерацию, модель не останавливается вместе с клиентом.
Повторять все ошибки без разбора: код 400 (промпт не влез в контекст) не исправится сам, а каждая попытка стоит денег.
Полагаться на temperature=0 как гарантию воспроизводимости и писать тесты на точное равенство строк: они будут ложно падать из-за серверного батчинга.
Подбирать размер семафора по RPM, игнорируя TPM: с длинными промптами вы упрётесь в лимит токенов раньше.
Я проверял эти ошибки на реальных задачах: генерация описаний для каталога и классификация комментариев. Самый дорогой промах, ретрай без фильтра по типу ошибки. Он не кричит в логах, не падает с трейсбеком, просто тихо умножает счёт. Десять строк кода на логирование usage окупаются в первый же день. Честная оговорка: конкретные заголовки лимитов и параметры SDK отличаются у каждого провайдера, проверяйте документацию своего.
Генератор промптов dzen.guru
Проверьте, как правильно составленный промпт сокращает число токенов и повторных запросов
Попробовать бесплатноПростая проверка: откройте код вызова Python LLM прямо сейчас, найдите строку с create(...) и посчитайте, сколько из пяти защит на месте: семафор, фильтр повторов, адекватный таймаут, логирование usage, отказ от теста на точное равенство строк. Каждая недостающая стоит денег, и теперь вы знаете, каких именно.

Основатель dzen.guru. Эксперт по монетизации и продвижению на Дзен. Автор курса «Старт на Дзен 2026».
Читайте также

Устройства OpenAI получат камеру и будут наблюдать за домом: продажи с 2027 года
OpenAI готовит портативную колонку с камерой и голосовым ассистентом. Bloomberg описал устройство, которое компания подаёт как «домашний компьютер эпохи ИИ», и…
Сравнение LLM среднего класса: GigaChat и YandexGPT против трёх поколений Claude Sonnet
Сравнение LLM (большая языковая модель, программа, которая генерирует текст по вашему запросу) среднего ценового класса перестало быть абстрактным упражнением:…

OpenAI Codex получил физический пульт за $230: компания впервые вышла на рынок «железа»
OpenAI 4 июня 2025 года представила Codex Micro, физическую клавиатуру за 230 долларов с подсвечиваемыми клавишами для управления ИИ-агентами (полуавтономными…
Комментарии