Как ИИ генерирует JSON по JSON Schema: от Prompt к Structured Output

От JSON только в промпте и JSON Mode к Structured Outputs — ограничения JSON Schema, сравнение OpenAI / Gemini / Anthropic, pipeline проверки и отличие от Tool Calling.

В предыдущих публикациях этой серии рассматривалисьзачем агентам нужен JSON(Вызов инструмент в потоке данных MCP),почему JSON Schema⟧ стала инфраструктурой(Схема, Вызова функция и MCP эволюция), иКонфигурация Structured Output, специфичная для Gemini(Gemini API руководство).

Эта статья уменьшена:независимо от того, какую модель API вы используете, как перейти от «пожалуйста, ответьте в JSON» к «вывод должен соответствовать этой JSON схеме⟧»? Поставщики сошлись на этом в 2024–2026 годах под такими названиями, как Structured Outputs⟧ / JSON Schema⟧ mode — та же идея, немного другие имена полей, подмножества схемы и границы с Tool Calling.

Четыре уровня, каждый из которых «строже» предыдущего.

Для получения JSON из модели команды обычно используют четыре подхода — надежность различается на порядок:

УровеньПодходЧто вы контролируетеТипичный отказ
L0Только запрос: «вывод JSON»Мягкое ограничение```json fences, prose, single quotes, trailing commas
L1Подсказка + несколько примеров JSONФормируйте на собственном примере, без жестких правилДрейф имени поля, отсутствующие поля, смешанные типы
L2JSON Mode⟧ (response_format: json_object, etc.)Вывод должен быть действительным JSONParses, but price may be a string
L3Структурированный вывод+ JSON Схема⟧Поля, типы, перечисления, обязательныеСемантическая галлюцинация, усечение, игнорируемые ключевые слова

For production extraction, classification, or form filling, aim for L3. L0–L1 suit exploration; L2 when shape varies and you only need JSON.parse. L3 is the contract programs can consume directly.

Что контролирует JSON Schema⟧, а что нет

JSON Схема⟧описывает структуру документа: поля, типы, необходимые ключи, перечисления, диапазоны, форму элемента массива. Поставщик Структурированный выводs⟧ компилирует эту схему в генерацию, а не просто вставляет ее в командную строку.

Schema can enforce: syntax shape (object / array / string / integer), required, enum, minimum / maximum, additionalProperties: false, nested objects and arrays.

Schema cannot enforce business correctness. Example: “total_cents must equal sum of line items” — assert that in code after Schema validation. Schema also does not fact-check: a well-typed fabricated invoice number is still hallucination.

Tool inputSchema uses the same language; Structured Output constrains the final reply, Tool Calling constrains tool arguments. See руководство по потоку данных.

Ограниченное декодирование: почему Schema превосходит Prompt

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

Обычно вы получаете анализируемый, корректный по форме JSON без ограничений уценки с удалением регулярных выражений. Реализации различаются (FSM, грамматика, логит-маски), но контракт разработчика тот же:передать схему в API, а не только приглашение.

Ограниченные гарантии декодированияструктура, нетсемантика. Всегда выполняйте повторную проверку с использованием той же схемы и добавляйте бизнес-правила в производство.

OpenAI, Gemini, Anthropic сравнение

Та же концепция, разные имена полей. Пример: извлеките один объект счета.

ПродавецРежим JSONСтруктурированный вывод/СхемаПримечания
OpenAIresponse_format: { type: "json_object" }response_format: { type: "json_schema", json_schema: { name, schema, strict: true } }strict: true rejects undeclared fields; works with Pydantic model_json_schema()
Google БлизнецыresponseMimeType: "application/json"Above + responseJsonSchema or SDK response_schemaВидетьспециальная статья о Gemini API
АнтропныйПодсказка + разборoutput_format (Claude structured output) or schema in Messages APIПоля развиваются вместе с SDK; сохранять схему плоской

When migrating vendors, keep the Schema itself standard JSON Schema⟧ (type, properties, required, enum); SDKs only wrap the request. Do not mix OpenAPI 3.0 uppercase types (OBJECT) with JSON Schema⟧ lowercase (object).

Написание хорошей схемы: от Pydantic к производству

Recommended flow: define types in Pydantic / Zod → export JSON Schema⟧ → tune → send to API. Put semantics in description — it enters model context and disambiguates “qty = pieces vs boxes”; type: integer alone cannot.

from pydantic import BaseModel, Field


class LineItem(BaseModel):
    name: str = Field(description="Product name")
    qty: int = Field(description="Quantity, positive integer", ge=1)
    unit_price_cents: int = Field(description="Unit price in cents", ge=0)


class Invoice(BaseModel):
    vendor: str
    currency: str = Field(description="ISO 4217, e.g. CNY")
    items: list[LineItem]
    total_cents: int

schema = Invoice.model_json_schema()
# In production add additionalProperties: false

Практические правила:

  • Prefer object root over root-level array; { "items": [...] } is more stable on some APIs.
  • Start with type / properties / required / enum, then add additionalProperties, min/max; do not dump full Draft 2020-12 — some keywords are ignored.
  • Продолжайте вкладывать неглубоко; циклические ссылки отклоняются — сглаживайте схему.
  • Разделенная схема против подсказки: Схема = форма; Подсказка = семантика («извлечь счет из текста ниже…»).

OpenAI Пример структурированного выводаs⟧

Chat Completions supports json_schema response format since 2024. With strict: true, output should only contain Schema fields:

from openai import OpenAI
from pydantic import BaseModel

client = OpenAI()

class Invoice(BaseModel):
    vendor: str
    total_cents: int

response = client.chat.completions.create(
    model="gpt-4o-2024-08-06",
    messages=[
        {"role": "user", "content": "Extract invoice: Acme sold 2 keyboards for 398 CNY."}
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "invoice",
            "strict": True,
            "schema": Invoice.model_json_schema(),
        },
    },
)

data = response.choices[0].message.content  # JSON string
import json
invoice = json.loads(data)

Gemini uses response_mime_type + response_json_schema — see the dedicated Gemini API article. For Anthropic, check current SDK structured output docs — same idea, official field names.

Производственный конвейер: генерировать → анализировать → проверять → повторять попытку.

Структурированный вывод — это не «один вызов API и готово». Исправьте эти четыре шага:

  1. Generate: call model with Schema; log prompt, Schema version, raw content.
  2. Parse: JSON.parse (or SDK parsed); on failure, retry whole response — no half-parse.
  3. Schema validate: run same JSON Schema⟧ via AJV / jsonschema / Pydantic; retry or degrade on failure.
  4. Бизнес-подтверждение: пользовательские утверждения (итогов, внешние ключи); человек или правила двигателя при сбое.

В разработке сохраните Schema плюс 2–3 положительных/отрицательных образца в репозитории; используйте JSON Toolbox⟧ локально для структуры и Diff — тот же подход, что и для контрактных тестов REST, потребитель — это LLM.

Распространенные ошибки: запрос «объясните тогда JSON», когда режим JSON включен; усечение (увеличение максимального количества токенов или разделение задач); API ключи в демоверсиях интерфейса; Версия схемы отклоняется от подсказки.

Чем он отличается от Tool Calling

Структурированный выводВызов инструмента / MCP
ОграниченияОкончательный ответ пользователю в формате JSONTool argument JSON (inputSchema)
Побочные эффектыНет — только данныеHost / MCP Сервер выполняет
Типичное использованиеИзвлечение, классификация, заполнение форм, передача агентаИнвентарь, файлы, внешние API
При неудачеПовторить попытку или человекОшибка в сообщении инструмента → спросите модель еще раз

Полный цикл агента часто выглядит так:Структурированный вывод извлекает намерение → Вызов инструмента действует → Структурированный вывод или суммирует для пользователя. Не используйте Structured Output, чтобы представить «вызов платежа API» — модель его не вызывала.

Часто задаваемые вопросы

Достаточно ли в командной строке «пожалуйста, выведите JSON»?

Нет. Подсказки только повышают шансы на соответствие — ограничения уценки, конечные запятые и дрейф полей по-прежнему случаются. В рабочей среде включите как минимум JSON Mode⟧; в идеале передать JSON Schema⟧ через канал API Structured Output, чтобы декодирование исключало незаконные токены.

В чем разница между JSON Mode⟧ и Structured Output?

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

Являются ли поля конфигурации OpenAI, Gemini и Anthropic одинаковыми?

Одна и та же концепция, разные названия. OpenAI: формат ответа с json_schema и strict; Gemini: responseMimeType + responseJsonSchema; Антропный: output_format или структурированный вывод в инструментах. Сохраняйте стандарт схемы; SDK оборачивают запросы.

Может ли Структурированный вывод заменить Вызов инструмента?

Нет. Структурированный вывод ограничивает окончательный ответ JSON; Вызов инструмента ограничивает аргумент инструмента JSON и требует, чтобы хост выполнял инструменты. Используйте первое для извлечения/классификации/заполнения; последний для инвентаря, файлов, MCP. Полные агентские сети часто используют оба варианта.

Нужно ли мне еще проверять выходные данные модели?

Да. Ограниченное декодирование сокращает синтаксические ошибки и дрейф типов, но не семантическую корректность (допустимые типы, сфабрикованные значения). Повторно запустите ту же самую JSON Schema⟧ в рабочей среде; повторите попытку, ухудшите качество или проверьте в случае неудачи.

Как проверить схему и образец вывода локально?

Сохраните JSON Schema⟧ и несколько образцов выходных данных модели в виде файлов JSON; используйте JSON Toolbox⟧ в браузере для проверки синтаксиса и структуры — ничего не загружается.

Краткое содержание

Чтобы получить JSON, соответствующий JSON Schema⟧ от ИИ, порядок имеет значение:сначала определите схему, включите JSON Mode⟧ / Structured Output, затем напишите приглашение. Подсказка = семантика; Схема = форма; Pydantic / Zod — дружественные к авторам фронты; API поставщика предоставляют каналы схемы.

Запустите один реальный счет или сквозную расшифровку расшифровки: Схема → API вызов → вставьте выходные данные в валидатор. Когда оно совпадает, подключите базу данных или следующего агента. Инструментальные аргументы по-прежнему проходят через Tool Calling/MCP — не сливаются в один API.