Мультиагентные системы: как «команда ИИ» берёт сложность штурмом

от автора

Введение: мир, где одному ИИ тесно

Софт стал распределённым организмом: микросервисы, бесконечные API, CI/CD, инфраструктура как код, пользователи в разных часовых поясах. Ошибки проявляются не линейно, а «каскадами». Один умный помощник-универсал (даже очень большой) часто упирается в пределы: медленно, хрупко, дорого. Как и в инженерных командах, нужна кооперация ролей — планирование, исследование, реализация, проверка, эксплуатация. Эту идею и воплощают мультиагентные системы (MAS): коллекция автономных агентов, которые общаются, координируются и вместе решают задачи, где одиночный ИИ буксует. Репозиторий кода — https://github.com/iRatG/mas.

Почему одиночному ИИ тяжело

  • Рост сложности и динамики. Задачи распадаются на подзадачи с конфликтующими целями (качество, скорость, стоимость). Один агент «видит» лишь локальную оптимальность и спотыкается на компромиссах.

  • Ограничение внимания и времени ответа. Даже крупные модели ограничены контекстом и токен-бюджетом. Попытка «думать дольше» (длинные chain-of-thought) увеличивает стоимость и латентность, а не гарантирует качество.

  • Отсутствие надёжной верификации. Во многих доменах (код, математика) решение требует проверки — тестов, пруверов, формальных критериев. Без внешнего «судьи» одиночный агент склонен к уверенным, но неверным ответам.

Что такое мультиагентная система (MAS)

MAS — это набор автономных агентов со своими целями, наблюдениями и действиями. Они обмениваются сообщениями, договариваются и координируются. На практике: планировщик дробит задачу, исследователь собирает контекст, разработчик пишет патч, критик проверяет, а оператор запускает тесты. Коммуникация может быть явной (сообщения) или опосредованной арбитрами/агрегаторами; координация — синхронной (барьеры, раунды) или асинхронной (гонки гипотез, «первый дошёл — молодец»).

Фундамент: как LLM-агенты «думают, действуют и сверяются»

ReAct (Reason+Act) показывает, что связка рассуждения и действия (инструменты, среда) даёт устойчивые траектории решения: агент мыслит шагами, вызывает инструменты, читает наблюдения и корректирует план [1].
Self-Consistency добавляет стохастическое «многоголосие» — мы генерируем несколько независимых рассуждений и берём консенсус. Эта простая техника заметно повышает точность на текстовых задачах [2].
Процесс-супервизия (PRM) учит модели/критиков оценивать каждый шаг рассуждения, а не только финальный ответ. Это превращает «верим-не верим» в проверяемую лестницу шагов и синергирует с инструментами верификации [3].

Отсюда рождаются два практических рычага, которые MAS используют системно:

  1. Время на вывод (inference-time compute): больше проб и ветвей → выше шанс, что хотя бы один путь правильный (а значит, нужен хороший отборщик). 2) Множественность мнений: разнородные агенты/модели смотрят на задачу под разными углами, а агрегатор «собирает» ответ (Mixture‑of‑Agents) [5].

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

Mixture‑of‑Agents (MoA)

MoA — это «слоёная» кооперация моделей/агентов: в каждом слое несколько proposer‑ов предлагают версии, а aggregator синтезирует итог. Важны разнообразие предложений и способность агрегатора не просто ранжировать, а переосмысливать входы. Эмпирически MoA улучшает метрики (AlpacaEval, FLASK) и даже обгоняет сильные одиночные модели, особенно по устойчивости и полноте ответа; минус — рост времени до первого токена [5].

Повышение отдачи от времени вывода

