TL;DRЕсли один пользовательский диалог проходит через несколько агентов, это задача оркестрации, а не «микросервисность». В естественном языке нет контрактов урTL;DRЕсли один пользовательский диалог проходит через несколько агентов, это задача оркестрации, а не «микросервисность». В естественном языке нет контрактов ур

[Перевод] Мультиагенты — это скрытые распределённые монолиты

TL;DR

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

Практичнее трактовать суб-агентов как зависимости, держать единый источник истины и покрывать ключевые сценарии сквозными интеграционными тестами. A2A полезен для внешних/легаси-агентов, но сам по себе проблему границ и координации не решает.

Ранее мы вводили определения оркестрации и разбирали пример банковского ассистента, который помогал пользователям подобрать, купить и профинансировать новый автомобиль (назовём его Ace).

Для конечных пользователей мы хотим, чтобы любой диалог с Ace ощущался просто как «разговор со своим банком», без необходимости сталкиваться со сложностью организации, стоящей за агентом. Одна из распространённых продуктовых целей для таких ассистентов — объединять взаимодействия с клиентом в непрерывный диалог.

Но предприятия — это сложные организации. Если мы хотим, чтобы Ace охватывал весь спектр того, что может предложить банк, наш агент должен будет взаимодействовать со множеством разных подразделений. Как масштабировать Ace на всю организацию? И когда вклад в разработку вносят многие команды, как добиться независимости — возможности быстро выпускать итерации, при этом сохраняя единый, цельный пользовательский опыт?

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

Микросервисы зависят от контрактов API, соблюдение которых можно обеспечивать. С естественным языком таких контрактов не существует.

Лучший способ справиться с этой сложностью — воспринимать суб-агентов как зависимости. Если же относиться к ним как к автономно работающим сервисам, вы получите всю боль распределённых систем — и ни одного из их преимуществ.

Создание мультиагентной системы на микросервисах

Ключевая идея: агент-«оркестратор» выступает входной точкой и делегирует задачи специализированным «суб-агентам».

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

Это порождает три проблемы, из-за которых микросервисы становятся непрактичными. Разберём каждую.

Проблема 1: маршрутизация — это сложно

В диалоге ниже Ace уже поискал в интернете и порекомендовал Hyundai Kona. Затем пользователь спрашивает: «сколько они стоят»?

Какой суб-агент должен отвечать? Агент веб-поиска может найти общую информацию о ценах. Но по замыслу системы этим должен заниматься сторонний агент объявлений (для примера возьмем cars.com), чтобы показать конкретные предложения Hyundai Kona в продаже рядом с домом пользователя.

Это решение о маршрутизации нужно где-то явно зафиксировать. Вам нужно определить:

  • Web search отвечает за: общую информацию об автомобилях, обзоры, сравнения

  • Cars.com отвечает за: поиск по объявлениям, конкретные цены по предложениям, наличие

  • Financing отвечает за: условия кредита, ежемесячные платежи, оценку доступности по бюджету

И вот где начинается самое неприятное: LLM-агенты стремятся «угодить» и будут пытаться помогать за пределами своей зоны ответственности. Агент cars.com, получив управление, охотно скажет что-то вроде:

  • «Какой у вас диапазон бюджета? Это поможет мне отфильтровать результаты».

  • «Хотите рассмотреть варианты финансирования?»

Если по дизайну вы решили, что обсуждать бюджет и кредиты должен только агент финансирования, вам теперь нужно явно определить:

  • Когда маршрутизировать на cars.com, а когда — задавать вопросы про финансирование

  • Ограничения для агента cars.com, чтобы он НЕ предлагал помощь с финансированием

  • Ограничения для агента веб-поиска, чтобы он НЕ отвечал на вопросы о цене

Эта координационная работа должна где-то выполняться — будь то в оркестраторе, прямо в промптах агентов или в какой-то общей конфигурации. И каждый раз, когда вы меняете границы ответственности суб-агента, вам приходится обновлять правила маршрутизации и ограничения сразу в нескольких агентах.

В традиционных микросервисах соблюдение контрактов проверяют в рантайме с помощью схем/валидации (например, API-схем). Здесь же вы пытаетесь обеспечить их соблюдение множеством промптов и небольшой долей молитвы.

Проблема 2: изменения «расползаются» каскадом

Один из наших критериев дизайна — команды должны иметь возможность выпускать изменения независимо друг от друга.

Команда финансирования хочет улучшить свой сценарий. Сейчас они спрашивают: «Вам кредит на 36, 48 или 60 месяцев?» Затем уточняют первоначальный взнос. Они хотят перевернуть логику: начать с вопроса «Какой ежемесячный платёж вы можете себе позволить?» и уже от этого рассчитывать условия кредита.

Казалось бы, это простое изолированное изменение. Одна команда, один агент, одно обновление промпта. Но тут появляется проблема.

Агент cars.com уже спрашивает у пользователя «бюджет» перед поиском — имея в виду общую стоимость автомобиля. А агент финансирования теперь тоже спрашивает о «бюджете» — но имея в виду ежемесячный платёж, который пользователь может себе позволить. Одно и то же слово — два разных смысла.

Диалог пользователя может развиваться по-разному:

  • Пользователь начинает с поиска конкретной машины, но, увидев условия кредита, понимает, что она не вписывается в бюджет, и начинает искать что-то подешевле

  • Пользователь точно знает, какую сумму в месяц может платить, и хочет найти лучший автомобиль в рамках этого ограничения

  • Пользователь предпочитает новую машину, но готов рассмотреть подержанную, если разница в цене слишком велика

