# Структурированный вывод (JSON mode)

> Способы заставить языковую модель отвечать данными строго заданной формы — JSON по схеме — через промпт, JSON mode, ограниченное декодирование и валидацию.

Источник: https://llmdocs.ru/wiki/structured-output/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0

- **Задача**: получать от LLM машиночитаемые данные вместо свободного текста
- **Формат схем**: JSON Schema
- **Уровни гарантий**: промпт → JSON mode → строгая схема (constrained decoding)
- **Библиотеки**: Pydantic, Instructor, Outlines, XGrammar, llguidance
- **Поддержка в API**: OpenAI, Anthropic, Google, vLLM, llama.cpp
**Структурированный вывод** (англ. *structured output*) — режим работы [языковой модели](https://llmdocs.ru/wiki/llm.md), при котором ответ представляет собой данные заданной формы, чаще всего [JSON](https://llmdocs.ru/wiki/json.md) по схеме, а не свободный текст. Это нужно везде, где ответ модели читает программа: извлечение полей из документов, классификация, заполнение форм, вызов функций в [агентах](https://llmdocs.ru/wiki/ai-agent.md). Без специальных мер модель время от времени добавляет пояснения, пропускает поля, путает типы или выдаёт синтаксически сломанный JSON — и каждый такой случай ломает конвейер.

## Уровни гарантий

| Подход | Как | Гарантия |
|---|---|---|
| Просьба в промпте | «Ответь только JSON вида …» с примером | никакой; ошибки в процентах случаев |
| JSON mode | API гарантирует синтаксически корректный JSON | синтаксис, но не схема |
| Строгая схема | API или движок ограничивает генерацию по JSON Schema | синтаксис и структура |
| Валидация и повтор | проверить ответ, при ошибке отправить её модели | зависит от числа попыток |

Хорошая практика — сочетать строгую схему на уровне генерации и валидацию на стороне приложения: схема гарантирует форму, но не правильность значений.

## Ограниченное декодирование

Модель генерирует текст по одному [токену](https://llmdocs.ru/wiki/tokenization.md), каждый раз выбирая из распределения вероятностей по словарю. **Ограниченное декодирование** (constrained decoding) на каждом шаге обнуляет вероятность токенов, недопустимых по грамматике: после `{"age": ` разрешены только цифры, после закрытия последнего обязательного поля — только `}`. Схема JSON или регулярное выражение компилируется в конечный автомат или грамматику, и проверка выполняется быстро.[4]

На этом принципе работают режим strict в API OpenAI, структурированный вывод Anthropic, движки Outlines, XGrammar и llguidance, встроенные в [инференс-серверы](https://llmdocs.ru/wiki/vllm.md), и грамматики GBNF в llama.cpp.[1][2][5][7] Поддерживается не вся JSON Schema: обычно доступны объекты, массивы, перечисления, обязательные поля и вложенность, но часть ограничений (форматы, сложные условия) не применяется.[3]

## Пример

Схему удобно описывать классами Pydantic и получать сразу типизированный объект (см. [Dataclasses и Pydantic](https://llmdocs.ru/wiki/dataclasses-pydantic.md)):

```python
from pydantic import BaseModel, Field
from openai import OpenAI

class Vacancy(BaseModel):
    title: str
    salary_from: int | None = Field(description="в рублях, без НДФЛ")
    remote: bool
    stack: list[str]

client = OpenAI()
resp = client.responses.parse(
    model="gpt-5-mini",
    input=[{"role": "user", "content": f"Извлеки поля из вакансии:\n{text}"}],
    text_format=Vacancy,
)
vacancy: Vacancy = resp.output_parsed
```

Библиотека Instructor даёт такой же интерфейс для разных провайдеров и локальных моделей, добавляя автоматический повтор с текстом ошибки валидации.[6]

## Связь с вызовом инструментов

[Вызов инструментов](https://llmdocs.ru/wiki/tool-use.md) технически — тот же структурированный вывод: модель выдаёт имя функции и аргументы по JSON Schema. Поэтому один из способов получить структуру — объявить «инструмент» с нужной схемой и потребовать его вызова. Современные API предлагают для этого отдельный режим.

## Практические советы

- **Порядок полей важен.** Модель генерирует слева направо: поле с рассуждением (`reasoning`) перед итоговым ответом улучшает точность, после — бесполезно.
- **Описания полей** в схеме работают как часть промпта: единицы измерения, формат дат, что делать при отсутствии значения.
- **Оставлять выход.** Для извлечения данных нужен способ сказать «не найдено» (`null`, отдельное перечисление), иначе модель выдумает значение — см. [Галлюцинации LLM](https://llmdocs.ru/wiki/hallucinations.md).
- **Не перегружать схему.** Глубоко вложенные структуры с десятками полей лучше разбить на несколько вызовов.
- **Жёсткие ограничения могут вредить.** Если формат мешает модели «думать», качество падает; иногда лучше дать свободный ответ, а затем извлечь из него структуру вторым вызовом.
- **Проверять смысл**, а не только форму: правильный по схеме JSON может содержать неверные данные. Качество измеряют на размеченном наборе — см. [Оценка LLM (evals)](https://llmdocs.ru/wiki/llm-evals.md).

## См. также

- [Tool use / function calling](https://llmdocs.ru/wiki/tool-use.md)
- [JSON](https://llmdocs.ru/wiki/json.md)
- [Промпт-инжиниринг](https://llmdocs.ru/wiki/prompt-engineering.md)
- [Dataclasses и Pydantic](https://llmdocs.ru/wiki/dataclasses-pydantic.md)
- [Галлюцинации LLM](https://llmdocs.ru/wiki/hallucinations.md)

## Источники

1. [OpenAI — Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs)
2. [Anthropic — Structured outputs](https://docs.claude.com/en/docs/build-with-claude/structured-outputs)
3. [JSON Schema — specification](https://json-schema.org/specification)
4. [Willard, Louf — Efficient Guided Generation for Large Language Models (Outlines, 2023)](https://arxiv.org/abs/2307.09702)
5. [llama.cpp — GBNF grammars](https://github.com/ggml-org/llama.cpp/blob/master/grammars/README.md)
6. [Instructor — документация](https://python.useinstructor.com/)
7. [vLLM — Structured Outputs](https://docs.vllm.ai/en/latest/features/structured_outputs.html)