Работы по массовому пересэмплингу показывают почти «законы масштабирования» на тест‑тайме: покрытие задач растёт лог‑линейно с числом проб на порядки, особенно там, где есть автоматический вердикт (юнит‑тесты, пруверы) [6,9]. Параллельно возникает вопрос «compute‑optimal инференса»: когда выгоднее взять меньшую модель, но больше проб/поиска, и какими алгоритмами (best‑of‑n, взвешенное голосование, дерево‑поиск) это делать — здесь появляются эмпирические правила и новые алгоритмы (например, REBASE), дающие лучшую «цена/качество» кривую [9].

Агент ↔ компьютер: ACI [4] и реальные среды

В инженерных задачах ключевое — связать агента с окружением. Парадигма Agent‑Computer Interface (ACI) задаёт дискретное действие («открой файл», «отредактируй патч», «запусти тесты», «проанализируй лог») и обратную связь (диагностика, линт, тест‑репорты). Такая формализация увеличивает воспроизводимость, расширяемость «навыков» и эффективность планирования. В задачах уровня SWE‑bench ACI‑подход сочетается с многораундовой стратегией и даёт прирост качества — особенно когда действия тонко подобраны (например, отдельное edit с атомарными диффами + автоматический линт) [4].

Платформы агентов

Практические фреймворки (например, «реальные компьютерные агенты» в изолированных Docker‑песочницах, с набором AgentSkills и делегацией подзадач) демонстрируют, как строить безопасные траектории действий в ОС/IDE и кооперацию агентов через шины событий и контроль политик [7].

Оценка и подводные камни

Софт‑агенты легко «переобучаются на бенчмарк»: утечки данных, детерминированные окружения, «подгонка под валидатор». Для честного прогресса важны: скрытые тесты, перемешивание/рандомизация окружения, проверка патча end‑to‑end, и независимые верификаторы (а не «LLM‑судья») [8,10].

Как это приземлить в «репозитории» (разбор кода и режимов)

Ниже — «экскурсия» по ключевым идеям и их воплощению в репозитории. Мы берём концепты из теории (ReAct, self‑consistency, процесс‑супервизия, MoA, inference‑time compute) и показываем, где они «сидят» в коде.

Подход 1: Синхронный (sync)

Идея. Чистая реализация ReAct [1]: один агент ведёт диалог с окружением/инструментами по шагам «Думаю → Действую → Наблюдаю → Корректирую план». Это минимальная, но надёжная форма координации — особенно когда есть явный верификатор (юнит‑тесты/чек‑листы). Теоретически это хорошо сочетается с процесс‑критикой: «маленький PRM» может проверять промежуточные гипотезы и фильтровать галлюцинации [1][3].
В репозитории. Оркестратор sync и CLI‑точка mas.cli.main --approach sync последовательно выполняют кейсы, поддерживают ретраи и собирают метрики (время/кандидаты/успехи). Это ровно тот baseline, на который хорошо «навешивать» self‑consistency и маленькие проверяющие [см. ниже].

Подход 2: Асинхронный (async, через оркестратор)

Идея. Роли и сообщения: Analyst локализует проблему, Fixer предлагает патч, Controller следит за бюджетом/таймаутами, Coordinator собирает итог. Это «тонкий MoA» [5]: несколько агентов дают разный взгляд на задачу, а оркестратор решает, когда остановиться и что принять. Теоретически это усиливает устойчивость (диверсификация гипотез), но повышает цену/латентность — значит, важно управлять глубиной и числом сообщений [5][6].
В репозитории. mas.cli.main --approach async включает шину сообщений и считает коммуникативные метрики (сколько сообщений, таймауты, эффективность). Роли реализованы как отдельные компоненты/хэндлеры, что упрощает расширение (легко добавить «Browser» или «Doc‑search»).

Подход 3: Итеративный/продвинутый

