Справочник8 сентября 2026 г.·обновлено 8 сентября 2026 г.

OpenAI API: из чего состоит запрос

Разбор тела запроса и полей ответа: чем задаётся форма результата, где утекают деньги на токенах, почему ответ обрывается на полуслове и когда повтор запроса имеет смысл, а когда нет.

Что это решает

Первый запрос к модели собирается за две минуты копипастом чужого curl, и до продакшена этого хватает. Дальше начинается: ответ обрывается на середине предложения, раз в час прилетает 429, счёт за месяц вдвое выше прикидки, а модель «не держит формат». Каждая из этих четырёх бед чинится конкретным полем тела запроса или конкретным полем ответа, которое обычно никто не читает. Разбор состава запроса нужен затем, чтобы дёргать нужный рычаг, а не переписывать промпт наугад в третий раз.

Как устроено

Транспорт и ключ

Снаружи это обычный HTTPS POST с JSON в теле. Обязательных заголовка два: Authorization: Bearer <ключ> и Content-Type: application/json. Ключ живёт на сервере. В браузерном бандле или в мобильном приложении его достанут за вечер, а платить будет владелец ключа. Рабочая схема одна: клиент ходит в собственный бэкенд, бэкенд — к провайдеру, и он же считает лимиты по пользователям и пишет логи.

Эндпоинтов несколько — текстовая генерация (классический chat completions и более поздний формат с единым полем входа), эмбеддинги, аудио, изображения, файлы, пакетная обработка. Форма везде одинаковая: JSON внутрь, JSON или поток событий наружу.

Тело запроса

ПолеЧем управляетКогда трогать
modelкакая модель считает запросвынести в конфиг: имена моделей живут своей жизнью, перевыкатывать код из-за них не надо
messages (или input в новом формате)сам диалог — массив сообщений с ролямивсегда
tools, tool_choiceописания функций приложения, которые модель может вызвать, и принуждение к вызовукогда ответ должен опираться на данные системы, а не на память модели
response_format / JSON-схемаформа ответа вплоть до строгой схемывсегда, когда ответ разбирает код, а не человек
temperature, top_pразброс при выборе следующего токенавниз — извлечение данных, классификация, расчёты; выше — черновики текстов
max_tokens / max_output_tokensпотолок длины ответаставить всегда: это ещё и предохранитель по деньгам
stopстроки, на которых генерация обрываетсяжёсткие форматы, разделители
streamотдавать ответ частямиинтерфейсы, где ждёт живой человек
seedпопытка повторяемости выдачитесты и отладка
user, metadataметка запроса для логов и разбора злоупотреблениймногопользовательские продукты

Роли и память

Сообщения различаются ролями. Системная (в новых форматах — роль разработчика) задаёт рамки: кто отвечает, в каком формате, чего не делать. Пользовательская несёт задачу. Ассистентская — прошлые ответы модели. Отдельная роль возвращает результат вызова инструмента.

Сервер диалог не хранит. Каждый запрос уезжает целиком, со всей историей, которую приложение склеило само. Часть API умеет держать состояние на своей стороне по ссылке на предыдущий ответ, но по умолчанию обрезка старых реплик, сжатие их в резюме и порядок сообщений — работа приложения.

Токены и деньги

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

Что приходит в ответ

Кроме текста в ответе есть два поля, ради которых его и читают. finish_reason говорит, почему генерация закончилась: нормально, упёрлась в лимит длины, ушла в вызов инструмента, попала под фильтр. usage показывает фактический расход токенов на вход и выход. Обрезанный JSON после finish_reason: length не распарсится, и виновата тут не модель, а отсутствие проверки в коде.

Вызов инструментов

Цикл на четыре такта. Первый: запрос уходит со списком tools — имя функции, описание, JSON-схема аргументов. Второй: модель возвращает не текст, а вызов — имя, аргументы и идентификатор вызова. Третий: приложение исполняет функцию само и добавляет в историю сообщение с результатом и тем же идентификатором. Четвёртый: запрос повторяется с расширенной историей, и модель формулирует ответ.

