18+
реклама
18+
Бургер менюБургер меню

Ранас Мукминов – Оркестрация ИИ-агентов. Claude Opus 4.7 (страница 6)

18

Эта ось порождает класс вопросов, который не сводится к работе и состоянию. Кто отвечает за стык между двумя агентами — за то, что выход A корректно понят входом B? Кто отвечает за результат, собранный агрегатором из частей, каждая из которых по отдельности корректна, а вместе — нет? Кто отвечает, когда агент честно отчитался об успехе, но его часть на самом деле не работает? Ответственность в рое описывается контрактами агентов (вход, выход, инварианты — см. главу 18) и границами ролей (см. главу 16); проверяемость этих контрактов — единственный способ сделать распределённую ответственность управляемой.

Failure mode распределения ответственности: диффузия ответственности и ложный успех. Диффузия — отказ происходит на стыке, за который формально не отвечает никто, и при разборе каждый агент «сделал свою часть правильно». Ложный успех — агент сообщает об успешном завершении, система засчитывает его как готовый, а на деле часть не выполнена; в рое такой ложный успех распространяется дальше, потому что следующий агент доверяет отчёту предыдущего. Это специфический и опасный отказ: одиночный агент тоже может ошибиться, но в рое ошибка одного, принятая на веру другими, усиливается каскадом (см. главу 67).

Три распределения выбраны не произвольно. Они соответствуют трём вопросам, на которые любая распределённая система обязана ответить: кто что делает (работа), кто что знает (состояние), кто за что отвечает (ответственность). Четвёртая величина — координация — не отдельная ось, а то, что связывает эти три: координация есть работа по согласованию распределённой работы, распределённого состояния и распределённой ответственности. Поэтому координация всегда стоит и рассматривается как налог, а не как данность (см. главу 5). Чем сильнее распределение по любой из осей, тем выше координационный налог; оркестрация оправдана только там, где выгода распределения превышает этот налог (см. главу 4).

Существенно, что оси независимы. Можно распределить работу, но держать всё состояние в одном месте (оркестратор с воркерами, где воркеры stateless, — см. главу 8). Можно распределить состояние, но не работу (несколько агентов, читающих и пишущих общую доску по очереди, — blackboard, см. главу 11). Распределение ответственности почти всегда сопутствует распределению работы, но не наоборот: бывает распределённая работа с централизованной ответственностью, когда оркестратор берёт на себя ответственность за итог, а воркеры отвечают лишь перед ним. Конкретные комбинации осей дают конкретные топологии; этому посвящена часть II.

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

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

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

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

Определение опирается на слово «недетерминированные», и оно несёт основную нагрузку. Именно природа узла отличает оркестрацию агентов от оркестрации задач и заставляет переписывать классические приёмы распределённых систем с поправками.

Узел мультиагентной системы обладает четырьмя свойствами, которых нет у обычного узла распределённой системы.

Первое — недетерминизм. Один и тот же вход даёт разные выходы. Это ломает идемпотентность по умолчанию: повтор операции у обычного сервиса безопасен, у агента — нет, потому что повтор может дать другой результат. Семантика повторов и ключи идемпотентности в рое приходится вводить специально (см. главы 43, 29).

Второе — стоимость. Каждое обращение к узлу стоит токенов и времени, и стоимость нелинейна по объёму контекста. Это делает спекулятивное и избыточное исполнение (запуск с запасом ради скорости — см. главу 36) не бесплатной оптимизацией, а экономическим решением; и это ставит экономику в центр проектирования (см. главу 100).

Третье — естественный язык как интерфейс. Агенты обмениваются не строго типизированными сообщениями, а текстом, который нужно парсить и валидировать. Граница между данными и инструкцией размывается, и это открывает поверхность атаки — prompt injection, передаваемый через handoff и общую память (см. главу 86). Форматы сообщений и схемы (см. главу 25) — попытка вернуть строгость туда, где её нет по умолчанию.

Четвёртое — правдоподобная ошибочность. Агент ошибается не как падающий сервис (явно, с трассировкой), а как уверенный исполнитель: возвращает связный, грамматически корректный, но неверный результат. Это самое коварное свойство, потому что обычные механизмы обнаружения отказа — тайм-аут, исключение, код ошибки — здесь не срабатывают. Отказ нужно обнаруживать по содержанию, а не по форме, и часто силами другого агента (самопроверка и взаимное ревью — см. главу 65).

Классическая теория применима, но требует поправок, и честность этих поправок — методологический принцип всей книги. Консенсус между агентами возможен (голосование, кворум — см. главу 39), но «правильность» голоса недетерминирована, поэтому majority не гарантирует корректности так, как в детерминированной репликации. Тайм-ауты, повторы, circuit breaker переносятся напрямую (см. главу 70), но повтор недетерминированного узла — это не та же операция, что повтор детерминированного, и circuit breaker должен учитывать стоимость. Изоляция отказов через bulkhead (см. главу 71) работает, но «отказ» нужно переопределить, включив в него правдоподобную ошибочность, а не только падение.

Главный неверный шаг — приписать агентам гарантии, которыми они не обладают. Агент не даёт строгой согласованности по своему выходу; не идемпотентен без специальных мер; не сообщает об ошибке надёжно. Архитектура мультиагентной системы — это во многом строительство строгих гарантий поверх ненадёжных, недетерминированных, дорогих узлов. Это и есть содержание оркестрации, и это объясняет, почему она ближе к распределённым системам, чем к prompt engineering.

Чтобы определение стало операциональным, рассмотрим две минимальные системы, которые легко спутать, и применим к ним проверку через три оси. Системы намеренно обобщённые и иллюстративные.

Система первая: на вход поступает запрос, он рассылается в три экземпляра модели, каждый отвечает независимо, агрегатор выбирает ответ по согласию большинства. Применяем проверку. Распределение работы — нет, три экземпляра делают одно и то же. Распределение состояния — нет, экземпляры не видят друг друга. Распределение ответственности — нет, отвечает агрегатор. Вывод: это ансамбль, не оркестрация. Изъятие любого экземпляра не меняет работу остальных. Проектировать его как рой — значит платить за координацию, которой нет.

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

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