Идея. Масштабируем качество за счёт времени вывода: запускаем несколько независимых попыток (разных температур/подсказок), собираем «лучшее из N» по верификатору, запоминаем историю разборов (что сработало и почему), и повторно используем успешные траектории. Это прямая реализация результатов по repeated sampling/compute‑optimal инференсу [6]: иногда «меньше модель + больше попыток» превосходит «больше модель + одна попытка» [6].
В репозитории. mas.cli.iterative хранит историю, поддерживает батчи попыток и критерии отбора (юнит‑тесты/чек‑листы), а затем выводит сводные метрики. Этот режим легко комбинируется с sync/async: итерации можно вкручивать и в последовательный, и в многоролевой сценарий.


Два режима работы LLM: имитация и реальный API

A) Имитация LLM (для быстрых прогонов и демонстрации)

Зачем. Стабильно воспроизводить прогоны без интернета и расходов; быстро демонстрировать оркестрацию. Теоретически это важно для валидности экспериментов: мы фиксируем сиды/кейсы и исключаем дрейф модели.
В репозитории. Модуль mas.llm.mock_client возвращает предсказуемые ответы для заранее описанных кейсов («выход за границы», «деление на ноль» и т. п.), что позволяет сравнивать архитектуры в «чистом» виде и видеть, сколько сообщений/шагов/ретраев реально нужно каждому подходу.

Б) Реальный LLM через API (OpenAI и др.)

Зачем. Проверить, как система ведёт себя «в поле»: промпт‑инжиниринг, шумные логи, неоднозначные сообщения об ошибках, лимиты токенов. Теоретически здесь раскрывается роль ACI: чем чище действие и информативнее отклик (линт, дифф, трассировка), тем надёжнее петля ReAct [4].
В репозитории. mas.llm.real_llm (см. env_example.txt и docs/SETUP_OPENAI.md) подключает API, уважает модель/параметры, и проксирует вызовы через общий интерфейс. CLI:

python -X utf8 -m mas.cli.main --use-openai --openai-model gpt-4 --approach both --cases 1 2 3 

Как собирается промпт (в упрощённом виде)

Точная реализация может отличаться между ролями/подходами, но общий конструкт выглядит так — и хорошо соответствует современной практике:

[system] Вы — инженер‑разработчик в мультиагентной команде. Работаете атомарными действиями (ACI): READ_FILE, EDIT_PATCH, RUN_TESTS, ANALYZE_LOG. Правила: делайте минимальные правки; поясняйте план; не выдумывайте факты; уважайте формат вывода.  [user] Контекст: <описание кейса + фрагменты кода + сообщение об ошибке/тест‑фейл> Цель: исправить баг так, чтобы прошли тесты. Ограничения: изменяйте только указанные файлы; не меняйте API; время ≤ X сек; бюджет токенов ≤ Y.  [assistant] План (шаги): 1) локализую строку/функцию; 2) предложу патч; 3) запущу тесты; если упали — уточню план и повторю.  [assistant → tool] EDIT_PATCH <<<< unified‑diff @@ file.py:42‑50 @@ - return a / b + if b == 0: +     return 0  # safe‑guard + return a / b >>>>  [tool → assistant] RUN_TESTS → FAIL (test_div_zero) LOG: Traceback ... ZeroDivisionError ...  [assistant] Обновляю гипотезу: нужно вернуть специальный код, а не 0. Предлагаю патч v2… 

Теория рядом. Такой промпт прямо «вшивает» ReAct (план→действие→наблюдение), добавляет процесс‑супервизию [3] (объясняй шаги/решения), и готов к self‑consistency: можно параллельно сгенерировать несколько планов и свести их агрегатором. Для async‑режима роли получают свой system‑блок («Ты — Analyst», «Ты — Fixer») и общаются через короткие сообщения‑артефакты.


