Structured Output

structured output — гарантированный формат ответа модели

Раздел
Языковые модели
Обновлено
18.05.26

Structured Output — режим LLM, в котором модель **гарантированно** возвращает ответ в заданном формате (обычно JSON по схеме). Раньше приходилось парсить и переспрашивать, теперь OpenAI и Anthropic дают строгий контроль: модель сэмплирует только токены, соответствующие схеме. Главный механизм для интеграции LLM в продакшен-код, где формат критичен.

Коротко

Коротко. Structured Output — это режим API, гарантирующий, что модель вернёт строго в указанной структуре: JSON со схемой, XML, конкретный список значений. До этого режима LLM иногда возвращали «почти JSON» с лишним текстом или обрывали ответ. Теперь OpenAI (с 2024) и Anthropic дают токен-ограниченную генерацию: модель не может выйти за рамки схемы. Главный путь использовать LLM в продакшене.

Что это такое

Программист пишет API: пользователь загружает резюме, получает разбор по полям (имя, опыт, навыки, контакт). Использует GPT для извлечения.

Без structured output:

Извлеки данные из резюме в JSON со схемой 
{name, experience_years, skills (array), contact_email}.

В 95% случаев получает правильный JSON. В 5% — сюрпризы:

  • Вот разбор резюме: {...} — лишний текст до/после.
  • {"name": "Иван", ...} обрывается на середине.
  • {"experience": "5 лет"} — поле experience вместо experience_years.
  • {"skills": "Python, JavaScript"} — строка вместо массива.

Каждые 5% означают, что приложение падает или показывает мусор. Приходится писать обработку ошибок, переспрашивать модель.

С Structured Output:

response = client.chat.completions.create(
    model="gpt-4o-2024-08-06",
    messages=[...],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "resume_data",
            "schema": {
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "experience_years": {"type": "integer"},
                    "skills": {"type": "array", "items": {"type": "string"}},
                    "contact_email": {"type": "string"}
                },
                "required": ["name", "experience_years", "skills"],
                "additionalProperties": false
            },
            "strict": true
        }
    }
)

100% случаев — правильный JSON по схеме. Никаких сюрпризов. Если поле experience_years обязательно — оно будет integer, не строка.

К 2026-му это стандарт для LLM-в-проде:

  • OpenAI: Structured Outputs (с 2024) — JSON Schema или Pydantic-модели.
  • Anthropic: Tool Use с принудительным схемой ответа.
  • Gemini: response_schema параметр.
  • Локальные: llama.cpp grammar-режимы (GBNF), Outlines, Guidance.

Как это работает

Магия не в промпте, а в сэмплировании токенов. Обычно модель на каждом шаге выбирает следующий токен из 50000+ возможных. С Structured Output эта выборка ограничена:

  1. Токенайзер строит грамматику из JSON Schema.
  2. На каждом шаге модель смотрит, какие токены допустимы по грамматике в текущем состоянии.
  3. Невалидные токены отключаются (логит-маска).
  4. Модель сэмплирует только из валидных.

В результате каждый сгенерированный токен гарантированно ведёт к корректному JSON. Невозможно сгенерировать «почти-JSON».

Поддерживаемые форматы (по моделям):

  • JSON Schema — universal (OpenAI, Gemini, локальные).
  • Pydantic-модели — OpenAI Python SDK конвертирует в схему автоматически.
  • TypeScript-интерфейсы — Vercel AI SDK конвертирует.
  • Регулярные выражения — Outlines, Guidance.
  • Grammar (BNF) — llama.cpp, очень гибко.

Пример на практике

Команда строит сервис для контент-аналитики. На вход — статья с сайта, на выход — структурированные метаданные для индексации.

Через OpenAI Structured Output + Pydantic:

from openai import OpenAI
from pydantic import BaseModel
from typing import Literal

class ArticleMetadata(BaseModel):
    title: str
    summary: str
    topic: Literal["tech", "business", "lifestyle", "science"]
    sentiment: Literal["positive", "neutral", "negative"]
    keywords: list[str]
    estimated_reading_minutes: int

client = OpenAI()

resp = client.beta.chat.completions.parse(
    model="gpt-4o-2024-08-06",
    messages=[
        {"role": "system", "content": "Extract article metadata."},
        {"role": "user", "content": article_text}
    ],
    response_format=ArticleMetadata
)

