В конвейере автоматизации ответ модели — не текст для человека, а данные для следующего шага. Значит он должен приходить в форме, которую программа разберёт без гадания: поля, типы, допустимые значения.
Просьба «ответь в формате JSON» эту задачу не решает. Модель обычно послушается — а иногда добавит пояснение перед ответом, обернёт его в разметку, поставит запятую не там или выдаст поле, которого не просили. В конвейере, обрабатывающем тысячи операций, «обычно» означает регулярные сбои.
Правильный подход: не просить, а ограничивать. Это базовое требование к любому конвейеру автоматизации процессов: обмен между шагами должен быть предсказуемым.
Три уровня надёжности
Просьба в промпте
«Верни ответ в виде JSON с полями name, date, amount».
Работает в большинстве случаев, ломается в остальных. Годится для прототипа, не годится для эксплуатации.
Схема, передаваемая модели
Формат описывается явной схемой, которая передаётся вместе с запросом. Современные модели поддерживают такой режим и следуют схеме заметно надёжнее, чем текстовой просьбе.
Основной рабочий вариант.
Ограниченная генерация
Модель физически не может выдать ответ, не соответствующий схеме: недопустимые варианты отсекаются в процессе. Доступно при локальном развёртывании и в части интерфейсов.
Самый надёжный вариант. Формат перестаёт быть вероятностным.
Разумный выбор: схема как основной механизм плюс проверка результата кодом. Проверка нужна в любом случае — даже строгое соответствие формату не гарантирует осмысленности содержимого.
Как описывать схему
Явные типы. Число — числом, а не строкой. Дата — в одном формате, указанном в описании поля.
Перечисления вместо свободного текста. Категория выбирается из списка допустимых значений. Это снимает целый класс проблем: модель не придумает новую категорию, и не придётся сопоставлять «доставка», «Доставка» и «проблемы с доставкой».
Обязательность каждого поля. Что должно быть всегда, что может отсутствовать.
Явное значение для «нет в документе». Критично. Если такого значения не предусмотрено, модель заполнит поле правдоподобным вымыслом — это её поведение при нехватке данных.
Ограничения на значения. Диапазоны для чисел, формат для строк, максимальная длина.
Описания полей. Не «amount», а «итоговая сумма документа с НДС, в рублях». Описание влияет на качество заметнее, чем формулировки в промпте.
Что положить в схему помимо данных
Три поля, которые окупаются многократно.
Подтверждение из источника. Фрагмент текста, откуда взято значение. Код проверяет, что фрагмент действительно есть в исходнике. Ловит выдуманные значения — приём тот же, что в цитировании источников.
Признак неуверенности. Не оценка в процентах — она систематически завышена, — а явный флаг «значение неоднозначно» с пояснением. По нему операция уходит на проверку человеком.
Причина отказа. Если модель не смогла разобрать вход, она должна сказать об этом в структурированном виде, а не вернуть пустые поля.
Последнее меняет поведение системы качественно: пустое поле и «поле отсутствует, потому что документ не содержит раздела с реквизитами» — разные ситуации, и обрабатывать их надо по-разному.
Разбор: отказ от свободного текста
Задача. Разбор заявок из писем. Модель возвращала описание заявки текстом, дальше конвейер пытался достать из него данные.
Что ломалось. Формулировки менялись от письма к письму. Разбор текста регулярными выражениями работал в большинстве случаев и падал в остальных — причём падал молча: не находил нужное и подставлял пустое значение.
Отдельная проблема — категории. Модель писала «доставка», «проблема с доставкой», «вопрос по срокам доставки» — с точки зрения кода три разные категории.
Что сделали.
Описали схему: тип заявки из перечисления, срочность из перечисления, контакты, номер заказа с указанием формата, суть в свободном виде, флаг неуверенности, фрагмент-подтверждение для номера заказа.
Перешли на передачу схемы модели вместо просьбы в промпте.
Добавили проверку результата: соответствие типам, наличие обязательных полей, формат номера заказа, наличие фрагмента-подтверждения в тексте письма.
При несоответствии — один повтор с указанием, что именно не так; при повторной неудаче — в очередь разбора, «Обработка ошибок».
Что изменилось.
Разнобой в категориях исчез: перечисление физически не позволяет вернуть значение вне списка.
Молчаливые пропуски прекратились: обязательные поля проверяются, отсутствие обнаруживается сразу.
Появилась работа с неуверенностью, которой раньше не было вовсе — модель сообщала о неоднозначности вместо того, чтобы выбирать наугад.
Выдуманные номера заказов перестали проходить: фрагмент-подтверждение либо есть в письме, либо нет.
Неожиданный побочный эффект. Расход на обращение немного снизился. Раньше модель писала развёрнутое описание, теперь возвращает поля — текста на выходе меньше.
Вывод. Свободный текст на выходе модели уместен, когда результат читает человек. Если результат читает программа, формат должен быть задан схемой, а не надеждой.
Что проверять после получения ответа
Даже при строгом формате:
- соответствие схеме — типы, обязательные поля, допустимые значения;
- осмысленность значений — дата не из будущего, сумма не отрицательная, диапазоны;
- контрольные суммы — ИНН, счета: «Извлечение данных из документов»;
- наличие подтверждения в источнике;
- согласованность полей — итог равен сумме позиций, дата акта не раньше даты договора.
Строгий формат гарантирует форму, но не содержание. Проверки нужны обе.
Частые вопросы
Как заставить модель отвечать в строгом формате?
Передавать схему вместе с запросом, а не просить об этом в промпте: современные модели следуют схеме заметно надёжнее. При локальном развёртывании доступна ограниченная генерация, где модель физически не может выдать ответ вне схемы. В любом случае результат проверяется кодом.
Почему просьбы «ответь в формате JSON» недостаточно?
Потому что она соблюдается обычно, но не всегда: модель может добавить пояснение перед ответом, обернуть его в разметку или вернуть лишнее поле. В конвейере на тысячи операций это означает регулярные сбои, которые к тому же трудно воспроизвести.
Что делать, если нужного значения нет во входных данных?
Предусмотреть в схеме явное значение «отсутствует». Если такой возможности нет, модель заполнит поле правдоподобным вымыслом — это её обычное поведение при нехватке данных. Отдельно полезно поле с причиной, по которой значение не найдено.
Как отличить надёжный результат от сомнительного?
Просить возвращать фрагмент источника, из которого взято значение, и программно проверять, что он есть во входных данных. Плюс явный флаг неуверенности с пояснением. Числовая оценка уверенности от модели ненадёжна — она систематически завышена.
Нужны ли проверки, если формат задан схемой?
Да. Схема гарантирует форму ответа, но не осмысленность содержимого: дата может быть из будущего, сумма отрицательной, ИНН не проходить контрольную сумму. Форму проверяет схема, содержание — код.
Что делать, если ответ не соответствует схеме?
Повторить запрос, указав, что именно не так, — обычно этого достаточно. При повторной неудаче отправлять операцию в очередь разбора, а не пытаться разобрать что получилось. Число повторов должно быть ограничено.
Что дальше
Как использовать структурированный вывод для извлечения полей — «Извлечение данных из документов», для разбора обращений — «Классификация обращений». Что делать с неуверенными результатами — «Человек в контуре проверки». Как описываются вызовы инструментов у агентов — «Function calling».
Проектирование конвейеров с предсказуемым обменом данными — часть работы по автоматизации процессов.