Как система «решает проблему в реальности» (путь данных)

  1. Загрузка кейса (evaluation/test_cases): исходник+тест/описание фейла.

  2. Планирование (sync или async): формируется трасса шагов и бюджет.

  3. Действия по ACI: чтение/редактирование/запуск тестов/анализ логов (песочница). Именно здесь «чистота» интерфейсов критична: атомарные патчи с диффом и явная диагностика снижают галлюцинации [4].

  4. Верификация (evaluation/patching, тест‑раннер): проходим/падаем → даём агенту наблюдение; для iter‑режима — best‑of‑N по вердиктору.

  5. Аналитика (analytics/results): время, число сообщений, ретраи, успехи/фейлы; сравнение подходов (mas.cli.compare). Это связано с идеями compute‑optimal инференса: считаем не только качество, но и цену/латентность [6].


Примеры (test_cases)

        # Пытаемся вызвать функции с проблемными параметрами         if case['id'] == 1:  # Выход за границы             result = env['calculate_sum']([1, 2, 3])             print(f"❌ НЕОЖИДАННО: код выполнился! Результат: {result}")                      elif case['id'] == 2:  # None обращение             result = env['process_data'](None)             print(f"❌ НЕОЖИДАННО: код выполнился! Результат: {result}")                      elif case['id'] == 3:  # Деление на ноль             result = env['divide'](10, 0)             print(f"❌ НЕОЖИДАННО: код выполнился! Результат: {result}")                      elif case['id'] == 4:  # Несоответствие типов             result = env['add_numbers']('hello', 5)             print(f"❌ НЕОЖИДАННО: код выполнился! Результат: {result}")                      elif case['id'] == 5:  # Неинициализированная переменная             env['count_down'](2)             print("❌ НЕОЖИДАННО: код выполнился без ошибок!")                  except Exception as e:         print(f"✅ ОШИБКА ОБНАРУЖЕНА: {type(e).__name__}: {e}")         print(f"   Это именно та проблема, которую должна решить MAS система!") 

Запуски

# Синхронный/асинхронный прогон (имитация LLM) python -X utf8 -m mas.cli.main --approach sync  --cases 1 2 3 python -X utf8 -m mas.cli.main --approach async --cases 1 2 3  # Реальный LLM через API python -X utf8 -m mas.cli.main --use-openai --openai-model gpt-4 --approach both --cases 1 2 3  # Продвинутый итеративный режим (память и отбор «лучшее из N») python -X utf8 -m mas.cli.iterative  # Сравнение подходов и сводные метрики python -X utf8 -m mas.cli.compare 

«Скриншоты» вывода

SYNC, кейс 1

Запуск СИНХРОННОГО подхода (seed=42) -------------------------------------------------- --- SYNC кейс 1: Выход за границы массива --- ✅ Статус: success    Время: 0.003 сек    Кандидатов: 2    Ретраев: 0 

ASYNC, кейс 1 + сводка

Запуск АСИНХРОННОГО подхода в ПОСЛЕДОВАТЕЛЬНОМ режиме (seed=42) -------------------------------------------------- --- ASYNC кейс 1: Выход за границы массива --- ✅ Статус: success    Время: 0.005 сек    Сообщений: 3/3    Таймауты: 0  ================================================================================ СВОДНЫЙ ОТЧЁТ ПО АНАЛИЗУ ПОДХОДОВ ================================================================================ Общее время выполнения: 2.156 сек Всего обработано кейсов: 10  СИНХРОННЫЙ ПОДХОД:   • Обработано кейсов: 5   • Успешных: 5, Неудачных: 0   • Процент успеха: 100%   • Среднее время: 0.004 сек   • Всего ретраев: 0   • Среднее кандидатов на кейс: 2.0  АСИНХРОННЫЙ ПОДХОД:   • Обработано кейсов: 5   • Успешных: 5, Неудачных: 0, Таймаутов: 0   • Процент успеха: 100%   • Среднее время: 0.008 сек   • Всего сообщений: 15   • Эффективность сообщений: 1.0 ⚡ СРАВНЕНИЕ:   • Быстрее: sync подход   • Разница во времени: 0.004 сек   • Больше успешных: equal   • Разница в успешности: 0 кейсов ================================================================================ 

Мельчайший ACI‑фрагмент

