Структурированный вывод
JSON, схемы и валидированные ответы
Проблема: LLM создают красивые тексты, но вашему коду нужен JSON. Свободный текст ломает парсеры, имеет непредсказуемый формат и требует хрупких регулярных выражений для извлечения данных. Как получить надёжный, машиночитаемый вывод?
Решение: Укрощение свободного текста в структуры данных
Structured output (структурированный вывод) — это способ ограничить ответ LLM так, чтобы он следовал конкретной схеме: JSON-объекту, типизированному набору параметров функции или любой валидируемой структуре данных, вместо свободного текста. Представь, что ты даёшь модели форму для заполнения, а не чистый лист. Обычный промпт может вернуть «Конечно! Клиента зовут Анна, сумма заказа примерно 42 доллара.» — отлично читается человеком, но для кода это кошмар. Структурированный вывод заставляет тот же ответ принять вид { "name": "Анна", "total": 42.0 }, и так каждый раз.
Как это работает
Под капотом есть два основных механизма. JSON mode сообщает модели, что весь её ответ должен быть одним валидным JSON-документом, — это убирает «полезную» болтовню вокруг данных. Function calling (вызов функций, он же tool calling) идёт дальше: ты описываешь функцию и её параметры как схему, и API ограничивает генерацию так, что модель может выдать только аргументы, совпадающие по именам полей и типам с твоим описанием. Многие провайдеры реализуют это через ограниченное декодирование (constrained decoding) — на каждом шаге модель может выбрать только те токены, которые сохраняют вывод синтаксически валидным по схеме, так что некорректный ответ становится структурно невозможным, а не просто маловероятным.
Когда применять — и в чём подвох
Используй структурированный вывод всегда, когда ответ LLM напрямую подаётся в другой код: пайплайны извлечения данных, ответы API, запись в базу, вызовы инструментов агентом или генерация конфигов. Главный выигрыш в том, что можно выбросить хрупкие регулярки и парсинг строк и доверять форме данных. Ключевой подвох: валидный JSON — это не то же самое, что верные данные. Схема гарантирует форму (есть поле total, и оно число), но никогда не гарантирует смысл — модель всё ещё может галлюцинировать неправильное число или перевернуть булево значение. Например, попроси счёт в виде { "amount": number, "currency": string, "paid": boolean } — и получишь идеально валидный JSON, где amount ошибается на разряд, а paid перевёрнут. Всегда валидируй значения инструментом вроде Pydantic или Zod, а не только схему, и при ошибке возвращай её модели для одной-двух повторных попыток.
Представьте это как заполнение формы вместо написания сочинения:
- 1. Определяем схему вывода: Пишем JSON Schema, модель Pydantic или интерфейс TypeScript, описывающий точную форму данных
- 2. Включаем JSON mode или function calling: Передаём схему в API; модель теперь ограничена выводом, соответствующим этой структуре
- 3. LLM генерирует вывод, соответствующий схеме: Модель заполняет поля как форму — имена полей, типы и вложенность гарантированы
- 4. Парсим и валидируем по схеме: Десериализуем и запускаем валидацию Pydantic/Zod для выявления семантических ошибок, а не только ошибок формата
- 5. Повторяем с описанием ошибки при невалидном результате: При ошибке валидации возвращаем сообщение об ошибке модели для самокоррекции (не более 2 попыток)
Где это используется?
- Форматирование ответов API: Гарантированные JSON-ответы, которые парсеры могут использовать без обработки ошибок формата
- Пайплайны извлечения данных: Извлечение структурированных полей (имя, дата, сумма) из неструктурированных документов в масштабе
- Автоматизация заполнения форм: Преобразование произвольных форм или писем в валидированные записи базы данных
- Генерация конфигурации: Превращение описаний фич на естественном языке в типизированные объекты конфигурации или infrastructure-as-code
- Частая ловушка: семантически неверные значения: Даже в JSON mode LLM может выдать валидный JSON с неверными значениями (придуманные даты, инвертированные булевы) — всегда валидируйте значения, а не только форму схемы, с помощью Pydantic или Zod
Интересный факт: Без JSON mode LLM добавляют "полезный" текст вокруг JSON примерно в 30% случаев: "Вот запрошенный JSON: {...}". С JSON mode это снижается до 0%. Function calling идёт дальше — гарантирует не просто валидный JSON, но валидный JSON, соответствующий вашей точной схеме. Разница в ошибках парсинга: 30% → 0,5%.
Попробуйте сами!
Используй интерактивный пример ниже, чтобы увидеть разницу между свободным текстом и структурированным выводом, и создай собственные схемы для надёжного извлечения данных.
Structured Output Explorer
ИнтерактивноВходной текст
Привет, я Сара Чен из Acme Corp. Меня можно найти по sarah@acme.com или позвонить 555-0123. Я в Сан-Франциско и хотела бы обсудить предложение о партнёрстве на Q3.
Отправитель — Сара Чен из компании Acme Corp. Её email: sarah@acme.com, телефон: 555-0123. Она находится в Сан-Франциско и хочет обсудить предложение о партнёрстве Q3.
- • JSON mode устраняет 30% ответов, которые оборачивают JSON в «полезную» прозу.
- • Function calling гарантирует соответствие ВАШЕЙ схеме — поля, типы, обязательные/опциональные.
- • Всегда валидируйте + retry: большинство ошибок формата решаются за 1 retry с обратной связью.
Частые вопросы
Что такое JSON mode и когда его использовать?
JSON mode заставляет LLM выдавать валидный JSON. Используйте когда нужен машиночитаемый вывод — ответы API, извлечение данных, заполнение форм. Большинство провайдеров поддерживают через параметр (response_format: json_object).
Как function calling помогает со структурированным выводом?
Function calling позволяет задать точную схему (параметры с типами, обязательные поля, enum). LLM заполняет схему вместо генерации свободного текста. Это гарантирует соответствие формату и позволяет типобезопасную интеграцию.
Что делать, если LLM вернёт невалидный вывод?
Реализуйте валидацию + повтор: распарсите вывод, проверьте по схеме, при ошибке отправьте сообщение об ошибке обратно LLM с просьбой исправить. Большинство сбоев решаются за 1 повтор. Установите лимит (2–3 попытки).
Можно ли получить вложенные или сложные структуры?
Да. Чётко определите вложенные схемы с примерами. Для очень сложных структур разбейте на несколько вызовов — сначала верхнеуровневые поля, затем детали каждого. Pydantic-модели отлично подходят для определения и валидации сложных схем.
Попробуй сам
Интерактивное демо этой техники
Извлеки контактную информацию из подписи email в формате JSON
Имя: Иван Петров Должность: Директор по маркетингу Email: ivan@techcorp.ru Телефон: +7 (495) 123-45-67
{ "name": "Иван Петров", "title": "Директор по маркетингу", "company": "ООО ТехКорп", "email": "ivan@techcorp.ru", "phone": "+7 (495) 123-45-67", "website": "https://techcorp.ru" }
Для извлечения структурированных данных дайте модели точную JSON-схему с типами и правилом null для отсутствующих полей — это делает вывод программно парсируемым без постобработки.
Создайте бесплатный аккаунт для решения челленджей
1 челленджей с AI-проверкой для этого урока
Этот урок — часть структурированного курса по LLM.
Мой путь обучения