Structured Outputs в OpenAI-compatible API: руководство по JSON Schema

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

Structured Outputs позволяет запросить JSON, который соответствует заданной схеме, а не просто попросить модель «вернуть JSON». В OpenAI-compatible API одна JSON Schema может использоваться через Responses и Chat Completions, но поля wrapper различаются, а поддержку необходимо проверять на конкретной модели и маршруте.

Безопасный production-подход состоит из трёх слоёв: использовать strict, когда модель его поддерживает, повторно парсить и валидировать результат в приложении, затем применять детерминированные бизнес-правила. Соответствие Schema устраняет форматные ошибки, но не доказывает фактическую или семантическую корректность.

Structured Outputs и JSON mode — не одно и то же

Метод Валидный JSON Обязательное соответствие Schema Типичное применение
Только Prompt Не гарантируется Нет Прототип с допустимыми ошибками parsing
JSON mode При поддержке и полном завершении Нет Гибкий JSON, форму которого проверяет приложение
Structured Outputs с strict: true С обработкой completion и refusal Да, в поддерживаемом subset Типизированное извлечение и workflows

Руководство OpenAI Structured Outputs рекомендует этот режим вместо JSON mode, если его поддерживают модель и endpoint. Structured response format нужен для предсказуемого объекта ответа; Function Calling — для запроса действия у приложения. Схемы могут быть похожи, но Call IDs и сообщения результата относятся к другому контракту.

Сначала определить Schema, затем выбрать endpoint

Для классификации обращения нужны четыре поля:

{
  "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
}

Required Properties и additionalProperties: false создают стабильный объект. Это не делает переносимыми все keywords JSON Schema. OpenAI документирует поддерживаемый subset; другой поставщик может реализовать иной subset или не иметь Strict Schema Mode.

Отправить Schema через Responses API

Responses размещает Schema в text.format:

{
  "model": "<MODEL_WITH_VERIFIED_STRUCTURED_OUTPUT_SUPPORT>",
  "input": "The customer was charged twice and wants a refund.",
  "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
    }
  }
}

Body отправляется на POST https://modelflare.dev/v1/responses с Authorization: Bearer <YOUR_API_KEY>. Результат находится в типизированных Output Items. SDK может дать Helper, но HTTP-клиент должен найти завершённый текст и выполнить JSON parsing, не предполагая top-level объекта.

Отправить ту же Schema через Chat Completions

Chat Completions использует response_format.json_schema:

{
  "model": "<MODEL_WITH_VERIFIED_STRUCTURED_OUTPUT_SUPPORT>",
  "messages": [
    { "role": "user", "content": "The customer was charged twice and wants a refund." }
  ],
  "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 и требует parsing.

Назначение Responses API Chat Completions
Container text.format response_format.json_schema
Type text.format.type response_format.type
Name text.format.name response_format.json_schema.name
Schema text.format.schema response_format.json_schema.schema
Strict text.format.strict response_format.json_schema.strict
Result Output Items / Helper choices[0].message.content

Modelflare конвертирует оба wrapper на поддерживаемых OpenAI/Codex-маршрутах, но конверсия не создаёт функцию в upstream-модели без её поддержки. Для Raw Chat Completions Pass-through контракт поставщика остаётся Source of Truth.

Проверять структуру и значение отдельно

{
  "category": "billing",
  "priority": 2,
  "requires_human": true,
  "summary": "Customer reports a duplicate charge and requests a refund."
}

Структурная валидация

JSON Schema validator проверяет Required Properties, отсутствие неожиданных полей, типы, Enum и диапазоны. Даже при Strict Adherence это защищает от неподдерживаемого маршрута, ошибки интеграции, truncation и будущих изменений контракта.

Семантическая и бизнес-валидация

Schema не знает, было ли двойное списание, верен ли priority: 2 и кто может одобрить возврат. Объект модели — предлагаемая классификация. Его нужно сверять с авторитетными данными, а права и финансовые лимиты применять в детерминированном коде. Валидный JSON не должен обходить authorization, billing или security boundary.

Обрабатывать неполный и исключительный вывод

Refusals

До JSON parsing проверяйте Status и Refusal Representation. Отказ по безопасности — не ошибка Schema.

Truncation и Output Limits

Если генерация остановилась раньше закрытия объекта, Schema не восстановит остаток. Проверяйте Completion Status и Stop Reason и задавайте достаточный, но ограниченный Output Limit.

Неподдерживаемые keywords

Начинайте с Objects, Arrays, Primitive Types, Enums, Required и явных Additional Properties. References, recursion, сложные Unions и расширенные validators используйте после проверки документации поставщика.

Задержка первой Schema

Некоторые поставщики предварительно обрабатывают и кэшируют новую Schema. Переиспользуйте стабильные версионированные схемы и измеряйте First Use отдельно от Steady State.

Несовместимость модели или маршрута

Endpoint может принимать обычный Chat Completions, но отклонять json_schema или игнорировать strict. Ответ 200 с JSON не подтверждает Strict Adherence. Нужны негативные и граничные тесты.

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

Тест Сохраняемые данные
Минимальный Required Object Status, модель, маршрут, Parsed Object, результат валидации
Каждый Enum Создание и parsing всех значений
Недостающая информация Ограниченное значение или запрос уточнения
Safety Input Формат refusal и обработка приложением
Низкий Output Limit Completion Status и truncation
Неподдерживаемая функция Явная ошибка или молчаливое игнорирование
Responses и Chat Wrapper Эквивалентные объекты приложения
Стабильная Schema First Use и Steady State

Schema, Prompt, Region, Streaming Mode и Output Limit должны оставаться одинаковыми. Записывайте дату теста.

Выбирать endpoint после проверки workflow

Responses подходит для Typed Output Items, Responses Streaming Events и более широкого Tool Workflow. Chat Completions — для стабильной Message-based Integration, если маршрут поддерживает response_format. См. Responses API и Chat Completions.

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

  1. храните одну версионированную Source of Truth для JSON Schema;
  2. меняйте wrapper, но не смысл;
  3. валидируйте завершённый ответ;
  4. затем применяйте детерминированные бизнес-правила;
  5. отдельно наблюдайте parsing, refusal, truncation и compatibility failures.

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

Structured Outputs делает модельный ответ более надёжным интерфейсом, но не заменяет проверку фактов, authorization или billing logic. «OpenAI-compatible» остаётся утверждением, которое нужно проверять для каждой функции.