В последнее время я много работаю с проектами вокруг ИИ. Одной из важных задач в рамках реализации ИИ-проектов является интеграция с LLM. При работе с LLM, естественно, приходится учитывать особенности данной технологии, одной из которых является то, что модель выдает непредсказуемый текстовый ответ, который сложно поместить в надёжный пайплайн. И для того чтобы обуздать произвольный характер ответа LLM, подойдет решение под названием Structured Output. Это подход, который заставляет модель отвечать строго по заданной схеме, превращая «рандомайзер» в предсказуемый API. Ниже зафиксирую краткий гайд по четырём способам реализации Structured Output, от простых до более продвинутых.
Еще раз, Structured Output — это подход, который объявляет для LLM строгий контракт ответа, например: в формате предварительно заданной JSON-схемы. В результате чего мы получаем фиксированный структурированный формат ответа, на базе которого можем спокойно строить привычные пайплайны с дальнейшими манипуляциями над данными, как в случае при работе с традиционным REST API.
#1. Первым, так называемым, базовым способом "в лоб" будет объявление структуры в промте + реализация стратегии ретраев при валидации ответа LLM: если ответ LLM не будет соответствовать заданной "маске", то мы будем делать повторный запрос на повторную генерацию. Готовую реализацию данного подхода можно найти в таких библиотеках, как https://github.com/567-labs/instructor/tree/main.
#2. Второй способ это использование https://docs.boundaryml.com/. По своей сути это развитие первого подхода с важным дополнением в виде Schema-Aligned Parsing (SAP). SAP — это «мягкий» парсер, который исправляет типовые ошибки в заданном формате схемы ответа, например в JSON это могут быть забытые скобки и запятые, неверное экранирование, лишний текст до/после JSON.
#3. Третьим рассмотрим уже не просто способ по обработке ответа LLM, а то, как не только через промпт влиять на сам процесс генерации. Constrained Decoding — это способ про то, как не просить модель ответить правильно, а не дать ей ответить неправильно. Работает это следующим образом: LLM генерирует ответ токен за токеном, но на каждом шаге библиотека (например, https://github.com/dottxt-ai/outlines) "обнуляет вероятность" всем остальным токенам, которые нарушили бы генерацию заданной схемы на текущем шаге, на каждом шаге модель может выбрать только допустимый вариант токена (символа).
#4. И в заключении отмечу https://abdullin.com/schema-guided-reasoning/. Суть этого способа заключается в том, чтобы объединить силу Chain-of-Thought и структурированного вывода, тем самым заставить модель рассуждать внутри заранее заданной схемы. Как это выглядит: допустим, вы проектируете JSON-схему, которая отражает экспертный чеклист или логику решения задачи. Далее модель вынуждена заполнять поля последовательно, что в свою очередь гарантирует прохождение всех шагов рассуждения и позволяет валидировать промежуточные результаты.
#AI #LLM