Event Driven Agents

Мультиагентная система без оркестратора: агенты не ждут команды, а подписаны на шину событий и реагируют асинхронно. Отказ от модели «запрос — ответ» в пользу «случилось событие — кто-то отреагировал».

Суть

В привычных паттернах кто-то главный решает, кому передать работу: планировщик, координатор, следующий узел графа. Событийная архитектура убирает это звено. Агенты подключены к шине (Kafka, RabbitMQ), каждый слушает интересующие его типы событий и сам решает, вмешиваться или нет. Результат работы — тоже событие, на которое может отреагировать другой агент.

Выигрыш — в отсутствии единой точки отказа и в естественной масштабируемости: добавить нового агента — значит подписать его на поток, а не переписать граф.

Где это оправдано

Домен узкий, но характерный: реактивные задачи с непредсказуемым моментом наступления. Мониторинг безопасности в реальном времени, транзакционный фрод-мониторинг: здесь момент срабатывания неизвестен заранее, а события идут потоком, а не по запросу пользователя.

Для задач с явным началом и концом («проанализируй этот документ») событийная модель только добавляет сложности — там уместнее fan-out или последовательный пайплайн из Multi Agent Patterns.

Два обязательных требования

В факультативе они сформулированы как жёсткие: без них паттерн разваливается в проде.

Идемпотентность. Агент обязан безопасно переваривать дубликаты событий. Шина гарантирует доставку «хотя бы один раз», а не «ровно один раз» — повтор придёт рано или поздно. Если обработка события списывает деньги или пишет в базу без ключа идемпотентности, повтор превращается в инцидент.

Dead-Letter Queue. События, на которых сломался парсинг ответа модели, уходят в отдельную очередь для ручного разбора. Без DLQ битое событие либо теряется молча, либо бесконечно возвращается в основную очередь и отравляет поток.

Главная слабость: потеря трассировки

Уязвимость паттерна — потеря контекста при трейсинге. В синхронной цепочке traceparent передаётся HTTP-заголовком почти бесплатно (см. W3C Trace Context). В шине событий заголовка нет: идентификатор нужно класть в метаданные сообщения и восстанавливать контекст на стороне подписчика вручную, причём в каждом агенте.

Стоит этим пренебречь — и расследование инцидента превращается в сопоставление меток времени из разных логов. Для системы, где ветвление задумано как норма, это дорого вдвойне.

Идемпотентность и очередь недоставленных

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

Что делать с DLQ. Развилка решается тем, устарело ли событие. События, описывающие факт (заказ создан, документ загружен), переигрывать после фикса можно и нужно — факт не протух. События, описывающие намерение в моменте (пользователь ждёт ответа в чате), переигрывать бессмысленно: получатель ушёл, и повторная обработка создаст ответ в пустоту, а иногда и побочный эффект. Практическая политика — размечать события этим признаком при публикации, а не решать судьбу очереди задним числом; и в любом случае переигрывать с новой версией обработчика в ключе идемпотентности, иначе сработает дедупликация и ничего не произойдёт.

Связано с

  • EDA For AI — та же шина, но со стороны потока данных: буфер перед GPU, Fat Events, Event Sourcing как основа объяснимости
  • Multi Agent Patterns — паттерны с оркестратором, от которых событийная модель отказывается
  • Multi Agent Systems — место паттерна в общей картине MAS
  • W3C Trace Context — почему проброс идентификатора здесь становится ручной работой
  • Agent Failure Modes — молча потерянное событие не отражается ни в одной метрике
  • Hybrid Orchestration — противоположный полюс: максимум детерминизма вместо максимума автономии