Структурированный вывод LLM API: JSON Mode, JSON Schema и реальная поддержка у каждого провайдера (2026)
Практическое руководство по structured output (response_format) для OpenAI, Anthropic, DashScope, DeepSeek и SiliconFlow. Разбираем json_object, json_schema strict mode, output_config у Anthropic, взаимодействие со streaming, ограничения глубины schema и проблемы совместимости при маршрутизации запросов между провайдерами.
Получить валидный JSON от LLM — звучит просто. Пока не попробуешь сделать это через пять провайдеров. Один предлагает strict schema enforcement на уровне токенов. Другой поддерживает json_object, но не json_schema. Третий использует совершенно другое имя параметра. А когда тот же запрос проходит через gateway, параметр structured output может быть, а может и не быть корректно транслирован.
Мы маршрутизируем structured-output запросы через OpenAI, Anthropic, DashScope, DeepSeek и SiliconFlow каждый день. В этом руководстве задокументировано, что именно поддерживает каждый провайдер, где возникают несовместимости и как построить production pipeline, который получает надёжный JSON независимо от того, какой провайдер обрабатывает запрос.
OpenAI-совместимость означает, что провайдер предоставляет endpoint chat-completions, чей контракт запроса и ответа достаточно близок к API OpenAI, чтобы немодифицированный вызов OpenAI SDK работал после замены трёх значений: API key, base URL, название модели. Минимальная поверхность на практике —POST /v1/chat/completions с messages, model и потоковым ответом в форме OpenAI.
Сводная таблица
| Провайдер | json_object | json_schema (strict) | Нативный параметр | Нужен "json" в prompt | Streaming + structured |
|---|---|---|---|---|---|
| OpenAI | Да | Да (constrained decoding) | response_format | Только json_object | Да |
| Anthropic | Нет (используйте output_config) | Да (grammar-based) | output_config.format | Нет | Да |
| DashScope | Да | Нет (только json_object) | response_format | Да | Да |
| DeepSeek | Да | Нет (только json_object) | response_format | Да | Да |
| SiliconFlow | Да (зависит от модели) | Нет | response_format | Да (рекомендуется) | Да |
Главный вывод: только OpenAI и Anthropic предлагают гарантированный schema structured output через constrained decoding. DashScope, DeepSeek и SiliconFlow поддерживают json_object — валидность JSON-синтаксиса гарантирована, но schema (имена полей, типы, вложенность) не контролируется на уровне token-генерации.
Как это работает под капотом
JSON Object mode (type: "json_object") сообщает модели, что нужно выдать валидный JSON. Провайдер ограничивает генерацию токенов — скобки закрываются правильно, строки в кавычках и т.д. Но модель может вернуть любую валидную JSON-структуру. Если вы ожидали {"name": string, "age": number}, можете получить {"full_name": "Alice", "years_old": 25}. Валидный JSON, неверный schema.
JSON Schema mode (type: "json_schema") использует constrained decoding с конечным автоматом, отслеживающим позицию в schema. На каждом токене модель может сгенерировать только токены, валидные в текущей позиции schema. Результат гарантированно соответствует schema — не просто валидный JSON, а именно та структура, которую вы указали.
Это различие критически важно для production: с json_object всё равно нужна валидация на уровне приложения; с json_schema провайдер берёт это на себя.
OpenAI: полный стек structured output
OpenAI предлагает наиболее полную реализацию structured output. Два режима через параметр response_format.
JSON Object Mode (legacy)
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(
model="gpt-5.6",
messages=[
{"role": "system", "content": "Извлеки детали события. Верни JSON."},
{"role": "user", "content": "Алиса и Боб встречаются в полдень в пятницу на обед."}
],
response_format={"type": "json_object"}
)
data = json.loads(response.choices[0].message.content)
В сообщениях обязательно должно быть слово "json" — иначе API вернёт ошибку. Вывод — валидный JSON, но не обязательно по вашему schema.
JSON Schema Mode (рекомендуется)
from openai import OpenAI
from pydantic import BaseModel
client = OpenAI()
class CalendarEvent(BaseModel):
name: str
date: str
participants: list[str]
response = client.responses.parse(
model="gpt-5.6",
input=[
{"role": "system", "content": "Извлеки информацию о событии."},
{"role": "user", "content": "Алиса и Боб идут на научную выставку в пятницу."}
],
text_format=CalendarEvent,
)
event = response.output_parsed # CalendarEvent, schema гарантирован
Ключевые детали:
- Constrained decoding — модель буквально не может генерировать токены, нарушающие schema
- Поддерживаемые модели — GPT-4o и позже, включая GPT-5.6
- Возможности schema — вложенные объекты, массивы, enum, опциональные поля,
anyOf/allOf - Обработка отказов — при отказе модели
response.refusalзаполняется;output_parsed=None - Streaming — поддерживается; chunks собираются в schema-валидный JSON
Ограничения schema: все поля должны быть required (nullable типы для опциональных), additionalProperties должен быть false, рекурсивные schema имеют ограничение глубины.
Источник: OpenAI Structured Outputs Guide (получено 2026-08-04)
Anthropic Claude: output_config с grammar-based enforcement
Anthropic использует другой подход. Вместо расширения response_format Claude использует отдельный параметр output_config с grammar-based constrained decoding.
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=1024,
messages=[
{"role": "user", "content": "Извлеки сущности из текста: Встреча в штаб-квартире Google во вторник."}
],
output_config={
"format": "json",
"schema": {
"type": "object",
"properties": {
"entities": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {"type": "string"},
"type": {"type": "string", "enum": ["person", "org", "location", "date"]},
"confidence": {"type": "number", "minimum": 0, "maximum": 1}
},
"required": ["name", "type", "confidence"]
}
}
},
"required": ["entities"]
}
}
)
Ключевые отличия от OpenAI:
- Имя параметра —
output_config, а неresponse_format. Не совместим с OpenAI. - Grammar сбрасывается между секциями — при использовании extended thinking grammar применяется только к финальному ответу, а не к блоку рассуждений. Claude может свободно рассуждать, а затем сгенерировать structured output.
- Нет
json_objectmode — Anthropic не поддерживает простой режим «просто дай валидный JSON». Либо полный schema, либо workaround через tool-use. - Несовместимости — citations и prefix-filling (prefill assistant message) несовместимы с
output_config. - Поддерживаемые модели — Claude Opus 4 и Claude Sonnet 4.5 и позже.
Источник: Anthropic Structured Outputs (получено 2026-08-04)
DashScope (Qwen): json_object через OpenAI-совместимый API
DashScope поддерживает structured output через OpenAI-совместимый endpoint, но только json_object — без strict json_schema.
from openai import OpenAI
client = OpenAI(
api_key="your-dashscope-key",
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)
response = client.chat.completions.create(
model="qwen-plus",
messages=[
{"role": "system", "content": "Извлеки имя и возраст пользователя. Верни JSON."},
{"role": "user", "content": "Привет, я Alex Brown, мне 34 года."}
],
response_format={"type": "json_object"}
)
data = json.loads(response.choices[0].message.content)
Ключевые детали:
- Модели — Qwen-Max, Qwen-Plus, Qwen-Flash, Qwen-Turbo, Qwen-Coder, Qwen-Long (все в non-thinking mode). Мультимодальные (Qwen-VL, Qwen-Omni) тоже поддерживаются.
- "json" в prompt обязателен — слово "JSON" (без учёта регистра) должно быть в system или user message.
- Thinking mode — модели в thinking mode принимают
json_objectбез ошибки, но некоторые могут вернуть невалидный JSON. - Нет
json_schema—type: "json_schema"не поддерживается.
Источник: DashScope Structured Output (получено 2026-08-04)
DeepSeek: только json_object
DeepSeek поддерживает structured output через json_object.
from openai import OpenAI
client = OpenAI(
api_key="your-deepseek-key",
base_url="https://api.deepseek.com"
)
response = client.chat.completions.create(
model="deepseek-v4-pro",
messages=[
{"role": "system", "content": "Разбери вопрос и ответ в JSON формат."},
{"role": "user", "content": "Какая самая высокая гора? Эверест."}
],
response_format={"type": "json_object"}
)
data = json.loads(response.choices[0].message.content)
Ключевые детали:
- Модели — DeepSeek V4 Pro, DeepSeek V4 Flash
- "json" в prompt — обязателен, как у OpenAI в
json_objectmode - Нет
json_schema— толькоjson_object - Reasoning-модели — DeepSeek-R1 и reasoning mode имеют ограниченную поддержку
json_object
Источник: DeepSeek JSON Output (получено 2026-08-04)
SiliconFlow: OpenAI-совместимый json_object
SiliconFlow предоставляет json_object через OpenAI-совместимый API, но доступность зависит от модели.
from openai import OpenAI
client = OpenAI(
api_key="your-siliconflow-key",
base_url="https://api.siliconflow.cn/v1"
)
response = client.chat.completions.create(
model="Qwen/Qwen3-8B",
messages=[
{"role": "system", "content": "Верни ответ в формате JSON."},
{"role": "user", "content": "Назови топ-3 языка программирования."}
],
response_format={"type": "json_object"}
)
Ключевые детали:
- Зависит от модели — не все модели на SiliconFlow поддерживают
response_format - OpenAI-совместимый — тот же параметр
response_format - Нет
json_schema— толькоjson_object - "json" в prompt — рекомендуется для стабильности
Источник: SiliconFlow Chat Completions API (получено 2026-08-04)
Подводные камни при маршрутизации между провайдерами
При маршрутизации structured-output запросов через TheRouter или любой gateway возникает несколько проблем совместимости.
1. Даунгрейд json_schema
Если запрос использует response_format: {type: "json_schema", json_schema: {...}} и маршрутизируется к DashScope или DeepSeek, strict schema enforcement теряется. Gateway может понизить до json_object и вставить schema в system prompt, но это best-effort.
Смягчение: Добавьте валидацию JSON Schema на уровне приложения после каждого ответа. jsonschema (Python) или ajv (JavaScript) дают пренебрежимую латентность.
2. Трансляция параметров Anthropic
Anthropic использует output_config вместо response_format. Gateway должен транслировать параметр и учитывать, что Claude вообще не поддерживает json_object.
3. Требование "json" в prompt
OpenAI (json_object mode), DashScope и DeepSeek требуют слово "json" в сообщениях. Anthropic — нет.
Смягчение: Всегда включайте "json" в system prompt при использовании response_format. Для провайдеров, которым это не нужно, это безвредно.
4. Streaming + structured output
Все провайдеры поддерживают streaming со structured output, но поведение различается:
- OpenAI — каждый chunk — частичный JSON-фрагмент; собранный результат schema-валиден
- Anthropic — streaming с
output_configработает; grammar constraint действует между chunks - DashScope / DeepSeek — streaming выдаёт частичные JSON chunks; только финальный результат гарантированно валиден
5. Ограничения глубины schema
OpenAI json_schema имеет ограничения: максимум 5 уровней для anyOf, все поля required, additionalProperties: false обязателен.
DashScope и DeepSeek не имеют ограничений schema — но и не гарантируют его соблюдение.
Чеклист для production
-
Всегда валидируйте после генерации — даже с
json_schemaпроверяйте ответ в коде приложения. -
Стратегия retry — при ошибке JSON-парсинга попробуйте упрощённый prompt или переключитесь через fallback routing.
-
Достаточный
max_tokens— если token limit достигнут посреди JSON, получится невалидный JSON. -
Логируйте сырой ответ — для отладки schema-несоответствий.
-
Тестируйте на всех провайдерах — schema, работающий на OpenAI, может давать другой порядок полей на DashScope.
-
Обрабатывайте отказы — OpenAI возвращает
refusal, Anthropic —stop_reason: "end_turn"с возможно пустым контентом, DashScope/DeepSeek могут вернуть текст вместо JSON.
Интеграция с TheRouter
TheRouter маршрутизирует OpenAI-совместимые запросы через настроенных провайдеров, включая structured-output запросы. Когда запрос содержит response_format, TheRouter сохраняет параметр для провайдеров, которые его поддерживают (OpenAI, DashScope, DeepSeek, SiliconFlow). Для Anthropic трансляция следует провайдер-специфичному маппингу.
Если запрос указывает json_schema, а маршрутизированный провайдер поддерживает только json_object, schema enforcement зависит от провайдера. Мы рекомендуем валидацию на уровне приложения в любом случае.
При fallback routing structured-output параметры сохраняются между retry. Fallback-провайдер может иметь другой уровень поддержки schema.
Частые ошибки и решения
| Ошибка | Провайдер | Причина | Решение |
|---|---|---|---|
messages must contain the word 'json' | OpenAI, DashScope, DeepSeek | json_object без "json" в сообщениях | Добавить "Return JSON" в system prompt |
Invalid response_format type | DashScope, DeepSeek | json_schema на провайдере без его поддержки | Даунгрейд до json_object + schema в prompt |
output_config is incompatible with citations | Anthropic | output_config + citations | Отключить citations или tool-use workaround |
| Обрезанный JSON | Все | max_tokens слишком мал | Увеличить max_tokens |
| Валидный JSON, неверный schema | DashScope, DeepSeek, SiliconFlow | json_object не контролирует schema | Валидация JSON Schema после генерации |
| Пустой content + stop_reason | Anthropic | Модель отказала | Проверить отказ; повторить с изменённым prompt |
FAQ
Можно ли использовать json_schema с reasoning-моделями?
Зависит от провайдера. OpenAI поддерживает json_schema с o-series. Anthropic output_config работает с extended thinking — grammar применяется только к финальному ответу. DashScope предупреждает, что thinking-mode модели могут вернуть невалидный JSON даже с json_object.
tool-use или response_format для structured output?
response_format (или output_config на Anthropic) — когда сам ответ модели должен быть structured JSON. tool-use — когда модель подключается к реальным функциям. Подробнее в руководстве по function calling.
Instructor или Outlines?
Instructor (Python/TypeScript) и Outlines обеспечивают structured output на уровне фреймворка. Instructor оборачивает клиент провайдера и добавляет Pydantic/Zod валидацию с автоматическими retry. Outlines использует grammar-constrained decoding для локальных моделей.
Как structured output взаимодействует с prompt caching?
На OpenAI запросы с одинаковым json_schema выигрывают от prompt caching. На Anthropic output_config не взаимодействует с cache_control. На DashScope json_object кэшируется нормально через context caching.
Последняя проверка: 4 августа 2026 года. API провайдеров меняются; проверяйте официальную документацию для актуальной информации о поддержке schema.