Введение: мир, где одному ИИ тесно
Софт стал распределённым организмом: микросервисы, бесконечные 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].
Автор: AyratGil