Идея — показать, как связываются действия и обратная связь; конкретные названия функций/классов могут отличаться, что в репозитории.

class ACI:     def read_file(self, path: str) -> str:      # READ_FILE         return fs.read_text(path)      def edit_patch(self, diff: str) -> None:    # EDIT_PATCH (unified diff)         apply_unidiff(diff)      def run_tests(self) -> TestReport:          # RUN_TESTS         return run_pytests_capture()  # Пример шага агента (sync/async одинаково) obs = ACI().read_file("src/module.py") plan = agent.think(obs)                         # ReAct [1] ACI().edit_patch(plan.to_unidiff()) report = ACI().run_tests() if not report.ok:     critique = critic.judge(report)             # процесс‑супервизия [3]     plan = agent.revise(plan, critique) 

Async-оркестратор с реальным LLM (идеологический псевдокод)

# === ключевые компоненты === class LLM:     def ask(role, messages) -> str: ...  # реальный API: chat(messages) → текст/JSON  class ACI:     def read(path) -> str: ...     def patch(unified_diff) -> None: ...     def test() -> Report: ...  # pass/fail, logs  # === сообщения и роли === def bus_emit(topic, payload): ... def fork_variant(payload): ...  # меняем подсказку/температуру → параллельная ветка  def start(case):     bus_emit("plan", case)  def Analyst_on_plan(case):     out = LLM.ask("Analyst", prompt(role="Analyst", ctx=case))   # ReAct [1]     bus_emit("propose_patch", out)  def Fixer_on_propose_patch(plan):     diff = LLM.ask("Fixer", prompt(role="Fixer", ctx=plan))      # минимальный unified diff     ACI.patch(diff)     report = ACI.test()     bus_emit("report_ready", {"report": report, "diff": diff})  def Controller_on_report_ready(payload):     if payload["report"].pass:         bus_emit("done", payload)     elif budget.has_room():         bus_emit("retry", fork_variant(payload))                  # repeated sampling [6]     else:         bus_emit("fail", payload)  def Coordinator_on_retry(payload):     bus_emit("propose_patch", payload)                            # ветка идёт параллельно (mini-MoA [5])  def Coordinator_on_done_or_fail(payload):     persist(payload)                                              # логируем, выбираем best-of-N по тестам 

Мини-шаблон запроса к реальному LLM:

[system] Ты — <ROLE> в команде. Действуешь через ACI: READ_FILE, EDIT_PATCH, RUN_TESTS. [user] Контекст кейса + цель (исправить баг так, чтобы прошли тесты). [assistant] Верни: PLAN и ACTION в JSON (если Fixer — unified diff). 

Идея в трёх строках:
Analyst даёт план/локацию → Fixer делает патч и тест через ACI → Controller решает готово/ветвим попытки; Coordinator параллелит варианты и выбирает лучшее по тестам. Это скрещивает ReAct, ACI, mini-MoA и repeated sampling — подход, который демонстрирует репозиторий кода — https://github.com/iRatG/mas.


Что здесь важно по идее

  • ReAct внутри ролей. Каждая роль строит план → действие (ACI) → наблюдение → ревизию; это снижает галлюцинации и делает шаги проверяемыми (микро-процесс-супервизия) — ролевая версия ReAct [1][3].

  • Явный ACI. Только атомарные действия: read_file / apply_unidiff_patch / run_tests_capture. Это уменьшает «шум CLI», делает обратную связь плотной (линт/логи/дифф) и резко повышает воспроизводимость.

  • Асинхронность как «мини-MoA». Оркестратор параллелит ветви решения: альтернативные планы/патчи (температуры/подсказки). Затем Controller делает best-of-N по вердиктору (тестам). Это сочетает MoA и repeated sampling: больше диверсифицированных кандидатов при контролируемом бюджете [5][6].

  • Бюджеты как контракт. Budget(tokens, time, attempts) — не просто счётчик, а политика остановки/повтора. Для Habr-читателя это ключ к «инженерной дисциплине»: мы управляем ценой и задержкой, а не гонимся вслепую за точностью.

  • Верификатор на двух уровнях. judge_step (микро-PRM: отбрасываем бредовые шаги) и judge_final (юнит-тесты). Там, где юнит-тесты «дырявые», step-judger спасает от тупиков и бешеного роста попыток.

  • Наблюдаемость. corr_id в каждом сообщении, persist_success/failure с логами и диффами — позже это корм для отчётов и «памяти попыток» (ваш продвинутый режим).