metadata = resp.choices[0].message.parsed  # уже Pydantic-объект
print(metadata.topic)  # "tech" — гарантированно одно из 4
print(metadata.keywords)  # list[str] — гарантированно список строк

Никакого парсинга, никакой обработки ошибок формата. Если topic объявлен как Literal из 4 вариантов — модель не может вернуть пятый. Если keywords это list[str] — не вернёт str или dict.

Обработали 100 000 статей за неделю. Ошибок формата — 0.

В Anthropic похожий результат через Tool Use: определяется «инструмент» с input-схемой, модель должна вызвать инструмент с правильными аргументами. Получается тот же эффект — гарантированный формат.

С чем часто путают

  • Structured Output и JSON Mode — JSON Mode гарантирует, что ответ — валидный JSON, но не контролирует схему. Structured Output — гарантирует и формат, и схему.
  • Structured Output и Function Calling — Function Calling построен на Structured Output: модель «вызывает функцию» с строго типизированными аргументами.
  • Structured Output и Few-Shot для JSON — Few-shot повышает шансы правильного формата, но не гарантирует. Structured Output — гарантирует на уровне сэмплинга.
  • Structured Output и Output Parsing — Parsing это разбор уже сгенерированного текста (post-process). Structured Output — контроль самой генерации.
  • strict: true и strict: falsestrict: true это полная гарантия схемы (медленнее, иногда отказывает). strict: false — best-effort.

Частые ошибки и заблуждения

  • «Structured Output замедляет генерацию». Чуть-чуть (5–15%) — на проверку грамматики на каждом токене. Но качество гарантированно, что обычно стоит этой цены.
  • «Можно использовать любую JSON Schema». Не любую. Поддержка ограничена: oneOf, allOf, if/then/else часто не работают. Поддерживается базовый набор: типы, required, enum, nested objects, arrays.
  • «Structured Output избавляет от галлюцинаций». Только от формата. Содержание всё равно может быть выдумкой. Если попросить вернуть experience_years: integer, и в резюме это не указано — модель сама что-то впишет.
  • «Это работает в любых LLM». Только в моделях с поддержкой. GPT-4 (с 4o-2024-08-06), Claude (через Tool Use), Gemini 1.5+, локальные с Outlines/Guidance. Старые модели — нет.
  • «Pydantic-модели лучше JSON Schema». Удобнее в Python, но под капотом конвертируются в JSON Schema. Возможностей не больше.

Связанные термины

  • JSON Mode — упрощённая версия Structured Output.
  • Function Calling / Tool Calling — построены на Structured Output.
  • JSON Schema — стандарт описания структуры.
  • Pydantic — Python-библиотека для типизации, удобна с SO.
  • Grammar (GBNF) — низкоуровневый аналог в llama.cpp.
  • Outlines / Guidance — библиотеки для SO в локальных моделях.
  • API — главное место применения Structured Output.

Частые вопросы

В каких моделях OpenAI работает Structured Output? GPT-4o (2024-08-06+), GPT-4o-mini (2024-07-18+), o1, o3 и новее. Старые версии — только JSON Mode без схемы.

Что такое strict: true? Параметр, который включает 100% гарантию схемы. Без него модель «старается», но может изредка нарушить. С strict: true нарушение физически невозможно (за счёт логит-масок).

Можно ли вложить объекты? Да, но с ограничениями глубины (обычно 5 уровней). Сложные nested-структуры лучше упростить.

Structured Output работает с потоковой генерацией (streaming)? Да. Можно стримить чанки, парсить incrementally. SDK обычно даёт partial-объекты по мере генерации.

Дороже ли Structured Output по токенам? Нет. Стоимость — обычные input + output токены. Дополнительной платы за схему нет.

В Claude как это работает? Через Tool Use: определяете «инструмент» с input-схемой, модель должна его «вызвать». Эквивалент Structured Output, синтаксис другой.

Главное

Structured Output — это режим LLM-API, гарантирующий, что ответ будет строго по заданной схеме. Не «попросили JSON и надеемся», а «модель физически не может вернуть не-JSON по схеме». Реализуется через ограничение сэмплинга на токенах: невалидные варианты отключаются на каждом шаге. Главные применения: API в проде, извлечение данных, классификация с фиксированным списком значений, любая интеграция, где формат важнее, чем «креатив». Лучшая практика — описывать схему через Pydantic (Python) или TypeScript (Node.js), SDK конвертирует в JSON Schema автоматически. К 2026-му без Structured Output работать с LLM в проде уже не принято.