Структурированный вывод в API, совместимых с OpenAI: руководство по JSON Schema

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

Структурированный вывод в API, совместимых с OpenAI: руководство по JSON Schema

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.

Независимо от выбора:

  1. храните один версионированный источник истины для JSON Schema;
  2. меняйте формат обёртки, но не смысл;
  3. валидируйте завершённый ответ;
  4. затем применяйте детерминированные бизнес-правила;
  5. отдельно отслеживайте ошибки разбора, отказы, обрезанный вывод и проблемы совместимости.

Для миграции используйте руководство по API, совместимым с OpenAI, для неполных потоков — руководство по потоковым ответам AI API. Проверьте модели и цены и тестируйте Structured Outputs на точном маршруте API-ключа.

Structured Outputs делает ответ модели более надёжным интерфейсом, но не заменяет проверку фактов, авторизацию или логику учёта платежей. Совместимость с OpenAI остаётся утверждением, которое нужно проверять для каждой функции.