AI Engineering - обзор книги

AI Engineering - обзор книги

Evgenii Nikitin

Сколько копий сломано вокруг определения термина AI... В этой книге Чип Хуен делает ход конём - оказывается, AI engineering - это только про большие генеративные модели. Да и вообще это книга про LLM, хотя в паре месте и упоминаются мультимодальные и картиночные модели.

Впрочем, бог с ним, с названием, как сама книжка? В целом - скорее, понравилась. Фактически это очередная попытка написать большой справочник по миру LLM-систем в проде, ближе всего к этой книге по духу LLMs in Production, про которую я уже кратко писал. Если вы уже работаете с LLM-системами, целиком читать особого смысла нет. Можно выбрать интересные главы или даже части глав и читать только их.

Сначала хотел подробно написать про содержание книги, но там всё понятно из, собственно, содержания. Поэтому вместо этого расскажу про какие-то запомнившиеся мне особенности, мысли или фрагменты книги. От себя добавлю кое-какие ссылки на инструменты и примеры.

Сильной стороной книжки является довольно широкое описание разных подходов к одной и той же проблеме. Допустим, вы хотите, чтоб модель отдавала вам ответ в каком-то заданном структурированном форматие - JSON, XML, HTML и так далее. К этой проблеме есть много потенциальных ключиков, каждый со своими плюсами и минусами, про которые тоже обычно написано:

  • Затюнить промпт и навалить в него примеров формата
  • Сделать постпроцессинг - например, через либу json-repair
  • Сделать валидацию ответа - руками или через либу типа Instructor и добавить ретраи
  • Сделать ограниченный сэмплинг - занулять вероятности токенов, которые противоречат ожидаемому формату ответа
  • Зафайнтюнить модель - может хватить даже 100-200 примеров

Всё - эксперимент

Одна из ключевых мыслей книги - всё должно расцениваться как эксперимент. Любое изменение в идеале должно тригерить пайплайн оценки. Например, пересчитываем метрики, если:

  • Поменяли промпт (даже на один символ)
  • Поменяли настройки модели - температуру, top-p, top-k, repetition penalty
  • Поменяли логику пайплайна - например, заменили реранкер-модель на реранкинг через LLM
  • Поменяли саму LLM

Такой подход называется evaluation-based development. В идеале оценка должна производиться автоматически. Самый популярный подход сейчас - это LLM-as-a-Judge. Стандартная практика - описываем критерии оценки в промпте и просим модель оценить ответ бинарно или по шкале, но есть и более хитрые подходы, которые позволяют оценивать, насколько корректны факты в ответе модели:

  • Само-верификация. Просим модель сгенерить ответ на один и тот же вопрос несколько раз, и проверяем консистентность ответов.
  • Разбиваем ответ на несколько независимых компонентов, и используем API поиска для получения фактической информации

Вообще помимо "правильности" ответа в разных задачах могут быть важны самые разные критерии оценки модели:

  • Локальная консистентность - противоречит ли ответ модели предоставленному контексту
  • Глобальная консистентность - противоречит ли ответ модели общеизвестным фактам
  • Безопасность ответа - мат, насилие, секс, расизм, сексизм и так далее
  • Следование инструкциям - отвечает ли модель в нужном формате
  • Ролеплей - следует ли модели заданной роли
  • Цена и скорость

Поскольку изменение промпта может вести к самым неожиданным последствиям, их обязательно надо версионировать, а ещё лучше - вместе с мета-данными (когда изменили, почему, кто).

Лучше всего, конечно же, со временем собрать свой датасет (можно начать и с 20-30 примеров), но можно и поискать релевантные задачи в проектах типа LM Evaluation Harness.

Фейлы агентов

Глава про RAG и агентов довольно объёмная, но, наверное, самая интересная часть про потенциальные фейлы агентов. Если коротко, то они могут зафейлиться тысячей разных способов (это правда, испытано на практике):

  • Выбран неправильный инструмент под задачу - например, поиск по БД вместо поиска по документации
  • Выбран правильный инструмент, но он вызван с неверным списком параметров - например, поиск по БД вызван без названия базы данных
  • Выбран правильный инструмент с правильным списком параметров, но неверными значениями - например, поиск по документации вызван с фильтром по источникам, но выбраны несуществующие источники
  • Всё выбрано правильно, но цель не достигнута, и агент это признал
  • Всё выбрано правильно, цели не достигнута, но агент утверждает, что всё окей
  • Всё выбрано правильно, цель достигнута, но это всё заняло час, и пользователь уже закрыл нафиг вашего агента
  • Ошибка в работе самого инструмента - например, поиск по БД отвалился по таймауту или сгенерили валидный, но неправильный SQL-запрос

