Структурированные выходные данные: получение надежного JSON из языковой модели
Первая версия каждой интеграции LLM анализирует текст. Вы запрашиваете «три основных риска, по одному на строку», разделяете их на новую строку, и это работает до того дня, пока модель сначала не напишет вводное предложение. Для завершения этого цикла существуют структурированные выходные данные: вы передаете модели схему JSON, декодер ограничен, поэтому он не может выдавать ничего, что нарушает его, и вы получаете обратно полезную нагрузку с запрошенными вами полями. Эта гарантия реальна, но она уже, чем кажется, и разница в том, где живут ошибки.
На что на самом деле распространяется гарантия
Ограниченные гарантии декодирования форма. Ответ будет проанализирован как JSON, у него будут ваши ключи, типы будут совпадать, а поля перечисления будут содержать одно из перечисленных вами значений. Это значительное улучшение по сравнению с методом «подсказка и надежда».
Это ничего не гарантирует содержание. Поле, напечатанное как строка, будет содержать строку; то, является ли эта строка точной или придумана для удовлетворения схемы, не изменилась по сравнению с предыдущим. На самом деле строгая схема делает изобретение несколько более вероятным, потому что обязательное поле должно быть чем-то заполнено, а в модели нет возможности сказать «нет в источнике». Это самый распространенный сбой в производстве: обязательный invoice_number в документе, которого нет.
Дизайн вокруг этого. Разрешить значение null там, где его отсутствие возможно, добавьте явное found: boolean или "unknown" член перечисления и никогда не делайте поле обязательным, если ответ действительно не существует в каждом вводе.
Разработка схемы, которую может заполнить модель
Схемы, написанные для проверки, и схемы, написанные для генерации, выглядят по-разному. Несколько правил, которые действуют для всех поставщиков:
- Плоские биты вложенные. На каждом уровне вложенности модель может потерять отслеживание. Три неглубоких объекта, извлеченных за три захода, побеждают одно глубоко вложенное дерево.
- Перечисления превосходят свободные строки. Если поле имеет пять допустимых значений, перечислите их. Вы удаляете целый класс кода нормализации, и ограниченный декодер применяет его за вас.
- Имена полей являются инструкциями.
due_date_iso8601производит лучший результат, чемdateс форматом, описанным в отдельной подсказке. Имена указаны в контексте; используйте их. - Использовать
descriptionна полях. Большинство поставщиков передают в модель описания схемы. Одно предложение на неоднозначное поле обходится дешевле и надежнее, чем параграф прозаических инструкций выше. - Набор
additionalProperties: false. В любом случае некоторые провайдеры требуют его для строгого режима, и это мешает модели изобретать дополнительный ключ, который ваш парсер молча игнорирует. - Предпочитайте массивы плоских объектов картам. Динамические ключи — объект, имена свойств которого заранее неизвестны — плохо поддерживаются строгими режимами и их неудобно вводить на принимающей стороне.
Поставщики также ограничивают ключевые слова схемы JSON, которые они поддерживают в строгом режиме: oneOf, ограничения шаблона, числовые границы и рекурсия обычно ограничиваются или игнорируются. Предположим, что схема ограничивает только структуру, и самостоятельно применяйте бизнес-правила после анализа.
Все равно подтвердить
Даже в строгом режиме проверяйте каждый ответ, прежде чем он попадет в вашу базу данных. Строгий режим может быть отключен при изменении конфигурации, резервный путь может попасть в модель, которая его не поддерживает, повторная попытка сети может вернуть объект ошибки, а ответ может быть усечен промежуточным объектом ограничения токена, что создает недопустимый JSON, режим схемы не предотвращает.
Когда полезная нагрузка все же выходит из строя, возникает полезный вопрос: какое поле и почему. Валидатор схемы JSON берет документ и схему и сообщает по одной строке для каждой проблемы с указанием пути указателя JSON, ключевого слова, которое не удалось, и фактически найденного значения. Это именно та форма, которая вам нужна для двух целей: исправление схемы во время разработки и возврат к повторной попытке — отчет о неудачной проверке, вставленный в последующее сообщение, является чрезвычайно эффективной подсказкой о ремонте, поскольку модель может точно увидеть, в чем была ошибка.
Ограничьте количество повторов одной или двумя. Модель, которая дважды терпит неудачу в схеме, обычно запрашивает что-то, чего нет на входе, и третья попытка изобретает это.
От примера полезной нагрузки к коду
Большинство схем начинают свою жизнь с образца ответа, который кто-то вставил в чат. Преобразование этого в типизированный, проверенный код вручную утомительно и чревато ошибками, поэтому не делайте этого.
Вставьте образец в JSON в схему Zod и вы получаете схему Zod плюс предполагаемый тип TypeScript. Он делает выводы для каждого поля, а не вводит все в виде строки: значения, которые выглядят как электронные письма, URL-адреса, UUID или даты ISO, получаются .email(), .url(), .uuid() и .datetime() вместо голого z.string(), массивы сохраняют свой тип элемента, а поле, тип которого варьируется в зависимости от вхождения, становится объединением, а не автоматически выбирает первое увиденное. Это последнее поведение стоит использовать сознательно: вставьте три или четыре реальных ответа, объединенных, а не один, чтобы необязательные и полиморфные поля отображались как объединения, а не были привязаны к тому, что содержал первый образец.
Если вам нужны только типы, а не проверка во время выполнения, поскольку полезная нагрузка поступает из источника, которому вы уже доверяете, — JSON в TypeScript создает интерфейсы напрямую, при этом вложенные объекты разбиваются на именованные подинтерфейсы, а не на встроенные анонимные объекты.
Сохраняйте истину прямо: одно определение схемы, а все остальное генерируется из него. Схема Zod и схема JSON, поддерживаемые отдельно, разойдутся между собой в течение месяца, и это разногласие проявится как ошибка производственного анализа, а не как провал теста.
Чтение того, что вернулось
Ответы моделей поступают в уменьшенном виде в одной строке, что затрудняет их просмотр. Форматер JSON отступы и сортируют их во что-то читаемое, а его проверка немедленно улавливает случай усечения — полезная нагрузка, заканчивающаяся в середине строки, является сигнатурой предела токена попадания, а исправлением является более высокий предел вывода или меньшая схема, а не быстрое изменение.
Когда вы сравниваете то, что две модели выдали из одних и тех же входных данных, или проверяете, изменило ли быстрое изменение выходные данные непреднамеренным образом, дифференцируйте отформатированные полезные данные, а не считывайте оба. Структурные различия, невидимые в стене JSON — поле, которое незаметно превратилось в строку цифр вместо числа, — сразу бросаются в глаза в диффе.
Управление версиями
Схемы меняются, и вместе с ними изменяются выходные данные модели. Добавьте поле версии в полезные данные с первого дня, чтобы сохраненные записи имели ту форму, в которой они были записаны. Ретрофит, когда у вас есть миллион строк непомеченного JSON, — это тот вид миграции, на который никто не планирует времени.
Все эти инструменты запускаются локально в вашем браузере, что имеет большее значение для этого рабочего процесса, чем обычно: образцы полезных данных, которые вы превращаете в схемы, обычно представляют собой реальные ответы API с реальными данными клиентов в них, и их не следует загружать в службу форматирования для предварительного оформления.
Создатель TextArray — создания бесплатных инструментов, обеспечивающих конфиденциальность, которые полностью работают в вашем браузере.