Модель ничего не исполняет — она формирует намерение, решение звать функцию принимает код. Аргументы приходят от модели и проверяются как любой внешний ввод: схема не мешает прислать несуществующий идентификатор заказа или отрицательное количество.

Стриминг

При stream: true ответ приходит потоком серверных событий: куски с дельтами текста и финальный маркер. Лечит «интерфейс молчит десять секунд». Плата — усложнённая обработка ошибок: соединение уже открыто, код 200 уже отдан, и падение в середине надо ловить отдельно. Счётчики токенов в потоке приходят в конце и только если попросить их явной опцией.

Ошибки и повторы

КодЧто произошлоРеакция
400тело запроса или схема не годятсячинить код, повтор бессмысленен
401, 403ключ, права, региончинить доступ
404модель недоступна проектусверить имя модели и доступы
429лимит запросов, лимит токенов или кончился баланспауза и повтор с ростом задержки
5xx, таймаутсторона провайдераповтор с ростом задержки

Повторять имеет смысл только 429 и 5xx: экспоненциальный бэкофф со случайной добавкой, конечное число попыток, уважение к заголовку Retry-After. У повторного POST есть риск выполнить операцию дважды — на это в API есть заголовок идемпотентности. Идентификатор запроса из заголовков ответа пишется в лог всегда: без него в поддержке разговаривать не о чем.

Полезные сценарии

  • Классификация входящих обращений в строгую JSON-схему с полем уверенности и маршрутизацией спорных случаев на человека.
  • Извлечение полей из писем, счетов и накладных в структуру, готовую к записи в базу.
  • Вызов инструментов: поиск по каталогу, чтение остатков, черновик заказа — ответ собирается из данных системы, а не из памяти модели.
  • Стриминг ответа в интерфейс чата, чтобы первые слова появлялись сразу, а не после полной генерации.
  • Пакетная обработка архива: тысячи однотипных запросов уезжают файлом и считаются отложенно, дешевле поштучных вызовов.

Ограничения

  • Состояния нет. Помнить диалог — задача приложения, и оно же платит за историю на каждом шаге.
  • Контекстное окно конечно. Обрезка, сжатие и приоритет сообщений пишутся руками, автоматически ничего не ужимается.
  • Полной повторяемости не будет даже при нулевой температуре и заданном seed. Тесты строятся на проверке свойств ответа, а не на побайтовом сравнении.
  • Строгая схема гарантирует форму ответа; правдивость значений внутри неё проверяет код.
  • Лимиты по запросам и токенам в минуту делают наивный цикл for по тысяче документов неработоспособным — нужна очередь с ограничением параллелизма.
  • Данные уезжают в чужой контур. Для персональных данных и коммерческой тайны нужны отдельные меры: обезличивание, договор, локальная модель.
  • Привязка к провайдеру глубже, чем кажется: отличаются имена моделей, формат инструментов, поведение фильтров, подсчёт токенов. Прослойку делают тонкой, но делают.
  • Задержка чужого сервиса не под контролем. Синхронный вызов модели внутри обработки веб-запроса рано или поздно упрётся в таймаут.

Как проверить результат

  • Отправить минимальный запрос через curl и прочитать в ответе usage и finish_reason, а не только текст.
  • Специально выставить крошечный max_tokens и убедиться, что код видит обрыв и не пытается разобрать неполный JSON.
  • Посчитать токены промпта локально до отправки и сверить с usage — расхождение покажет, что в запрос уезжает лишнее.
  • Собрать golden set из 20–50 реальных примеров с эталонными ответами и прогонять его после каждой правки промпта. Сравнение «на глаз» перестаёт работать на третьей итерации.
  • Проверить ретраи на заглушке, отдающей 429: число попыток конечно, задержка растёт, Retry-After учитывается, лог не превращается в бесконечный цикл.
  • Убедиться, что идентификатор запроса и расход токенов попадают в лог по каждому вызову, включая неудачные.

Правило: всё, что должно быть предсказуемым, задаётся полями запроса и проверяется кодом; словами в промпте задаются только пожелания.

  • openai
  • api
  • llm
  • интеграции