[AEDB] Agents Event Driven Behavior: Part I Concept
Концепция распределенного роя
Сначала был набор бессвязных слов, которые первые прототипы AI постили в твиттер, а мы все дружно потешались и пытались искать в них смысл. Потом появилось поколение GPT-3.5, которое всколыхнуло IT-сектор и показало всем, что невозможное — возможно. Уже с той поры, участвуя в хакатонах по AI, я мечтал о времени, когда что-то подобное можно будет поднять на своей локальной тачке.
И вот сегодня на среднем игровом PC я могу запустить модель, которая на порядок переплюнет поколение GPT-3.5 и сможет выполнять реальные, прикладные задачи — стать агентом. Но аппетит приходит во время еды, и мы, люди, начали задумываться: а как бы нам сделать так, чтобы агенты сами делали работу, сами ее корректировали, координировали и оркестрировали, а мы, кожаные властелины, просто сидели бы на цифровом троне и рукой водили?
В процессе размышлений и экспериментов я (да и другие исследователи, каждый по-своему) пришел к выводу, что с этим отлично может справиться рой агентов, если организовать надежный механизм управления. Предлагаются совершенно разные концепции управления, но я не нашел в паблике полноценного описания архитектуры, на базе которой строю рой я. Поэтому я решил структурировать свой опыт и написать цикл постов с полным и развернутым описанием подхода AEDB (Agent Event Driven Behavior).
Все пакеты, код и библиотеки, которые будут описаны в цикле постов, являются публичными и распространяются под открытой лицензией, если не указано обратного.
Содержание
* Содержание будет дополняться по мере написания
Что такое рой агентов?
Прежде чем приступить к описанию самой AEDB-архитектуры, нам следует разобраться: что вообще такое рой агентов? На самом деле тут всё просто, это прямая аналогия с пчелиным роем: каждая пчела действует самостоятельно и независимо, но в общих целях улья, которые диктуются ей определенными сигналами. По прямой аналогии действуют и агенты в составе цифрового роя. Однако в нашем случае всё гораздо интересней.
Рой агентов — это некоторое количество гомогенных и гетерогенных агентов (о типах поговорим ниже), каждый из которых работает над своей частью задачи, но все вместе они решают одну глобальную проблему: понять интенцию пользователя и удовлетворить ее.
Например, у нас может быть агент-поисковик в интернете, агент, который пишет код, агент, который ищет по заметкам, и так далее. При обращении пользователя к системе происходит маршрутизация запроса соответствующему агенту (как именно — на этот вопрос и отвечает AEDB). Агент выполняет свою работу, делает отчет, при необходимости вносятся правки — привычный флоу мультиагентной ReAct системы. В таком режиме система может быть достаточно гибкой, хорошо и быстро выполнять поставленные перед ней задачи.
Именно способ маршрутизации является краеугольным камнем различных архитектур оркестрации. И AEDB пытается дать на него свой ответ.
Распределенность роя
В моем понимании, рой обязан быть распределенным. То есть агенты должны уметь работать как самостоятельные инстансы, выполнять свою часть задачи и при этом гибко координироваться с остальной системой. Распределенности можно достичь разными способами: хоть цепочкой вызовов API, хоть различными комбинациями микросервисных архитектур. Однако Event-Driven Design (событийно-ориентированный подход) позволит достичь максимальной децентрализации, сохранив при этом независимость агентов (демонам буквально не обязательно знать о существовании друг друга) и гибкую конфигурируемость системы (через подписки агентов на события по их профилю).
Здесь возникает классовое и типовое расслоение агентов, потому что:
- Нужен набор агентов, которые будут организовывать операционную работу роя:
- Организовывать роутинг;
- Планировать задачи и проверять их исполнение;
- Вести диалог с пользователем, организуя human-in-the-loop;
- и т.д.
- Нужен набор агентов-исполнителей:
- Поиск и анализ данных в сети;
- Написание кода и конфигураций;
- Работа с базой знаний пользователя;
- и т.д.
Если выстраивать логику взаимодействия между всеми этими агентами вручную на базе конфигурирования последовательностей API-вызовов, то распределенность получить можно, но управление и поддержка такого решения быстро превратятся в ад. Здесь нужна «кровеносная система» пакетов, то есть шина событий (детали ее реализации рассмотрим в следующих частях) и набор специфицированных правил событий.
Тогда каждый из агентов будет иметь понятную конфигурацию подписок на конкретный пул событий, относящийся к области его компетенции. Даже если по какой-то причине агент отвалился, после возвращения он продолжит работу с того места, где остановился.
Планирование и постановка задач
Агент-планировщик из операционного класса (о классах агентов — ниже) создает план действий, необходимых для достижения общей цели. Чтобы понять, какой инструментарий доступен, у планировщика есть онтология событий. После составления плана он публикует соответствующие события в шину. Сам он подписан на все сигналы о выполнении и изменении любых событий, связанных с его планом.
Это позволяет планировщику после создания плана асинхронно раздать задачи воркерам и так же асинхронно реагировать на обновления, корректируя стратегию на базе новых данных. В итоге получается постоянный процесс коммуникации внутри роя:
Planner -> EventBus: Создает событие с задачей
EventBus <-> Worker: Подписан на пул событий по своей компетенции
Worker -> Worker: Делает работу
Worker -> EventBus: Сообщает о работе ИЛИ об ошибке ИЛИ о неверной постановке задачи
EventBus <-> Planner: Подписан на все сигналы по событию
Planner -> Planner: Коррекция / изменение / дополнение плана
Planner -> EventBus: Новое событие после коррекции
Этот процесс позволяет планировщику гибко перестраивать граф плана, ориентируясь на события в реальном времени (что может быть критически важно для агентов в IoT-системах).
Классы и типы агентов
Для полноты концепции стоит обозначить классы и типы агентов в рое: что это такое и зачем нужно.
1. Операционный класс агентов (Kernel)
К этому классу относятся агенты, организующие работу роя. Обычно это:
- Маршрутизатор — агент на входе. Решает, куда направить запрос, и требуется ли отделить моментальную реакцию на команду от той, где нужно подумать и составить план действий.
- Планировщик — самая важная часть роя. Должен быть основан на самой сильной «думающей» модели из доступных. Строит граф плана в реал-тайме, корректируя его, пока задача не будет завершена.
- Ассистент — агент, взаимодействующий с пользователем непосредственно. Подписан на события, относящиеся к эскалации на юзера. Если рой не может однозначно принять решение или требуется разрешение на действие, то human-in-the-loop реализуется через него. По сути, это естественный интерфейс для пользователя.
Не буду перечислять все возможные виды, но для концептуального понимания этого достаточно.
2. Класс агентов-исполнителей (Daemons)
Как понятно из названия, это агенты, выполняющие поставленную перед ними задачу. Для узкого спектра задач можно сделать одного агента, у которого есть разные инструменты и который сам общается с пользователем. Однако когда речь заходит о сотнях или тысячах функциональных единиц, такой универсал просто потеряется в инструментах и начнет галлюцинировать.
Поэтому для сложных систем агенты обычно декомпозируются на профильных. С результатом их деятельности работает уже агент операционного класса, не засоряя свой контекст лишними деталями. В контексте AEDB каждый исполнитель — это демон, висящий в фоне и слушающий события по своим подпискам.
Подписки демона определяются рамками его компетенций. Контракт подписок содержит сигнал, который позволяет агентам общаться вокруг конкретного события.
Пример: Планировщик ошибочно распределил задачу на написание кода агенту-поисковику. Агент-поисковик получил событие, открыл задачу и первым делом проверяет: «А могу ли я вообще выполнить эту задачу?» Если нет, он создает это же событие, но с сигналом, сообщающим об ошибке. Планировщик, подписанный на эти сигналы, реагирует и корректирует свой план, пересоздавая событие с учетом ошибки. Это закладывает в систему адаптивность и отказоустойчивость.
Типы агентов
Для полноты описания терминологии давайте зафиксируем, что в контексте роя мы рассматриваем два типа агентов: гетерогенные и гомогенные.
Гетерогенный агент — индивидуально сконфигурированный агент, имеющий кастомную логику исполнения и заточен под конкретные задачи (например: Планировщик). Пишется, обычно на LangGraph или аналогах. Может быть реплицирован на инстансы, это не является определяющим.
Гомогенный агент — стандартизированный ReAct агент, имеющий набор различных инструментов и способный решать разный спектр задач, однако не очень сложных и не очень глубоко. Может быть сделан поверх высокоуровневого фреймворка, например DeepAgents.
Заключение
Это вводный пост в цикл постов по архитектуре, в нем я постарался сформулировать концепцию распределенного роя агентов в контексте Event-Driven Design. В следующих постах перейдем к конкретике и будем разбирать эти идеи на реальной реализации. Все ссылки для хронологического удобства чтения будут добавляться между постами в процессе их написания.