Мини-пример промпта (смысл)

[system] Ты — Fixer в мультиагентной команде. Действуй атомарно через ACI: READ_FILE, APPLY_UNIDIFF_PATCH, RUN_TESTS. [developer] Политика: минимальные правки, не трогай API, объясняй мысль коротко. [user] Цель: исправить падение test_div_zero в module.py. Логи и фрагменты кода ниже. [assistant] План: 1) локализация → 2) минимальный unified diff → 3) запуск тестов → 4) ревизия при провале. # Ожидаемый ответ: JSON с полями {rationale, patch_unidiff} 

Мультиагентность в репозитории — это не набор скриптов, а попытка реализации научных идей: ReAct даёт траектории; self‑consistency и MoA — разнообразие гипотез; процесс‑супервизия — контроль качества промежуточных шагов; ACI — плотную связь с реальной средой; итеративность — «масштаб качества» за счёт времени вывода. В сумме получается практичная система, где архитектура объясняет метрики, а метрики — подсказки к архитектуре. Мы оставляем код на минимуме в тексте — всё остальное читатель увидит сам в «репозитории».

Получается, что

мультиагентность — не «мода», а инженерный ответ на сложность: параллелизм гипотез, разделение ролей, проверяемость шагов и экономия за счёт compute‑optimal вывода. MAS соединяют лучшие идеи LLM‑эпохи — ReAct, self‑consistency, процесс‑супервизию [3], MoA, ACI — в практическую дисциплину построения «команд ИИ», которые действительно закрывают задачи. Будущее ИИ‑инженерии — это не один огромный мозг, а оркестр специалистов с хорошим дирижёром и строгим приёмщиком.


Источники

[1] ReAct [1]: Synergizing Reasoning and Acting in Language Models (arXiv:2210.03629).
[2] Self‑Consistency Improves Chain‑of‑Thought Reasoning in Language Models (arXiv:2203.11171).
[3] Let’s Verify Step by Step: Process Supervision via Stepwise Verifiers (PRM/PRM800K) (arXiv:2305.20050).
[4] SWE‑agent: Agent‑Computer Interface для решения задач SWE‑bench (arXiv:2405.15793).
[5] Mixture‑of‑Agents Enhances LLM Capabilities (arXiv:2406.04692).
[6] Large Language Monkeys: Scaling Inference Compute with Repeated Sampling (arXiv:2407.21787).
[7] OpenHands: Real Computer Agents — дизайн, песочницы, делегация (arXiv:2407.16741).
[8] SpecRover: робастная оценка и ловушки бенчмаркинга в программной инженерии (arXiv:2408.02232).
[9] Inference Scaling Laws: Compute‑Optimal Inference для LLM‑решения задач (ICLR’25) (arXiv:2408.00724).
[10] Agents that Matter: практическое руководство по честной оценке ИИ‑агентов (аргументы, риски LLM‑судей, репликабельность) (arXiv:2507.02825).
[11] Обсуждение SWE‑bench и Verified‑вариантов, требования к окружению и метрикам — по материалам [4], [7], [8].
[12] Связанные работы по ToT/дебатам/маршрутизации экспертов и проверке рассуждений — см. обзоры в [5], [6], [9].


ссылка на оригинал статьи https://habr.com/ru/articles/945472/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *