Структурированный вывод в API, совместимых с OpenAI: руководство по JSON Schema
Практическое руководство по строгой JSON Schema в Responses и Chat Completions: проверка результата, обработка ошибок и тестирование маршрутов.

Structured Outputs позволяет запросить JSON, который соответствует заданной схеме, а не просто попросить модель «вернуть JSON». В API, совместимом с OpenAI, одну JSON-схему можно использовать через Responses и Chat Completions, но форматы запросов различаются, а поддержку необходимо проверять на конкретной модели и маршруте.
Безопасный подход для продакшена состоит из трёх уровней: использовать strict, когда модель его поддерживает, повторно разбирать и проверять результат в приложении, затем применять детерминированные бизнес-правила. Соответствие схеме уменьшает число форматных ошибок, но не доказывает фактическую или семантическую корректность.
Structured Outputs и режим JSON — не одно и то же
| Метод | Валидный JSON | Обязательное соответствие схеме | Типичное применение |
|---|---|---|---|
| Только инструкция | Не гарантируется | Нет | Прототип, допускающий ошибки разбора |
| Режим JSON | При поддержке и полном завершении | Нет | Гибкий JSON, структуру которого проверяет приложение |
Structured Outputs с strict: true |
При обработке завершения и отказов | Да, в поддерживаемом подмножестве | Типизированное извлечение и рабочие процессы приложения |
Руководство OpenAI по Structured Outputs рекомендует этот режим вместо режима JSON, если его поддерживают модель и конечная точка. Формат структурированного ответа нужен для предсказуемого объекта данных; Function Calling — для запроса действия у приложения. Схемы могут быть похожи, но идентификаторы вызовов и сообщения с результатами относятся к другому контракту.
Сначала определить схему, затем выбрать конечную точку
Для классификации обращения нужны четыре поля:
{
"type": "object",
"properties": {
"category": {
"type": "string",
"enum": ["billing", "technical", "account"]
},
"priority": {
"type": "integer",
"minimum": 1,
"maximum": 3
},
"requires_human": {
"type": "boolean"
},
"summary": {
"type": "string"
}
},
"required": ["category", "priority", "requires_human", "summary"],
"additionalProperties": false
}
Если сделать все свойства обязательными и установить additionalProperties: false, объект для последующей обработки будет стабильнее. Однако не все возможности JSON Schema переносимы. OpenAI документирует поддерживаемое подмножество; другой поставщик может реализовать иное подмножество или не поддерживать строгий режим схемы.
Отправить схему через Responses API
Responses размещает схему в text.format:
export MODELFLARE_API_KEY="<YOUR_API_KEY>"
export MODEL_ID="<MODEL_WITH_VERIFIED_STRUCTURED_OUTPUT_SUPPORT>"
curl -sS https://modelflare.dev/v1/responses \
-H "Authorization: Bearer $MODELFLARE_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"model\": \"$MODEL_ID\",
\"input\": \"С клиента дважды списали оплату, и он просит вернуть деньги.\",
\"text\": {
\"format\": {
\"type\": \"json_schema\",
\"name\": \"support_ticket\",
\"schema\": {
\"type\": \"object\",
\"properties\": {
\"category\": {
\"type\": \"string\",
\"enum\": [\"billing\", \"technical\", \"account\"]
},
\"priority\": {
\"type\": \"integer\",
\"minimum\": 1,
\"maximum\": 3
},
\"requires_human\": { \"type\": \"boolean\" },
\"summary\": { \"type\": \"string\" }
},
\"required\": [\"category\", \"priority\", \"requires_human\", \"summary\"],
\"additionalProperties\": false
},
\"strict\": true
}
}
}"
Тело запроса отправляется на POST https://modelflare.dev/v1/responses с Authorization: Bearer <YOUR_API_KEY>. Результат находится в типизированных элементах вывода. SDK может предоставить вспомогательный метод, но HTTP-клиент должен найти текст завершённого ответа и явно разобрать его как JSON, не предполагая наличие объекта верхнего уровня.
Отправить ту же схему через Chat Completions
Chat Completions использует response_format.json_schema:
curl -sS https://modelflare.dev/v1/chat/completions \
-H "Authorization: Bearer $MODELFLARE_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"model\": \"$MODEL_ID\",
\"messages\": [
{
\"role\": \"user\",
\"content\": \"С клиента дважды списали оплату, и он просит вернуть деньги.\"
}
],
\"response_format\": {
\"type\": \"json_schema\",
\"json_schema\": {
\"name\": \"support_ticket\",
\"schema\": {
\"type\": \"object\",
\"properties\": {
\"category\": {
\"type\": \"string\",
\"enum\": [\"billing\", \"technical\", \"account\"]
},
\"priority\": {
\"type\": \"integer\",
\"minimum\": 1,
\"maximum\": 3
},
\"requires_human\": { \"type\": \"boolean\" },
\"summary\": { \"type\": \"string\" }
},
\"required\": [\"category\", \"priority\", \"requires_human\", \"summary\"],
\"additionalProperties\": false
},
\"strict\": true
}
}
}"
JSON обычно возвращается строкой в choices[0].message.content, которую нужно разобрать.
| Назначение | Responses API | Chat Completions |
|---|---|---|
| Контейнер | text.format |
response_format.json_schema |
| Тип | text.format.type |
response_format.type |
| Имя | text.format.name |
response_format.json_schema.name |
| Схема | text.format.schema |
response_format.json_schema.schema |
| Строгий режим | text.format.strict |
response_format.json_schema.strict |
| Результат | Элементы вывода / метод SDK | choices[0].message.content |
Modelflare преобразует оба формата на поддерживаемых маршрутах OpenAI/Codex, но преобразование не добавляет Structured Outputs в модель поставщика, если она его не поддерживает. При передаче Chat Completions без преобразования источником истины остаётся контракт поставщика.
Проверять структуру и значение отдельно
{
"category": "billing",
"priority": 2,
"requires_human": true,
"summary": "Клиент сообщает о двойном списании и просит вернуть деньги."
}
Структурная валидация
Валидатор JSON Schema проверяет обязательные свойства, отсутствие неожиданных полей, типы, перечисления и диапазоны. Даже при обещанном строгом соответствии это защищает от неподдерживаемого маршрута, ошибки интеграции, обрезанного вывода и будущих изменений контракта.
Семантическая и бизнес-валидация
Схема не знает, было ли двойное списание, верен ли priority: 2 и кто может одобрить возврат. Объект модели — лишь предлагаемая классификация. Его нужно сверять с достоверными данными, а права доступа и финансовые лимиты применять в детерминированном коде. Валидный JSON не должен обходить авторизацию, учёт платежей или границы безопасности.
Обрабатывать неполный и исключительный вывод
Отказы
До разбора JSON проверяйте состояние ответа и представление отказа. Отказ по соображениям безопасности — не ошибка схемы.
Обрезанный вывод и его лимиты
Если генерация остановилась до закрытия объекта, схема не восстановит недостающую часть. Проверяйте состояние завершения и причину остановки, а также задавайте достаточный, но ограниченный лимит вывода.
Неподдерживаемые возможности схемы
Начинайте с объектов, массивов, примитивных типов, перечислений, обязательных полей и явно заданных дополнительных свойств. Ссылки, рекурсию, сложные объединения и расширенную валидацию используйте только после проверки документации поставщика.
Задержка при первом использовании схемы
Некоторые поставщики предварительно обрабатывают и кэшируют новую схему. Переиспользуйте стабильные версионированные схемы и измеряйте первое обращение отдельно от установившегося режима.
Несовместимость модели или маршрута
Конечная точка может принимать обычные запросы Chat Completions, но отклонять json_schema или игнорировать strict. Ответ 200 с JSON не подтверждает строгое соответствие. Нужны проверки с некорректными входными данными и граничными случаями.
Выполнить матрицу совместимости
| Тест | Сохраняемые данные |
|---|---|
| Минимальный объект с обязательными полями | Статус, модель, маршрут, разобранный объект, результат валидации |
| Каждое значение перечисления | Генерация и разбор каждого значения |
| Недостающая информация | Ограниченное значение или запрос уточнения |
| Потенциально опасный ввод | Формат отказа и обработка приложением |
| Низкий лимит вывода | Состояние завершения и обработка обрезанного вывода |
| Неподдерживаемая функция | Явная ошибка или молчаливое игнорирование |
| Форматы Responses и Chat | Эквивалентные объекты приложения |
| Стабильная схема | Первое обращение и установившийся режим |
Схема, инструкция, регион, режим потоковой передачи и лимит вывода должны оставаться одинаковыми. Записывайте дату проверки.
Выбирать конечную точку после проверки рабочего процесса
Responses подходит для типизированных элементов вывода, потоковых событий Responses и более сложных процессов с инструментами. Chat Completions — для стабильной интеграции на основе сообщений, если маршрут поддерживает response_format. См. Responses API и Chat Completions.
Независимо от выбора:
- храните один версионированный источник истины для JSON Schema;
- меняйте формат обёртки, но не смысл;
- валидируйте завершённый ответ;
- затем применяйте детерминированные бизнес-правила;
- отдельно отслеживайте ошибки разбора, отказы, обрезанный вывод и проблемы совместимости.
Для миграции используйте руководство по API, совместимым с OpenAI, для неполных потоков — руководство по потоковым ответам AI API. Проверьте модели и цены и тестируйте Structured Outputs на точном маршруте API-ключа.
Structured Outputs делает ответ модели более надёжным интерфейсом, но не заменяет проверку фактов, авторизацию или логику учёта платежей. Совместимость с OpenAI остаётся утверждением, которое нужно проверять для каждой функции.