В каждом из этих сценариев будут вперемешку участвовать веб-поиск, cars.com и финансирование. И теперь «простое изменение» команды финансирования требует доработок оркестратора, чтобы тот корректно обрабатывал все эти ветки диалога. Нужны интеграционные тесты, чтобы не допустить регрессий. И деплоить придётся всё вместе.

Это не слабая связанность. Это распределённый монолит.

Проблема 3: разделяемое изменяемое состояние

Чтобы суб-агенты могли сотрудничать в рамках одного связного, «плавного» диалога, им нужно обмениваться данными:

  • Бюджет пользователя (ежемесячный и/или общий)

  • Выбранная модель автомобиля

  • Цена автомобиля

Нужно определить, какие агенты могут читать каждую из этих сущностей: сторонний агент cars.com, например, не должен видеть, что именно входит в ваши расчёты по финансированию. Но также нужно решить, кто имеет право обновлять эти переменные и что должно происходить, когда они меняются.

Пользователь говорит: «вообще-то, думаю, я смог бы платить на $50 больше в месяц». Это может означать покупку автомобиля классом выше — или просто более быстрое погашение кредита. Должен ли агент финансирования пересчитать условия кредита? «Раскрутить» расчёт в обратную сторону и вывести новый общий бюджет на автомобиль? Должен ли агент cars.com заново выполнить поиск, чтобы показать более дорогие варианты?

Эту координационную логику нужно где-то задать — в вашем оркестраторе или внутри каждого суб-агента. Какой бы вариант вы ни выбрали, вы в итоге управляете разделяемым изменяемым состоянием между якобы независимыми сервисами — а это прямо противоположно тому, что делает микросервисы жизнеспособными.

Это монолит, так и структурируйте код как монолит

Если вы ожидаете, что пользователи будут взаимодействовать с несколькими агентами в рамках одного разговора, у вас есть задача оркестрации, которую нужно решить. Запуск этих агентов как отдельных сервисов не сделает её проще.

Микросервисы работают тогда, когда можно принуждать к соблюдению контрактов API во время выполнения. С интерфейсом на естественном языке это невозможно. Без контрактов, соблюдение которых можно обеспечить, вы получаете всю сложность распределённых систем — и ни одного из их преимуществ.

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

Моя рекомендация такая: воспринимайте суб-агентов как зависимости, а не как сервисы. Пишите полноценные сквозные интеграционные тесты, которые покрывают важные пользовательские сценарии. Настройте job в CI/CD-пайплайне, которая будет прогонять эти тесты перед каждым деплоем. Явно определяйте и версионируйте определения доменов, логику обмена контекстом и сценарии диалогов.

Воспринимайте суб-агентов как зависимости, а не как сервисы.

Но это не вариант, когда вы интегрируете сторонние агенты (как cars.com в нашем примере). И вот тут появляется A2A.

Когда использовать A2A

Если один из ваших суб-агентов сделан третьей стороной или это легаси-проект на другом технологическом стеке, вашему оркестратору придётся относиться к нему как к «чёрному ящику». В таком случае имеет смысл использовать A2A, чтобы стандартизировать коммуникацию между оркестратором и суб-агентом.

Просто помните, что A2A — это протокол обмена сообщениями. Нельзя пригласить 100 человек в Slack и ожидать, что они автоматически начнут работать как компания; точно так же нельзя «соединить» агентов через A2A и ожидать, что они сами по себе начнут слаженно взаимодействовать. Возможность общения — лишь крошечная часть проблемы. Нужно определить, кто что делает и когда.

Эволюция A2A

По мере развития A2A я надеюсь, что он сможет более целостно решать проблему границ ответственности суб-агентов. Сейчас в A2A есть концепция agent card.

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

Стоит расширить спецификацию agent card так, чтобы она явно определяла, какие контекстные переменные суб-агент может читать, записывать и создавать.

Это сдвинет A2A в сторону слоя оркестрации, что, возможно, не совпадает с видением проекта. Но без таких вещей не обойтись, если мы хотим создать стандарт для построения оркестрируемых агентов, которые можно масштабировать, не превращая всё в спагетти-код.


Если хотите расти в архитектора, полезно уметь «разворачивать» систему на части так, чтобы она жила под нагрузкой и изменениями. На курсе «Microservice Architecture» разбирают практику: коммуникации и данные, кэширование/шардирование, распределённые транзакции и наблюдаемость (K8s, Kafka, Prometheus/Grafana, ELK). Готовы к серьезному обучению? Пройдите вступительный тест.

Для знакомства с форматом обучения и экспертами приходите на бесплатные демо-уроки:

  • 29 января в 20:00. «Брокеры сообщений: RabbitMQ и Kafka». Записаться

  • 2 февраля в 20:00. «Практические подходы к переходу от монолита на микросервисы». Записаться

  • 16 февраля в 20:00. «Тестирование в бэкенде». Записаться

Источник

Отказ от ответственности: Статьи, размещенные на этом веб-сайте, взяты из общедоступных источников и предоставляются исключительно в информационных целях. Они не обязательно отражают точку зрения MEXC. Все права принадлежат первоисточникам. Если вы считаете, что какой-либо контент нарушает права третьих лиц, пожалуйста, обратитесь по адресу [email protected] для его удаления. MEXC не дает никаких гарантий в отношении точности, полноты или своевременности контента и не несет ответственности за любые действия, предпринятые на основе предоставленной информации. Контент не является финансовой, юридической или иной профессиональной консультацией и не должен рассматриваться как рекомендация или одобрение со стороны MEXC.