
Структурированный вывод LLM удобно подключать к коду: модель возвращает поля, а приложение превращает их в объекты. Но корректный JSON в одном ответе ещё не означает, что интеграция надёжно работает. На другом входе модель может пропустить обязательное поле, выдать значение не того типа или вернуть ответ, который нельзя безопасно обработать.
Проверка устойчивости структурированного вывода LLM должна отвечать на практический вопрос: как часто модель и весь путь обработки дают пригодный результат на ваших запросах? Ниже — воспроизводимый тест для JSON Schema, повторов и обработки отказов.
Что именно считать успешным структурированным ответом
Разделите успех на уровни. Это позволит понять, где возник сбой, вместо того чтобы сводить всё к оценке «модель ответила неправильно».
Транспорт: API-запрос завершился, а ответ получен.
Формат: содержимое можно разобрать как JSON.
3. Схема: объект соответствует ожидаемой структуре — например, в нём есть обязательные поля нужных типов.
4. Смысл: значения подходят к конкретной задаче. Например, дата действительно относится к документу, а не просто имеет вид даты.
Первые три уровня можно проверять автоматизированно. Четвёртый требует собственных правил, эталонных ответов или проверки человеком. JSON Schema описывает структуру данных, но сама по себе не гарантирует фактическую правильность извлечённых сведений.
Заранее определите, какой уровень важен для вашего приложения. Для внутренней классификации ошибка в категории может быть приемлемой для последующей проверки. Для автоматической отправки платежа формально правильного JSON недостаточно: нужны отдельные бизнес-правила и контроль действий.
Опишите контракт данных до запуска теста
Возьмём узкую задачу: извлечь из обращения клиента тему, срочность и дату, если она указана. Схема может выглядеть так:
json
{
«type»: «object»,
«properties»: {
«topic»: {
«type»: «string»,
«enum»: [«оплата», «доставка», «возврат», «другое»]
},
«urgent»: {
«type»: «boolean»
},
«date»: {
«type»: [«string», «null»]
}
},
«required»: [«topic», «urgent», «date»],
«additionalProperties»: false
}
Здесь важно не только перечислить поля. `required` требует наличия каждого поля, а `additionalProperties: false` запрещает незаданные ключи. Поле `date` допускает строку или `null`, поэтому ожидание для случая без даты должно быть явно определено.
Для производственной интеграции уточните и то, что схема не выражает напрямую: допустимый формат даты, часовой пояс, связь даты с текстом обращения. Если приложению нужна дата в формате ISO 8601, проверяйте это отдельным валидатором или более строгим ограничением, поддерживаемым используемым инструментом.
Стандарты JSON Schema развиваются по версиям. Убедитесь, что валидатор, API и схема используют совместимые возможности. Некоторые API предлагают ограниченный поднабор схемы или собственный режим структурированного вывода; переносимость схемы между провайдерами не следует считать автоматической.
Соберите набор входов с ожидаемыми результатами
Тестируйте не демонстрационные примеры, а запросы, похожие на реальные. Для небольшой первой проверки достаточно набора случаев, покрывающего типичные и пограничные варианты:
- прямое обращение: «Верните деньги за заказ»;
- отсутствие даты;
- несколько дат в одном сообщении;
- неоднозначная формулировка срочности;
- опечатки, сокращения и разговорный язык;
- длинное сообщение с несколькими темами;
- пустой или почти пустой вход;
- текст, в котором нужные поля упоминаются в цитате или отрицании.
Для каждого примера запишите ожидаемую структуру и, если возможно, эталонные значения. Не подбирайте тестовые входы после просмотра ответов модели: это создаёт риск подогнать проверку под удачные случаи.
Храните набор отдельно от кода генерации и версионируйте его. При изменении промпта, схемы, модели или параметров запуска повторяйте один и тот же набор. Если запросы содержат персональные данные, используйте разрешённые для тестирования данные и не отправляйте их внешнему API без соответствующей проверки политики и настроек хранения.
Проверьте JSON, схему и смысл раздельно
Минимальная локальная проверка может использовать `jsonschema` в Python:
python
import json
from jsonschema import Draft202012Validator
schema = {
«type»: «object»,
«properties»: {
«topic»: {
«type»: «string»,
«enum»: [«оплата», «доставка», «возврат», «другое»],
},
«urgent»: {«type»: «boolean»},
«date»: {«type»: [«string», «null»]},
},
«required»: [«topic», «urgent», «date»],
«additionalProperties»: False,
}
validator = Draft202012Validator(schema)
def check_response(text):
try:
value = json.loads(text)
except json.JSONDecodeError as exc:
return {«parse_ok»: False, «schema_ok»: False, «error»: str(exc)}
errors = list(validator.iter_errors(value))
return {
«parse_ok»: True,
«schema_ok»: not errors,
«errors»: [error.message for error in errors],
«value»: value,
}
Этот код различает ошибку разбора и несоответствие схеме. Затем добавьте смысловые проверки, соответствующие задаче. Например, если в тексте нет даты, проверьте, что результат содержит `null`; если дата есть — что она извлечена верно. Такие правила должны быть частью тестового набора, а не скрыты внутри общей оценки.
Если вы используете Pydantic, его JSON-валидация позволяет преобразовать и проверить данные относительно объявленной модели. Но успешная валидация Pydantic, как и проверка JSON Schema, подтверждает соответствие заданной структуре, а не истинность содержания.
Повторите запросы и измерьте долю ошибок
Один вызов на один пример не показывает вариативность. Выполните каждый тестовый запрос несколько раз с теми же настройками. Число повторов выбирайте с учётом цены и задержки: несколько запусков годятся для предварительного сравнения, но не дают точной оценки редких ошибок. Для критичного сценария понадобятся больше повторов и отдельные испытания на большем наборе входов.
Считайте метрики по уровням:
- доля ответов, которые удалось получить;
- доля корректного JSON среди полученных ответов;
- доля объектов, прошедших схему;
- доля правильных значений по смысловым эталонам;
- частота отказа или усечения, если API возвращает соответствующий статус.
Всегда указывайте знаменатель. Например, «схему прошли 95 из 100 ответов» отличается от «схему прошли 95% всех запросов», если часть вызовов завершилась ошибкой до получения ответа. Не объединяйте ошибки API, ошибки парсинга и неверные значения в одну цифру: у них разные способы исправления.
Сохраняйте вход, версию модели, параметры запроса, схему и идентификатор тестового запуска. Не записывайте секретные ключи и лишние персональные данные. Так можно выяснить, вызван ли регресс изменением модели, контракта данных или клиентского кода.
Сравните режимы вывода, а не только названия моделей
Если API поддерживает режим структурированного вывода, сравните его с обычной просьбой «верни JSON» только на одинаковом наборе запросов и при одинаковом контракте. Например, OpenAI документирует Structured Outputs как способ привязать ответы к заданной схеме; это не следует путать с обычным JSON mode, который нацелен прежде всего на корректность формата JSON. Детали поддержки и ограничения зависят от конкретного API и модели — сверяйтесь с актуальной документацией провайдера.
Для каждого варианта запишите:
- долю ошибок разбора и схемы;
- точность значений по эталонам;
- число отказов и неполных ответов;
- задержку и стоимость, если это важно для сервиса.
Не делайте вывод о превосходстве на основании одного удачного примера или небольшой разницы без учёта размера выборки. Если один режим формирует валидные объекты чаще, но чаще ошибается в содержании, итоговая пригодность зависит от того, что делает приложение с этими данными.
Разберите сбои, прежде чем добавлять повторы
Сначала сгруппируйте ошибки: неверный тип, пропущенное поле, лишний ключ, невалидная дата, неверная категория, отказ или транспортная ошибка. Несколько повторяющихся причин часто указывают на разные исправления:
- расширить схему или правильно описать допустимые значения;
- явно определить, что возвращать при отсутствии данных;
- разделить сложную задачу на извлечение и последующую проверку;
- добавить обработку отказов и усечённых ответов;
- уточнить, какие утверждения должны опираться только на входной текст.
Повторный запрос может помочь при временном сбое API, но не исправляет неверный контракт и не гарантирует правильного значения. Если приложение повторяет запрос после ошибки, ограничьте число попыток и фиксируйте причину; иначе сбой может незаметно превратиться в рост задержки и расходов.
Также не пытайтесь автоматически «починить» любой ответ регулярным выражением и сразу передать его дальше. Такая очистка способна скрыть систематическое нарушение формата. Если восстановление необходимо, валидируйте результат после преобразования и учитывайте его как отдельный путь обработки.
Перед релизом закрепите повторяемый тест
Чтобы тест оставался полезным, храните вместе версию схемы, тестовые входы, ожидаемые значения и параметры вызова. Запускайте его при смене модели, SDK, промпта или валидатора, а в CI устанавливайте пороги отдельно для синтаксиса, схемы и качества полей. Порог выбирайте по риску приложения, а не по удобству получения зелёного статуса.
Перед подключением проверьте четыре вещи: поддерживает ли выбранный API нужные ограничения схемы; как он обозначает отказ и незавершённый ответ; соответствует ли валидатор версии JSON Schema; покрывают ли примеры реальные неоднозначные входы. Именно эти ограничения, а не один успешный JSON, покажут, можно ли доверять структурированному выводу в конкретном рабочем процессе.









