Эфир 18.11 · Поток 318 ноября в 19:00 МСК — бесплатный практический эфир по ИИ-агентам · Живой Поток 3 стартует 23.11Эфир 18 ноября →Поток 3 (23.11)
РелизAPI / Продукт · В работуHabr AI→ оригинал

Batch API для LLM: 50 000 запросов со скидкой до 50% и три класса ошибок

Когда сервису нужно прогнать через LLM 50 000 договоров, синхронный API упирается в TPM, RPM и бюджет. OpenAI, Anthropic и Google предлагают Batch API: вы грузите один JSONL-файл, платите со скидкой и получаете результат в течение 24 часов. Батчи живут в отдельном пуле лимитов, но у него есть свой потолок по enqueued-токенам. А ошибки приходят не сразу, а внутри готового файла.

AI-обработка оригинала Habr AI; редакция Hamidun News
Batch API для LLM: 50 000 запросов со скидкой до 50% и три класса ошибок
Источник: Habr AI. Коллаж: Hamidun News.
Слушать статью
Паспорт материала и цифры
ПараметрДанные
ПервоисточникHabr AI ↗
Главный редактор
Ключевой факт #1Считайте токены до отправки, иначе получите token_limit_exceeded
Ключевой факт #2Разбирайте результат по custom_id на succeeded, errored и expired
Ключевой факт #3Не переотправляйте весь пакет — повторяйте только упавшие строки

Пока запросов к LLM десяток или сотня, синхронный API ведёт себя прилично: отправил запрос, получил ответ. Но когда нужно обработать 50 000 договоров или карточек товаров, вы быстро упираетесь в лимиты TPM и RPM, а длинные контекстные запросы начинают отваливаться ещё до генерации. Для таких задач у OpenAI, Anthropic и Google есть пакетный режим, Batch API. Вы собираете все задачи в один файл, отправляете провайдеру и ждёте до 24 часов, зато платите меньше.

Как устроена очередь

За простым словом «батч» стоят три уровня ограничений.

Первый уровень — сам пакет. Это JSONL-файл, где каждая строка содержит custom_id, method, url и body с моделью и сообщениями. По сути, это обычный запрос к Chat Completions, упакованный в одну строку. Файл загружается через Files API с purpose «batch», после чего создаётся задача. Результаты возвращаются не в том порядке, в котором вы их отправляли, поэтому custom_id фактически работает как первичный ключ: по нему вы сопоставляете ответ с исходной записью.

Второй уровень — пул enqueued-токенов. Лимит считается не по файлам, а по суммарному объёму токенов во всех незавершённых пакетах. Если новый пакет выводит организацию за потолок, API возвращает token_limit_exceeded и отказывается создавать джобу. У OpenAI потолок зависит от tier: чем он выше, тем больше токенов можно держать в очереди.

Третий уровень — окно завершения. Сутки — это SLA, а не прогноз. На практике пакеты чаще всего завершаются за несколько часов, а Anthropic пишет, что большинство батчей готово меньше чем за час. Но рассчитывать нужно на худший случай. Параметр completion_window сейчас принимает только значение «24h».

Где ломается пайплайн

Автор исходной статьи делит ошибки на четыре класса, и ловушки тут нетривиальные.

До создания пакета. Лишняя запятая в JSONL, дубль или пропуск custom_id, неверный endpoint. По словам автора, Anthropic проверяет параметры запросов только после завершения всего пакета: можно отправить 100 тысяч строк, прождать час и узнать, что в трёх из них кривой max_tokens. Поэтому валидируйте файл локально до загрузки: распарсите каждую строку, проверьте уникальность custom_id и наличие model и messages. Для этого подойдут и Pydantic-модели.

На уровне очереди. Здесь главная ошибка — token_limit_exceeded. Лечится подсчётом токенов до отправки и собственной очередью на стороне приложения. Если бюджет не влезает, ждите завершения предыдущих пакетов или повторяйте попытку с экспоненциальным backoff: 30, 60, 120 секунд и так далее.

Внутри пакета. Самая коварная категория. Пакет completed, но в выгрузке часть строк succeeded, часть errored, часть expired. Если код просто читает content и пишет в базу, проблемные строки молча теряются. У Anthropic счётчики errored, canceled и expired в request_counts остаются нулевыми, пока не завершится весь пакет, так что заранее оценить масштаб провала не получится. Разумная схема — три корзины: invalid_request чинится и переотправляется, серверные ошибки повторяются с задержкой, expired идёт в новый пакет, потому что окно уже закрыто.

