Введение: мир, где одному ИИ тесно
Софт стал распределённым организмом: микросервисы, бесконечные 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 используют системно:
-
Время на вывод (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») и общаются через короткие сообщения‑артефакты.
Как система «решает проблему в реальности» (путь данных)
-
Загрузка кейса (
evaluation/test_cases): исходник+тест/описание фейла. -
Планирование (
syncилиasync): формируется трасса шагов и бюджет. -
Действия по ACI: чтение/редактирование/запуск тестов/анализ логов (песочница). Именно здесь «чистота» интерфейсов критична: атомарные патчи с диффом и явная диагностика снижают галлюцинации [4].
-
Верификация (
evaluation/patching, тест‑раннер): проходим/падаем → даём агенту наблюдение; для iter‑режима — best‑of‑N по вердиктору. -
Аналитика (
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/
Добавить комментарий