Large Language Model Programs
Imanol Schlag, Sainbayar Sukhbaatar, Asli Celikyilmaz, Wen-tau Yih, Jason Weston, Jürgen Schmidhuber, Xian Li
Статья: https://arxiv.org/abs/2305.05364
Любопытная работа, я её прочитал из-за авторства Sainbayar Sukhbaatar, но тут и Шмидхубер в соавторах.
LLM-ки вовсю входят в нашу жизнь и затачиваются на разные задачи. Традиционно есть два больших направления кастомизации LLM, каждое со своими плюсами и минусами.
Во-первых, файнтюнинг (или дообучение) предобученной базовой модели. Требует заметных вычислительных ресурсов (но много меньших, чем для предобучения), сбора данных в каком-то вменяемом количестве (скорее от тысяч и выше), ну и какой-то инфраструктуры, чтобы этим заниматься и потом хостить файнтюненные модели. При этом для сложных алгоритмических задач нетривиально добиться выучивания алгоритма моделью.
Есть другой подход, всеми любимый in-context learning, вотчина промпт-инженеров, когда результата добиваются составлением правильного промпта с примерами решения задачи, сопутствующими техниками типа Chain-of-Thought (CoT) и т.д. Здесь свои сложности, главная из которых это ограниченный размер текста, который можно подать в модель -- и тут есть тренд на увеличение контекста, вспомним тот же недавний Unlimiformer (https://hottg.com/gonzo_ML/1507) или вот свежий анонс от Anthropic про новую версию Claude с контекстом в 100k (https://www.anthropic.com/index/100k-context-windows). Да и у того же GPT-4 (https://hottg.com/gonzo_ML/1383) где-то до сих пор висит в загашнике модель с контекстом в 32k. Есть и более тонкие сложности, например, в том, что в сложном многоходовом промпте шаги могут интерферировать между собой и модель может отвлекаться на то, на что в моменте отвлекаться не надо.
Авторы предлагают альтернативный путь под названием LLM Programs, который можно рассматривать как развитие in-context learning. Здесь LLM встраивается в программу (на обычном языке программирования, например, на питоне) и хранением состояния и ведением модели по шагам занимается этот внешний для модели код. Плюсы в том, что языки программирования для этого приспособлены замечательно, и если мы уже структурировали последовательность шагов решения задачи (что нам обычно нужно сделать и в случае промпт-инжиниринга, да и для файнтюнинга часто надо достаточно хорошо понять задачу, чтобы нагенерить примеров), то задать их внешним кодом может быть и проще. Как бонус, растёт размер доступного контекста и шаги не интерферируют между собой, потому что теперь контекст не забивается данными, не относящимися к другим шагам алгоритма. На каждом шаге промпт строго специфичный для этого шага.
Ключ для решения задачи через LLM Program -- это способность декомпозировать решение задачи в последовательность более простых шагов (и очевидно не со всеми задачами такое легко сделать). Выход каждого шага надо парсить, собирать важные части состояния программы в этом высокоуровневом коде, генерить новые промпты для новых шагов. Этот подход отличается от предыдущих работ, где модель использовала внешние тулы, типа калькуляторов или интерпретаторов кода (например, Toolformer, https://hottg.com/gonzo_ML/1305, но не только, LaMDA, например, тоже это умела, https://hottg.com/gonzo_ML/1229). Там за поддержание состояния отвечала LLM, а здесь наоборот.
Чем такой подход хорош? Ну, во-первых, не требуется (или требуется мало) файнтюнинг. Во-вторых, можно таким образом описать достаточно сложную и развесистую задачу, которую описать промптом или обучить может быть весьма непросто. Попутно появляются более точные спецификации входных и выходных данных для разных шагов программы, с этим проще и тестировать, и отлаживаться, и оценивать качество. Интерпретируемость тоже выше. И защиты разные проще ставить. Ну и интерференции между шагами нет, LLM работать проще, промпт инженеру работать проще.
Дальше в работе разбирают пример создания вопросно-ответной системы на базе LLM. Таких систем сейчас уже миллион (и много было до LLM). Как сейчас решается задача ответов на вопросы, например, по корпоративному сайту?
>>Click here to continue<<