В последнее время большие языковые модели (Large Language Models, LLM) стали невероятно популярными — кажется, их обсуждают везде, от школьных коридоров до Сената США. Сфера LLM растёт бурными темпами, привлекая внимание не только специалистов в области машинного обучения, но и обычных пользователей. Кто-то высказывает массу опасений насчет их дальнейшего развития, а кто-то и вовсе предлагает бомбить дата-центры — и даже в Белом Доме обсуждают будущее моделей. Но неужели текстом можно кому-то навредить? А что если такая модель приобрела бы агентность, смогла создать себе физическую оболочку и полностью ей управлять? Ну, это какая-то фантастика из (не)далёкого будущего, а про агентов нашего времени я расскажу в этой статье. И не переживайте — знание машинного обучения вам не понадобится!
На тему больших языковых моделей написано множество статей для разного уровня читающих. Если хотите на пальцах понять принцип работы GPT-like моделей, не имея технический бекграунд, рекомендую почитать обзор Игоря Котенкова “Как работает ChatGPT: объясняем на простом русском эволюцию языковых моделей с T9 до чуда”. Сегодняшний пост посвящен одному из интересных применений LLM — автономным агентам. Andrej Karpathy, бывший AI Director в Tesla, а теперь инженер в OpenAI (который по статусу в твиттере работает над something like Jarvis) сравнил LLM с первыми компьютерами, которые изначально использовались как калькуляторы. Только спустя какое-то время мы по-настоящему раскрыли их потенциал, построив вокруг этого операционные системы, множество приложений и обширную инфраструктуру. Автономные агенты на базе LLM могут стать аналогичным прорывом в мире языковых моделей. На сегодняшний день уже наблюдается активное развитие этой области, что подтверждается многочисленными исследованиями, публикациями, фреймворками и проектами ведущих компаний. Примером может быть GitHub CoPilot: представьте, если бы в гитхабе можно было открыть Issue, заполнить несколько полей, а далее бот сам напишет план, реализует код и откроет PR. Сколько багов мы получим времени можно будет сэкономить!
Этот обзор основан на обширном анализе статей и публикаций и представляет собой краткое изложение ключевой информации по теме. Для тех, кто хочет углубиться, в конце текста вы найдёте список литературы. Также присоединяйтесь к моему телеграм каналу AI[ex]Time, где я пишу про машинное обучение, NLP, LLM и в том числе про агентов. Отдельное спасибо Саше Абрамову (a.k.a DealerAI) и Игорю Котенкову из Сиолошной за ревью и обратную связь по данной статье.
Итак, начнем с базовых определений:
Определений агентов множество, но выделяя главное, можно сказать, что агенты — это системы, взаимодействующие с динамической средой, которые воспринимают ее и действуют, выполняя заложенные в них цели или задачи. Под LLM же в данном контексте будем понимать достаточно большие модели, которые по входному тексту, могут предсказать вероятный следующий токен (где токен – это слово или его часть).
Что же мы подразумеваем, говоря об агентах, основанных на LLM? В контексте сильного прогресса нейросетей и с появлением у моделей способности решать по-настоящему нетривиальные задачи, LLM может стать мозгом агента, а средой, в которой он функционирует, будет наш мир. Для этого система должна обладать следующими возможностями:
В некоторых сценариях уметь отыгрывать определенную роль. Роль возникает из того факта, что она улучшает перформанс и задает некоторые рамки поведения агента. Например, указание в промпте (т.е. текстовом запросе), что модель является "разработчиком на python" может улучшить качество кода (Profile).
Воспринимать поступающую информацию из различных источников. Это могут быть сенсоры, текст, изображения с камер, что угодно. Зачастую для полноценного выполнения задач агент должен уметь обрабатывать несколько модальностей (Perception).
Планировать, разбивая сложные задачи на серию более простых шагов. Например, формирование маршрута по Парижу с учетом лучших мест для проживания и мест, которые стоит посетить (Planning).
Использовать инструменты доступные в среде. Например, мы можем дать агенту возможность поиска в интернете, исполнять код, вызывать по API какие-то функции, другие модели и так далее. Как человек научился пользоваться инструментами и делегировать им задачи, так и к LLM можно подключить интернет, интерпретатор и прочее. Именно так нейронка и может влиять на реальный мир (Actions).
Рефлексировать на основе обратной связи из среды, информации об ошибках и корректировать свое планирование, исходя из данной информации (Reasoning).
Иметь краткосрочную и долгосрочную память для поддержания диалога или извлечения релевантной информации для дальнейших действий (Memory).
Далее мы поговорим про каждое направление и посмотрим на примере нескольких работ, какие прорывы случились за последний год.
На самом деле агенты, работающие только с текстом, уже могут выполнять разнообразные и серьезные задачи, просто получая информацию о состоянии среды в текстовом формате. Однако, их способности значительно расширяются, если добавить возможность обрабатывать и другие модальности, такие как аудио и изображения. Для этого необходимо не просто переводить каждую из сущностей в вектор (или последовательность векторов), но делать это так, чтобы векторы этих модальностей были в одном и том же скрытом пространстве.
Что значит в одном и том же скрытом пространстве?Модели оперируют векторами, это их язык. Но векторы могут быть разные, например, [0.1, -0.1] и [100, 101, 102, 103]. Не все из них "имеют смысл" для нашей итоговой модели. Чтобы достичь мультимодальности, мы учимся переводить звук, картинки, текст как раз в единый язык, то есть в векторы определенного формата, которые "понятны" модели.
Рассмотрим, например, ситуацию, когда модель хорошо понимает текст, но изображения переводятся в числовое представление совершенно другой моделью, о которой агент ничего не знает. В таком случае информация, представленная изображением, окажется для него бесполезной. Для перевода разных форматов входных данных в единое пространство используются различные подходы. Давайте посмотрим на некоторые из примеров: модели LLaVa [1] и BLIP-2 [2], способные обрабатывать как текст, так и изображения.
В качестве LLM для генерации текстового ответа используется LLaMA, которая декодирует эмбеддинги (то же, что и векторы) картинок и входного текста в ответ. Чтобы кодировать картинку в последовательность эмбеддингов в архитектуре используется Vision Transformer (ViT-L): модель переводит одну картинку в набор патчей, то есть кусочки этой картинки, и далее обрабатывает их как последовательность. Такой подход дает нам возможность использовать силу архитектуры трансформера, а именно attention между патчами (про attention поговорим чуть позже). Однако для LLaMa эти эмбеддинги изначально не имеют смысла, они буквально написаны на другом, неродном LLM языке! Чтобы это исправить, вводится дополнительное преобразование векторов ViT (Z_v) в новые векторы H_v, которые понятны LLaMa. Это преобразование представляет из себя умножение на матрицу, и матрица обучается на отдельном этапе.
Обучение происходит посредством языкового моделирования, когда модель генерирует текст на основе изображения по заранее подготовленной разметке.
В данной архитектуре используется немного другой подход. Основным элементом является Q-former, который служит связующим звеном между визуальной и текстовой модальностями. Это достигается за счет обучаемых Query-эмбеддингов, взаимодействующих с визуальными признаками через механизм Cross-attention. В этом случае, токены запроса могут 'посмотреть' на изображение, 'усвоить' важную визуальную информацию и преобразовать ее в числовое представление, которое затем обрабатывается языковой моделью. Заметим, что здесь тоже есть отдельное преобразование в виде полносвязного слоя между Q-Former и LLM.
Вспомним, как работает классический Self-Attention в трансформерах: В нем мы оперируем одной последовательностью, и задача состоит в том, чтобы взвесить векторы токенов для получения оптимальной комбинации, учитывающей весь контекст. Для этого токены, представленные матрицей запросов (Q), сравниваются сами с собой, но в виде матрицы ключей (K). Полученные в результате этого сравнения веса используются для получения взвешенного значения токенов, представленных матрицей Value (V). Этот процесс позволяет каждому токену собирать информацию от всех остальных. Cross-Attention же работает с двумя разными последовательностями: запросы (Q) берутся из одной, а ключи (K) и значения (V) — из другой. Это позволяет одной последовательности извлекать наиболее актуальную информацию из другой.
Можно провести такую аналогию: каждый раз мы закидываем удочку со словом (Query) во все множество слов, на которое хотим посмотреть, но вытягиваем только то, что актуально в данный момент.
Основная идея, которую хочется здесь зафиксировать, заключается в том, что для обучения мультимодальных моделей нам требуется датасет вида (модальность1, модальность2) и процедура дообучения, которая показывает модели, как эти модальности соотносятся друг с другом. Далее мы можем выбирать среди множества подходов, как именно реализовать это архитектурно.
Автономные агенты часто выполняют свои задачи, принимая на себя определенные роли. Добавление небольшой фразы, чтобы модель отвечала методом Сократа, позволяет добиться общения в стиле диалога с открытыми вопросами. Роли также нужны для симуляции некоторых социологических феноменов (в тех случаях, когда нет возможности поставить эксперимент в реальной жизни, например, распространение фейковых данных в обществе). В таком случае нужно, чтобы каждый агент имел определенный характер.
Обычно это достигается путем добавления специального промпта (system prompt) в начало контекста модели. Профиль может содержать базовую информацию, такую как возраст, пол, профессия, а также более специфические аспекты, например, психологический портрет, отражающий характер пользователя. Создание таких профилей обычно не представляет сложности.
Интересной альтернативой ручному созданию профилей агентов является их автоматическая генерация с помощью другой модели/алгоритма. Примером такого подхода является работа RecAgent [3] — агент для пользовательских симуляций, например, в области рекомендаций фильмов. В статье авторы используют автоматическую генерацию профиля, предоставляя лишь базовую информацию в виде таблицы, на основании которой уже формируется более полное описание агента. Дополнительно, в таких таблицах можно отразить распределения, характерные для реального мира, например, процентное соотношение мужчин и женщин или распределение по профессиям. В таком случае мы повышаем реалистичность симуляций за счет соответствия агентских профилей данным реального мира.
LLM способны генерировать только текст, и в обычном сценарии использования это сильно ограничивает диапазон задач, которые агенты могут решить. Однако, существует элегантный способ значительно расширить возможности агентов путем добавления различных инструментов.
Action Module — это специализированный компонент, позволяющий языковой модели выполнять внешние задачи или операции, выходящие за рамки простой генерации текста. Этот модуль выступает в качестве интерфейса между языковой моделью и внешними инструментами, базами данных, API и другими ресурсами, позволяя модели выполнять действия, получать данные или взаимодействовать с другими системами. Несколько примеров:
Извлечение данных из БД для последующей аналитики.
Исполнение кода в Python или вычисления выражений в Wolfram, Latex, и тд.
Вызов других моделей, например, для генерации картинки или синтеза речи (Вот вам милый пример Spot от Boston Dynamics — собака-робот с добавленной LLM для взаимодействия с пользователем).
Вращение камеры или совершение физического действия в среде, если мы говорим про Embodied Agents.
Для реализации Action Module необходимо, чтобы модель научилась запрашивать информацию из внешних источников и чтобы отдельная программа выполняла эти запросы, обрабатывала ответ и отдавала его обратно в контекст модели. Процесс обычно выглядит примерно так:
В случае, когда модель считает, что нужно обратиться к API, она генерирует что-то вроде “<API> api_name (expression), parameters </API> (Словарь модели нужно расширить специальными токенами <API>, </API>)
Отдельная программа парсит это предложение и переводит в понятный формат, например, REST запроса.
Программа выполняет запрос к API, обрабатывает каким-то образом ответ и помещает его в контекст модели. Либо же ответ API уже используются как итоговое действие.
Модель, имея информацию от источника, продолжает генерацию ответа.
Для того, чтобы научить модель пользоваться инструментами и генерировать в случае необходимости такие запросы, неплохо работает few-shot learning, то есть предварительно в контекст модели помещаются примеры вызовов внешних инструментов, их параметры и инструкция, в каком случае их можно вызывать. Но важно отметить, что действуя таким образом, мы жертвуем размером оставшегося контекста. Также могут быть ошибки генерации конкретных параметров, из-за чего вызов инструмента может пойти не так. Чтобы бороться с такими неприятными ошибками, можно ввести специальный аннотатор, который будет анализировать генерацию модели и вызывать различные функции, заточенные под выполнение конкретных задач (например, проанализировали текст, поняли, что хотим поискать в интернете и вызвали специальную функцию составления запроса для поиска). Подробнее можно почитать в работе BlenderBot3 [4]. Идею такого аннотатора можно применять и в других модулях, например, модуле памяти, о котором мы поговорим чуть позже.
Помимо этого есть работы, которые дополнительно обучают модель пользоваться инструментами — хороший пример, Toolformer [5]. В работе авторы сгенерировали самой же моделью датасет с примерами вызовов различных API, оставили самые полезные и дополнительно обучили на них модель. Это показало значительный прирост в способности взаимодействовать с внешними инструментами. Можно сказать, что модель сама научилась использовать инструменты, предварительно сгенерировав примеры для обучения!
По похожему принципу работают и ChatGPT плагины. Основная идея заключается в том, что вызов любых внешних инструментов может быть получен через обычную генерацию текста, нужно лишь показать модели, как это делать (с помощью, например, тюнинга или примеров использования через промпт).
Хотя LLM уже вмещают обширные объемы информации в своих весах, существуют множество приложений, где отдельный модуль памяти оказывается необходимым. Например, если спросить ChatGPT о годе первого полета человека на Луну, он с легкостью даст точный ответ. Однако, возникает вопрос: как обрабатывать свежие данные и факты, которых не могло быть в обучающей выборке? Этот вопрос особенно важен в контексте 'галлюцинаций', когда модель, не имея достоверной информации, всё равно пытается сгенерировать ответ, нежели чем сказать “я не знаю”. Это является значительной проблемой для алайнмента моделей, которую здесь мы рассматривать подробно не будем.
Кроме хранения фактической информации, модуль памяти может быть использован для других различных целей: от запоминания доступных API (API-Bank) до суммаризации различных фактов в более обобщенные и абстрактные выводы.
Таким образом, модуль памяти не только хранит информацию, но и обеспечивает дополнительные возможности эффективного ее использования и обновления в соответствии с новыми данными и ситуациями, что позволяет моделям быть более адаптивными и реалистичными в своих ответах.
Проведя аналогию с человеческой памятью, можно предложить следующую реализацию компонентов модуля памяти в агентах:
Краткосрочная (Short-term). Эта память представляет собой информацию, к которой агент имеет быстрый доступ, но она является ненадежной и может быть забыта в любой момент. В роли краткосрочной памяти выступает контекст самой модели и ее способность к in-context learning (когда по инструкции и нескольким примерам модель делает то, что мы от нее хотим, без сбора тысяч примеров для дообучения). Модель имеет прямой доступ ко всему, что находится в ее контексте, благодаря механизму attention во время генерации токенов. Есть множество примеров систем, использующих контекст для доступа к определенной информации, но в качестве интересного приведу CALYPSO [6] — агент для игры в Dungeons & Dragons, который может помогать ведущему (Dungeon Master) в создании и изложении историй. Его кратковременная память построена на описаниях сцен, информации о монстрах и предыдущих кратких описаниях.
Однако, ограничение этого типа памяти заключается в ограниченном размере контекста модели, из-за чего со временем информация может быть потеряна. Более того, есть работы, показывающие, что на очень длинных контекстах велика вероятность, что модель пропустит некоторую информацию (например, из середины этого контекста), даже если необходимые факты явно содержатся внутри.
Долгосрочная (Long-term). Это данные, хранящиеся в БД, которые могут извлекаться агентом по запросу. Этот вид памяти обеспечивает более медленный доступ к данным и не всегда гарантирует извлечение абсолютно точной информации, но он надежно сохраняет все данные и предотвращает их безвозвратную потерю. Более того для такой модели памяти нам важно уметь выполнять несколько операций:
Чтение из памяти и помещение информации в контекст модели. То есть цепочка превращений здесь: Долгосрочная память → Краткосрочная память → Вывод модели.
Суть чтения из памяти заключается в том, как извлечь ценную информацию.
При извлечении информации из памяти обычно используются три основных критерия: актуальность, релевантность и важность, оцениваемые посредством скоринговых функций ,и. Это помогает определить, какая часть информации из всей памяти (M) наиболее подходит для текущего запроса (q). В качестве такого запроса может быть задача, которую нужно решить или контекст, в котором находится агент. Параметры α, β, γ являются настраиваемыми и должны выбираться на основе требований к системе. Часто можно встретить, что используют только β, то есть для нахождения информации считаем только меру релевантности.
Однако, на практике просканировать все документы из базы тяжело, т.к. это будет слишком долго. О решении этой проблемы поговорим чуть дальше.
Запись информации в память. Цель записи в память — сохранить информацию, которая потенциально может быть полезна в будущем. Здесь есть несколько важных вопросов:
Понять, что и когда нужно сохранять. Возможно что-то из диалога с пользователем или опыт решения какой-то задачи.
Решить, что делать с устаревшей или дублированной информацией. Иначе со временем могут возникнуть проблемы по типу противоречий.
Решение может быть таким: мы объединяем информацию в небольшие группы, связанные одной темой. Как только размер группы превосходит порог, мы запускаем процедуру суммаризации и сжимаем кол-во документов в группе до одного-двух. На этом же этапе можем удалять/помечать устаревшую информацию.
Как альтернатива, сама LLM может решать, в каком случае нужно обновить, удалить, дополнить информацию из памяти и сделать соответствующий запрос. В RET-LLM [7] модель сама генерирует команду записи в память, когда считает, что конкретную информацию нужно сохранить (команда может выглядеть, например, как MEM_WRITE[info]).
Решить, что делать с переполнением памяти, то есть как освобождать место под новую актуальную информацию.
Наивное решение — использовать что-то вроде TTL (time to leave) или Cache Eviction policies, то есть классические методы для работы с базами данных, или отдать это на управлению пользователю. Например, в работе ChatDB [8], где в качестве памяти дополнительно используется база данных, к которой агент может обращаться путем SQL запросов, добавлена возможность удалять воспоминания путем пользовательских команд.
Более сложные подходы могут выглядеть как фоновые процессы, пытающиеся найти кандидатов к удалению по заданным критериям.
Рефлексия памяти. Рефлексия памяти имитирует способность человека наблюдать и оценивать свои собственные когнитивные, эмоциональные и поведенческие процессы. При адаптации к агентам ставится задача наделить их способностью самостоятельно обобщать и выводить более абстрактную, сложную и высокоуровневую информацию. Пример имплементации может выглядеть следующим образом:
Агент генерирует ключевые вопросы на основе своих воспоминаний, используя их для запроса в память, а затем формирует на их основе высокоуровневые выводы. Кроме того, процесс осмысления может происходить иерархически, то есть осмысление может генерироваться на основе уже существующих выводов. Например, в работе GITM [9] (Ghost in the Minecraft, агент по игре в Minecraft, где задачей ставится с нуля создать как можно больше вещей из определенного списка в 262 предмета), успешные действия, достигающие подцелей, хранятся в списке. Когда количество элементов в списке превышает порог, агент генерирует обобщенные шаблоны на основе этих действий для будущего использования.
Эти механизмы чтения, записи и рефлексии памяти обеспечивают агентам более глубокое и гибкое взаимодействие с информацией, позволяя адаптироваться под различные сценарии использования.
Давайте наконец вернемся к вопросу, как выглядит наиболее популярный подход для реализации работы долгосрочной памяти. Заключается он в использовании векторного поиска:
В первую очередь, все данные преобразуются в векторы определенного размера и хранятся в формате vector ↔ text.
Для извлечения информации запрос также переводится в вектор, и происходит поиск похожих документов в базе данных. Поиск заключается в том, что мы считаем некоторую меру схожести между векторами запроса и документа. В общем случае ее нужно посчитать для всех документов из базы, что дает нам линейную сложность. В случае миллионов или десятков миллионов документов такой поиск становится неэффективным.
В таком случае принято использовать алгоритмы ANN (Approximate Nearest Neighbors), способные извлекать почти-точных соседей (мы извлекаем близкие документы, но не гарантируем, что все из них – ближайшие) за сублинейную сложность, например за O(logn). Со списком алгоритмов можно ознакомиться на ann benchmarks, где представлено множество интересных реализаций. От себя хотел бы порекомендовать подробнее ознакомиться с HNSW, IVF и ANNOY.
После получения похожих документов, мы можем поместить их в контекст модели напрямую (переводя таким образом в краткосрочную память) или же использовать другие методы по типу Cross-Attention для выделения главной информации.
Помимо векторного поиска, существуют и другие способы взаимодействия с долгосрочной памятью, включая упомянутое выше использование SQL-запросов для обращения к внешним хранилищам. Также хочется сказать, что здесь мы тоже можем обучать модель пользоваться памятью эффективнее путем сбора подходящего датасета [7] и последующего на нем тюнинга.
На сегодняшний день, модуль планирования и декомпозиции задач, возможно, является одним из самых сложных аспектов в разработке автономных агентов. В то время как большие языковые модели уже демонстрируют способность решать простые задачи, используя дополнительные инструменты, API и извлекая информацию из долгосрочной памяти, ключевым вызовом остается обучение моделей эффективно разбивать сложные задачи на более мелкие и управляемые этапы. Это требует не только понимания общей структуры задачи, но и способности генерировать детализированные планы действий. Давайте рассмотрим, какие существуют подходы для реализации этого процесса, от простых методов к более сложным.
Single Path Reasoning и Chain-of-Thought (CoT) [10]. Классика промптинга, когда мы просим модель рассуждать шаг за шагом (“Think step by step”) по мере решения задачи. Модель таким образом от решения задачи напрямую переходит к рассуждению по шагам, что в некотором смысле и является декомпозицией задачи. Сейчас существует множество и других вариаций, например, в недавней работе [11] было показано, что добавление эмоционального окраса в промпт может улучшить метрики модели.
Также существуют различные методы для поиска оптимальных промптов под конкретную задачу с помощью оптимизационных алгоритмов, включая градиентные и эволюционные. В качестве примера для последнего оставлю ссылку на недавнюю интересную работу [12]. Однако, для оптимизационных алгоритмов нам нужно уметь оценивать качество работы агента на какой-то задаче, что в общем случае сделать нетривиально.
Multi Path Reasoning и Tree-of-Thought (ToT) [13]. Применяя технику CoT, мы можем строить на каждом шаге параллельные варианты дальнейших действий, получая таким образом целое дерево различных вариантов. Далее модель может посмотреть на полученные пути и выбрать наиболее перспективные для дальнейшей генерации. Здесь появляется важное свойство, что теперь модели не надо генерировать правильный ответ с первой попытки, можно сгенерировать тысячу кандидатов и потом выбрать лучшего. И это улучшает качество работы модели — в том числе и ризонинга.
Можно провести аналогию с Monte-Carlo Tree Search (MCTS) — алгоритмом, с помощью которого такие модели как AlphaGo генерирует варианты для дальнейшего хода (небольшое видео с объяснением алгоритма). Очевидно, что мы не можем перебрать все возможные ходы, поэтому ограничиваемся несколькими наиболее перспективными, из которых выбираем наилучшее продолжение, например, с помощью модели-критика.
Отдельно хочется упомянуть вариант планирования через дебаты между различными агентами [14]. Идея заключается в создании некоторой арены, где LLM агенты могут совместно приходить к общему выводу. В этой среде каждому агенту предъявляется запрос, и их ответы передаются всем остальным агентам. Важно, что контекст, который учитывает каждая LLM на каждом шагу, включает в себя как свои собственные рассуждения, так и рассуждения других агентов. После 3-4 итераций таких дебатов модели приходят к единому стабильному результату. Таким образом, подобно людям в дискуссии, они приходят к общим выводам, зачастую более правильным, чем первоначальный вывод отдельно взятого агента. Важным здесь остается вопрос выбора критерия останова для таких дебатов.
External Planners. Выделяющимся вариантом из предыдущих является обращение к внешнему планировщику, используя, например, язык PDDL для формализации задачи планирования. В таком случае LLM формулирует запрос на специальном языке, обращается к планировщику как внешнему инструменту и переводит его результат обратно в текст. Основной проблемой здесь является требование наличия такого планировщика и языка под конкретный домен, что бывает далеко не часто, поэтому метод можно встретить пока только в узких направлениях.
Во многих реальных сценариях для решения сложных задач агентам необходимо осуществлять долгосрочное планирование. При решении таких задач описанные выше модули планирования без обратной связи могут оказаться менее эффективными по следующим причинам: во-первых, сгенерировать безупречный план непосредственно с самого начала крайне сложно, поскольку необходимо учесть сразу все нюансы. Во-вторых, по ходу выполнения плана что-то может пойти не так и мы должны быть способны реагировать на изменения среды должным образом. Поэтому нужно научиться обрабатывать обратную связь.
Зачастую после какого-то действия среда дает нам отклик: поменялась обстановка на камерах, интерпретатор вернул код ошибки, браузер вернул список ресурсов и так далее. Эту информацию полезно учитывать для уточнения или корректировки текущего плана. В частности, подход ReAct [15] предлагает строить подсказки на основе триплетов "мысль - действие - наблюдение".
Компонент "мысль" облегчает высокоуровневые рассуждения и планирование для агента. Наблюдение соответствует результату выполненного действия, полученному через внешнюю обратную связь, например, результаты работы поисковой системы. Следующая мысль формируется под влиянием предыдущих наблюдений, что делает генерируемый план более адаптивным к окружающей среде.
Другой пример — Voyager [16], агент общего назначения в Minecraft для исследования среды, приобретения новых навыков и предметов. В этой работе агент строит планы, используя три типа обратной связи с окружающей средой, включая промежуточный ход выполнения программы, ошибки выполнения и результаты самопроверки.
Данная работа интересна и с других точек зрения, особенно рекомендую ее к прочтению. Например, там очень интересно устроен модуль памяти — агент сам пишет подпрограммы на javaScript для исполнения в будущем, они сохраняются, и далее из них уже выбираются возможные действия.
И наконец, в работе Teaching Large Language Models to Self-Debug [17] используется результат работы кода как фидбэк для последующего анализа моделью. Если код оказался нерабочим, то агент может исправить какие-то части и повторить выполнение.
Таким образом, интеграция долгосрочного планирования с обработкой обратной связи значительно улучшает способность агентов к адаптации и эффективному решению задач, позволяя им реагировать на изменения в среде и динамически корректировать свои планы действий. Стоит отметить, что мы также можем использовать методы по типу CoT и ToT в сценариях с обратной связью.
Такой сигнал является субъективным, но позволяет эффективно согласовывать работу агента с ценностями и предпочтениями человека, а также облегчает проблему галлюцинаций. Обратная связь может быть включена напрямую в промпт, по которому агент может делать дальнейшие выводы. Например, в работе Inner Monologue [18] агент может получать подсказки от пользователя для уточнения и объяснения деталей, которые ему сложно получить из среды самому.
Обратная связь от человека несет большую ценность, но имеет огромный недостаток — временную задержку на написания текста, как минимум это несколько секунд. Поэтому существует третий тип обратной связи — от других моделей. Этот тип обычно генерируется на основе предварительно обученных на конкретные задачи моделей. Агент генерирует ответ и получает от них обратную связь, на основе которых планирует следующие действия.
Алгоритм Reflexion [19] разработан для расширения возможностей планирования с помощью подробной обратной связи. В этом подходе агент сначала производит действие, основываясь на своей памяти, а затем другая модель-эксперт генерирует обратную связь, принимая историю агента в качестве входных данных. В отличие от большинства предыдущих работ, где обратная связь дается в виде численного значения или ответа среды напрямую, в Reflexion используется LLM для создания детальной обратной связи, которая обеспечивает более информативный сигнал для агента.
Другим хорошим примером, на мой взгляд, служит работа от OpenAI — Let’s Verify Step by Step [20]. В ней в качестве проблемы авторы выбрали математические задачи и обучали модель немного в другом формате. Вместо того, чтобы давать модели оценку за ответ целиком (например, 1, если ответ правильный и 0, если нет), предлагается делать это по промежуточным шагам, указывая на удачные/неудачные примеры рассуждений. Опять же, в таком случае получаем намного более полезный и информативный сигнал, нежели оценка всей генерации одним числом. Более того, из-за новой постановки задачи модель на выходе также способа оценивать корректность конкретного шага и выступать в роли некоторого критика, то есть в дальнейшем ее можно хорошо использовать с алгоритмом по типу ToT.
Полученная модель является только первым шагом на пути к системе, которая сможет заменить одного исследователя: OpenAI строят агента, но с планами амбициознее, чем игра в майнкрафт или доту, они хотят автоматизировать рисерч! Уже сейчас это дает свои результаты, но предстоящий прогресс в этой сфере завораживает.
Подход с обратной связью от модели позволяет получать более быстрый сигнал, делая процесс планирования эффективнее. Более того, главным преимуществам здесь является то, что модели-критики потенциально могут использоваться для всех видов задач (главное, обучить их этому), в то время как человеку во множестве доменов может не хватать экспертизы.
Итак, мы разобрали основные компоненты LLM-based агентов и посмотрели на современные работы, которые освещают эту тему. Когда я только начинал писать этот обзор, мне хотелось сделать 3 вещи:
Дать верхнеуровневое представление, как и для чего работает каждый модуль и какие есть проблемы в их реализации. Сделать это хотелось не сильно техническим языком, понятным в первую очередь людям не из сферы машинного обучения.
Посмотреть на последние работы и для лучшего понимания в качестве иллюстраций показать, как авторы решали те или иные проблемы.
Посмотреть, на что уже сегодня способны модели-агенты.
Надеюсь мне хотя бы отчасти это удалось и вам понравилось.
Возникает вопрос, а какой следующий шаг нужно сделать в разработке агентов, чтобы выйти на новый уровень? На мой взгляд, это модуль планирования и ризонинга. Возможно там уже есть новые разработки, о которых мы пока не знаем, но кажется для решения по-настоящему сложных задач (таких как автоматизация исследования в конкретной области) именно планирования и рассуждения играют ключевую роль. Здесь можно идти по пути усовершенствования LLM в целом (и тогда все сопутствующие навыки улучшатся) или разработки конкретных методов (как в работе Let's Verify Step by Step), либо сразу по обоим. Так что пристально следим за направлением.
Ну и напоследок, представьте, что агент сможет работать на удаленке, для этого не так много надо. Более того, часть из необходимых навыков, такие как поиск ответов в интернете и написание кода, текущие агенты уже решают отлично. Взять тикет, прикинуть план действий, провести сбор информации, написать код и тесты, покрыть документацией, сделать PR. Что будем делать тогда?
Все упомянутые статьи можно найти в списке ниже, чтения хватит надолго! Если у вас остались какие-то вопросы, то смело задавайте их любым удобном способом: телеграм, Singularis (alex_golubev) или LinkedIn, постараюсь оперативно отвечать.
Liu et al. "Visual Instruction Tuning" arXiv preprint arXiv:2304.08485 (2023).
Li et al. "BLIP-2: Bootstrapping Language-Image Pre-training with Frozen Image Encoders and Large Language Models" arXiv preprint arXiv:2301.12597 (2023).
Wang et al. "When Large Language Model based Agent Meets User Behavior Analysis: A Novel User Simulation Paradigm" arXiv preprint arXiv:2306.02552 (2023).
Shuster et al. "BlenderBot 3: a deployed conversational agent that continually learns to responsibly engage" arXiv preprint arXiv:2208.03188 (2022).
Schick et al. "Toolformer: Language Models Can Teach Themselves to Use Tools" arXiv preprint arXiv:2302.04761 (2023).
Zhu et al. "CALYPSO: LLMs as Dungeon Masters' Assistants" arXiv preprint arXiv:2308.07540 (2023).
Modarressi et al. "RET-LLM: Towards a General Read-Write Memory for Large Language Models" arXiv preprint arXiv:2305.14322 (2023).
Hu et al. "ChatDB: Augmenting LLMs with Databases as Their Symbolic Memory" arXiv preprint arXiv:2306.03901 (2023).
Zhu et al. "Ghost in the Minecraft: Generally Capable Agents for Open-World Environments via Large Language Models with Text-based Knowledge and Memory" arXiv preprint arXiv:2305.17144 (2023).
Wei et al. "Chain-of-Thought Prompting Elicits Reasoning in Large Language Models" arXiv preprint arXiv:2201.11903 (2022).
Li et al. "Large Language Models Understand and Can be Enhanced by Emotional Stimuli" arXiv preprint arXiv:2307.11760 (2023).
Guo et al. "Connecting Large Language Models with Evolutionary Algorithms Yields Powerful Prompt Optimizers" arXiv preprint arXiv:2309.08532 (2023).
Yao et al. "Tree of Thoughts: Deliberate Problem Solving with Large Language Models" arXiv preprint arXiv:2305.10601 (2023).
Zhuge et al. "Mindstorms in Natural Language-Based Societies of Mind" arXiv preprint arXiv:2305.17066 (2023).
Yao et al. "ReAct: Synergizing Reasoning and Acting in Language Models" arXiv preprint arXiv:2210.03629 (2022).
Wang et al. "Voyager: An Open-Ended Embodied Agent with Large Language Models" arXiv preprint arXiv:2305.16291 (2023).
Chen et al. "Teaching Large Language Models to Self-Debug" arXiv preprint arXiv:2304.05128 (2023)
Huang et al. "Inner Monologue: Embodied Reasoning through Planning with Language Models" arXiv preprint arXiv:2207.05608 (2022).
Shinn et al. "Reflexion: Language Agents with Verbal Reinforcement Learning" arXiv preprint arXiv:2303.11366 (2023).
Lightman et al. "Let's Verify Step by Step" arXiv preprint arXiv:2305.20050 (2023).