---
title: Структурированный вывод
description: Ответ по именованной JSON-схеме — какой формат принимает API, что значит строгость, как это выглядит на трёх диалектах и почему поддержка проверяется отдельно для каждой модели.
keywords: структурированный вывод, json_schema, response_format, strict, схема, refusal
group: gateway
---

## Быстро {#quick keywords="response_format, json_schema, схема, пример"}

Добавьте `response_format` — и ответ придёт по вашей схеме, а не свободным текстом.

```json title=Запрос
{
  "model": "<model>",
  "max_tokens": 256,
  "messages": [{ "role": "user", "content": "Разбери адрес: Казань, ул. Баумана, 15." }],
  "response_format": {
    "type": "json_schema",
    "json_schema": {
      "name": "postal_address",
      "strict": true,
      "schema": {
        "type": "object",
        "properties": [
          { "name": "city", "type": "string", "description": "Город." },
          { "name": "street", "type": "string", "description": "Улица." },
          { "name": "house", "type": "string", "description": "Номер дома." }
        ]
      }
    }
  }
}
```

```python title=Python
import json
import os

from openai import OpenAI

client = OpenAI(base_url="https://api.kumorouter.com/v1", api_key=os.environ["KUMO_API_KEY"])

answer = client.chat.completions.create(
    model="<model>",
    max_tokens=256,
    messages=[{"role": "user", "content": "Разбери адрес: Казань, ул. Баумана, 15."}],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "postal_address",
            "strict": True,
            "schema": {
                "type": "object",
                "properties": [
                    {"name": "city", "type": "string", "description": "Город."},
                    {"name": "street", "type": "string", "description": "Улица."},
                    {"name": "house", "type": "string", "description": "Номер дома."},
                ],
            },
        },
    },
)
address = json.loads(answer.choices[0].message.content)
```

## Как выглядит схема {#schema keywords="profile, properties, типы, список полей"}

Схема идёт под именем — оно несётся поставщику так, как этот протокол его несёт, — и подчиняется опубликованному профилю.

| Член | Что это |
| --- | --- |
| `name` | Имя схемы: буквы, цифры, дефис и подчёркивание, до 64 символов. |
| `strict` | Обязателен и равен `true`. |
| `schema` | Сама схема: корень — объект, поля перечислены списком. |

`properties` — **список именованных полей**, а не карта. У поля есть `name`, `type` и необязательное `description`; типов пять: `boolean`, `integer`, `null`, `number`, `string`. Список, а не карта, потому что каждый объект этого контракта замыкает сам себя, а карта произвольных имён этого не умеет.

Другого вида формата у этого члена нет. Голого режима «просто JSON» здесь не предлагают: он обещает валидный JSON и ничего не обещает о его форме, а такое понижение платформа молча не делает.

## Что значит «строго» {#strict keywords="strict, требование, отказ, семантика"}

`strict: true` значит, что поставщик обязан **проследить** за схемой, а не быть к ней склонён. Другого значения этот член не принимает: `strict: false` отвергается по имени, потому что схема, за исполнением которой никто не следит, — это пожелание, а не контракт, и обслуживать под одним именем две разные гарантии было бы хуже, чем отказать.

Строгость доказывается отдельно от самого структурированного вывода. Пара модели и канала, не доказавшая строгих семантик, отвергает такой запрос **до** обращения наверх, а не пробует и не понижает.

## На других диалектах {#dialects keywords="responses, text.format, messages, инструменты"}

На Responses то же требование живёт в `text.format` и несёт четыре члена сразу: `type`, `name`, `strict` и `schema`.

```json title=Responses
{
  "text": {
    "format": {
      "type": "json_schema",
      "name": "postal_address",
      "strict": true,
      "schema": {
        "type": "object",
        "properties": [{ "name": "city", "type": "string" }]
      }
    }
  }
}
```

У диалекта Messages члена структурированного вывода нет вовсе. Когда нужен разобранный объект, объявите там инструмент: его `input_schema` — ваша собственная схема, а аргументы вызова приходят объектом.

> [Как объявить инструмент →](/ru/tools)

## В потоке {#streaming keywords="стриминг, дельты, схема, чанки"}

Структурированный ответ стримится теми же дельтами, что и обычный текст: JSON приходит кусками и становится разбираемым только целиком. Разбирайте после завершающего кадра, а не по дороге.

Стриминг структурированного вывода — своя доказанная возможность, отдельная и от стриминга, и от самого структурированного вывода: в каталоге у пары есть отдельная клетка `structured_output_streaming_status`.

> [Правило завершающего кадра →](/ru/streaming)

## Когда модель отказывается {#refusal keywords="refusal, отказ, content null"}

Модель может отказаться отвечать. Тогда `content` приходит `null`, а рядом лежит `refusal` — её собственная формулировка. Это **ответ, а не ошибка**: запрос обслужен, поставщик его посчитал, и оплачен он как любой другой. Конверт ошибки в этом случае не приходит, статус остаётся успешным, и клиент обязан читать `refusal` сам.

На Responses отказ приходит частью вывода вида `refusal`, а в потоке — событием `response.refusal.delta`.

## Поддержка схемы подтверждается отдельно для каждой модели {#proof keywords="каталог, structured_output_status, strict_semantics_status"}

:::note
Структурированный вывод — доказанная возможность точной пары модели и канала. Каталог держит для неё четыре клетки: `structured_output_status`, `structured_output_mode`, `strict_semantics_status` и `structured_output_streaming_status`. Каждая из трёх «статусных» принимает `proven`, `unproven` или `unsupported`, и «не подтверждено» никогда не значит «наверное, поддерживает»: запрос к недоказанной паре отвергается до обращения наверх. Что доказано у конкретной модели, видно на её карточке в каталоге.
:::

## Что дальше {#next keywords="инструменты, стриминг, ошибки, каталог"}

:::cards
- [Инструменты](/ru/tools) — когда нужен вызов, а не ответ по схеме.
- [Стриминг](/ru/streaming) — как структурированный ответ приходит кусками.
- [Ошибки](/ru/errors) — конверт отказа и коды ответа.
- [Chat Completions](/ru/chat-completions) — члены запроса целиком.
- [Каталог моделей](/ru/models) — какая модель что доказала.
:::