В анализе фейлов не обойтись без какого-нибудь средства мониторинга. Например, мы используем Langfuse.

Суперион - трансформеров из трансформеров

Узнал я и что-то совсем для себя новенькое. Несколько лет назад я читал статью Model soups про усреднение весов разных моделей. Оказывается, такая штука довольно активно применяется в LLM-мире. К примеру, мы можем обучить несколько моделей или адаптеров под разные задачи, а потом смёрджить их в единую модель. Основные подходы:

  • Суммация - соединяем веса линейной комбинацией или методом SLERP
  • Стакинг слоёв - собираем из маленьких моделей большого франкенштейна
  • Конкатенация - используется реже, так как не предоставляет особых преимуществ по сравнению с раздельным использованием моделей в плане памяти или скорости

Синтетика или натуральный продукт

Три кита любых наборов данных - качество, разнообразие и количество. Оказывается, синтетические данные могут помочь с каждым из этих критериев:

  • Количество - почти всегда автоматическая генерация данных дешевле, чем человеческая
  • Разнообразие - можно создать пайплайн генерации данных, который будет покрывать самые разные темы и сценарии (хороший пример) или добавит именно тех данных, которых у нас мало
  • Качество - в некоторых случаях ИИ-данные лучше, чем человеческие, по крайней мере, если не задействовать дорогих экспертов

Генерировать данные можно не только с помощью LLM:

  • Генерация по правилам - берём шаблон и подставляем разные значения
  • Аугментация - замена с помощью синонимов
  • Симуляция - например, игровые данные

Оптимизируем инференс с умом

Оптимизировать инференс можно на трёх уровнях.

На уровне моделей самыми популярными методами являются квантизация и дистилляция. Но есть ещё группа интересных методов, связанных с главным ограничением LLM - авторегрессивный декодинг, а иначе говоря, а ничё тот факт, что мы генерируем по токену за раз.

  • Спекулятивный декодинг - достаточно популярный метод, даже имплементирован в vLLM. Используем более быструю модель, чтоб предсказывать следующие n токенов, а потом в параллель проверяем основной моделью все подпоследовательности. Берём самую большую верно сгенерированную подпоследовательность.
  • Инференс с референсом. Часто модели требуется процитировать документ из контекста или заменить в исходном промпте небольшой кусочек. Мы можем сильно сократить время, если будем брать эти кусочки напрямую, а не генерировать их "из памяти". Вот статья для более подробного изучения. Иногда мы хотим процитировать ответ какого-то инструмента - например, вместе с ответом вывести SQL-запрос или код, который сгенерировал предыдущий шаг. Тогда тоже лучше добавить его в стрим руками, а не просить модель скопировать его из инпута.
  • Параллельный декодинг. Самая эзотерическая техника - сразу обучаем модель предсказывать несколько токенов, например, с помощью отдельных голов. Довольно сильно усложняет логику работы модели.

Многие фишки, связанные с ускорением реализованы из коробки в инференс-фреймворках - том же vLLM или Dynamo AI от NVIDIA.

Архитектура LLM-системы и фидбек от юзеров

Финальная глава посвящена постепенному усложнению LLM-системы. Итоговый вариант выглядит как-то так:

Из интересных паттернов можно отметить:

  • Роутинг - выбираем, в какую модель, а, может быть, и вообще не модель отправить пользователя. Для этого обычно используется intent classifier, который определяет чего хочет пользователь.
  • Гейтвей - специальный компонент, который помогает использовать разные модели, как локальные, так и облачные через единый интерфейс - к примеру, litellm.
  • Кэширование - точное (если запрос пользователя полностью совпадает с более ранним, то можем сразу отдать ответ) и семантическое (значительно сложнее реализовать хорошо)
  • Input/output guardrails - проверки запросов пользователей и ответов LLM на соответствие нашим критериям качества и безопасности. Много готовых валидаторов есть в проекте Guardrails AI.

Одним из самых важных компонентов LLM-системы является сбор пользовательского фидбека. Собирать лучше всё, что можно, заранее не предсказать, что будет полезно, а что нет:

  • Как часто пользователи стопают генерацию
  • Длина чата - как по токенам, так и по количеству раундов реплик
  • Все инпуты и аутпуты модели вместе с параметрами запросов
  • Динамика распределения длин инпутов и аутпутов, а также распределений токенов - меняется ли поведение пользователей или модели?
  • Метрики скорости - time-to-first-token, time-per-output-token, total latency

Report Page