При опросе статуса. Если дёргать статус каждые пять секунд, можно поймать 429 на сам polling. Наивный цикл прочтёт это как «пакет не готов», хотя вы упёрлись в rate limit на чтение. Для пакетов до тысячи строк опрашивайте раз в 30 секунд, для крупных — раз в 2–5 минут. Если пакет висит дольше нескольких часов, проверьте, не застрял ли он на этапе validating.

Сколько это стоит на самом деле

Скидка в 50% — это потолок, а не гарантия. Итоговая цифра зависит от того, сколько запросов ушло в expired, сколько пришлось переотправить и использовался ли кеш системного промпта. В удачном сценарии экономия даже выше, потому что cached-input тоже дешевле. В неудачном вы платите дважды за одни и те же строки. Ещё важный нюанс: у OpenAI при отмене пакета незавершённые запросы отменяются, а за уже выполненные деньги списываются.

Отдельно стоит упомянуть, что оригинал частично написан в рекламном ключе: автор предлагает OpenAI-совместимый шлюз Bothub с оплатой российской картой и заявленной экономией 45%. Идея совместимого эндпоинта рабочая, но условия и надёжность любого посредника стоит проверять самостоятельно, а не по рефералке.

Что делать на практике

Батч — это другой контракт: вы получаете скидку и отдельный пул лимитов, но берёте на себя разбор результатов. Если вы строите массовую обработку документов, классификацию или разметку, закладывайте в пайплайн несколько вещей:

  • локальную валидацию JSONL до отправки;
  • подсчёт токенов и семафор на enqueued-лимит;
  • разбор выгрузки по типам результата и повторную отправку только упавших строк;
  • polling с backoff и логирование created_at.

И главное правило: не переотправляйте целый пакет из-за трёх упавших строк, потому что за успешные вы уже заплатили.

Сюжет

Вопросы и ответы по материалу

Что известно по теме: как устроена очередь?

За простым словом «батч» стоят три уровня ограничений. Первый уровень — сам пакет. Это JSONL-файл, где каждая строка содержит custom_id, method, url и body с моделью и сообщениями. По сути, это обычный запрос к Chat Completions, упакованный в одну строку. Файл загружается через Files API с purpose «batch», после чего создаётся задача. Результаты возвращаются не в том порядке, в котором вы их отправляли, поэтому custom_id фактически работает как первичный ключ: по нему вы сопоставляете ответ с исходной записью.

Что известно по теме: где ломается пайплайн?

Автор исходной статьи делит ошибки на четыре класса, и ловушки тут нетривиальные. До создания пакета. Лишняя запятая в JSONL, дубль или пропуск custom_id, неверный endpoint. По словам автора, Anthropic проверяет параметры запросов только после завершения всего пакета: можно отправить 100 тысяч строк, прождать час и узнать, что в трёх из них кривой max_tokens. Поэтому валидируйте файл локально до загрузки: распарсите каждую строку, проверьте уникальность custom_id и наличие model и messages.

Что известно по теме: сколько это стоит на самом деле?

Скидка в 50% — это потолок, а не гарантия. Итоговая цифра зависит от того, сколько запросов ушло в expired, сколько пришлось переотправить и использовался ли кеш системного промпта. В удачном сценарии экономия даже выше, потому что cached-input тоже дешевле. В неудачном вы платите дважды за одни и те же строки. Ещё важный нюанс: у OpenAI при отмене пакета незавершённые запросы отменяются, а за уже выполненные деньги списываются.

ЖХ
Жемал Хамидун — CPO Alpina Digital, продакт-менеджер AlpinaGPT. Делает AI-продукты с 2019 года. Hamidun News — pet project, который вырос в production-агрегатор с 6000+ читателей.
✦ Единое AI-пространство · Nomad

Протестируйте новые LLM и мультимодальные модели в одном окне

Платформа Nomad AI (nomadnet.ai) даёт прямой доступ к Claude Opus 5.5, GPT-6, Gemini 3.1, DeepSeek и автономным агентам без VPN, зарубежных карт и зоопарка подписок.

Открыть Nomad AI →Автономный Nomad Agent
Что вы думаете?
Загружаем комментарии…