Проблема: кто говорит следующим?
В диалоге двух агентов маршрутизация тривиальна — реплики ходят туда-обратно. Но добавь третьего, и появляется развилка: после того как исследователь выдал факты, кто продолжит — аналитик (считать) или критик (проверять)? Если просто пустить всех «по кругу», получится неестественно: критику нечего проверять, пока аналитик не сделал выводы.
Значит, групповому разговору нужен ведущий — тот, кто после каждой реплики решает, чья очередь. Это та же роль супервайзера из модуля 03, только в разговорной парадигме AutoGen: не маршрутизатор графа, а «модератор беседы».
AutoGen разбивает задачу на две сущности: GroupChat — это сам «чат-рум»: список участников и общая история сообщений. GroupChatManager — ведущий, который этим чатом управляет: после каждого хода выбирает следующего спикера и передаёт ему слово. Агенты разговаривают не друг с другом напрямую, а «через комнату».
Как устроен групповой разговор
Механика такая: все агенты сложены в GroupChat с общей историей. GroupChatManager запускает разговор и крутит цикл: выбрать спикера → дать ему слово → его реплика попадает в общую историю → выбрать следующего — пока не сработает условие завершения.
Стратегии выбора спикера
Самое важное в GroupChat — как менеджер выбирает следующего говорящего. Это задаётся параметром speaker_selection_method:
allowed_or_disallowed_speaker_transitions).Начинай с того, что предсказуемо. Если порядок ролей известен (исследователь → аналитик → писатель → критик), round_robin проще, дешевле и стабильнее, чем гонять LLM-менеджер на каждом ходу. "auto" бери, когда порядок реально зависит от контента и не фиксирован заранее. А чтобы LLM-менеджер не «промахивался», ограничь допустимые переходы между спикерами — это резко повышает управляемость.
Полный пример: команда в групповом чате
from autogen import AssistantAgent, UserProxyAgent, GroupChat, GroupChatManager
llm_config = {"model": "gpt-4o-mini", "api_key": "sk-..."}
# --- участники (узкие роли — привет уроку про специализацию) ---
researcher = AssistantAgent(name="researcher", llm_config=llm_config,
system_message="Ты исследователь. Находи факты по теме.")
analyst = AssistantAgent(name="analyst", llm_config=llm_config,
system_message="Ты аналитик. Делай выводы из фактов.")
writer = AssistantAgent(name="writer", llm_config=llm_config,
system_message="Ты писатель. Оформи выводы. В конце напиши TERMINATE.")
user_proxy = UserProxyAgent(name="user_proxy", human_input_mode="NEVER",
code_execution_config=False,
is_termination_msg=lambda m: "TERMINATE" in (m.get("content") or ""))
# --- чат-рум: все участники + общая история ---
groupchat = GroupChat(
agents=[user_proxy, researcher, analyst, writer],
messages=[],
max_round=12, # предохранитель: всего ходов в чате
speaker_selection_method="round_robin" # по очереди (предсказуемо)
)
# --- ведущий: рулит чатом ---
manager = GroupChatManager(groupchat=groupchat, llm_config=llm_config)
# Запуск: user_proxy открывает обсуждение через менеджера
user_proxy.initiate_chat(
manager,
message="Подготовь короткий обзор рынка электромобилей 2025.",
)
Что происходит: user_proxy отдаёт задачу менеджеру, тот по очереди даёт слово researcher → analyst → writer; каждый видит всю предыдущую историю чата и добавляет своё; writer в конце пишет TERMINATE — обсуждение закрывается. Агенты не вызывают друг друга — они «переписываются в общем чате» под управлением менеджера.
Завершение и предохранители
Групповой чат — это потенциально длинный цикл из многих LLM-вызовов, поэтому пределы здесь критичнее, чем в диалоге двоих:
max_round— общий лимит ходов в чате. Главный предохранитель: достигли — чат закрывается принудительно.is_termination_msg— осмысленное завершение: кто-то из участников (обычно финальный — writer) сигналитTERMINATE.- Согласованность с промптами — если завершение по
TERMINATE, то вsystem_messageтого, кто должен закончить, явно сказано это слово писать.
Каждый ход — это вызов LLM участника, а при "auto" ещё и вызов менеджера на выбор спикера. Чат из 4 агентов на 10 раундов — это десятки обращений к модели. Плюс агенты могут уйти в «болтовню» (поддакивать друг другу), не двигая задачу. Держи max_round небольшим, роли — узкими, и предпочитай round_robin, если порядок известен. Это прямое следствие урока «когда НЕ нужны мультиагенты»: групповой чат оправдан, когда ролей реально несколько.
GroupChat против графа
Полезно соотнести с тем, что мы знаем из модуля 03. GroupChat в AutoGen и Supervisor в LangGraph решают одну задачу — координацию многих агентов, — но по-разному:
| Критерий | AutoGen GroupChat | LangGraph Supervisor |
|---|---|---|
| Парадигма | разговор в общем чате | граф: узлы и рёбра |
| Выбор следующего | менеджер (auto/round_robin) | условное ребро по next |
| Общий контекст | история сообщений чата | state (messages + поля) |
| Контроль потока | проще начать, менее явный | явная структура, точный контроль |
Это вопрос вкуса и задачи, а не «лучше/хуже». AutoGen приятнее, когда координация естественно ложится на «обсуждение» и хочется быстро поднять команду. LangGraph выигрывает, когда нужен точный, воспроизводимый поток управления с явными переходами и состоянием. Многие в проде комбинируют идеи обоих.
Типичные ошибки
Без лимита ходов групповой чат может крутиться долго и дорого. max_round — обязательный предохранитель; задавай его небольшим.
LLM-менеджер на «auto» может выбирать спикеров хаотично и зацикливать двоих. Ограничь допустимые переходы или возьми round_robin, если порядок известен.
Если у агентов пересекающиеся system_message, менеджер путается, кому дать слово, а агенты дублируют работу. Роли в чате должны быть узкими и разными.
Если завершение завязано на TERMINATE, но ни в одном системном промпте это слово не упомянуто, чат не остановится «по смыслу» и упрётся только в max_round. Назначь финального агента и пропиши ему сигнал.
Шпаргалка
from autogen import GroupChat, GroupChatManager
# GroupChat = чат-рум: участники + общая история
# GroupChatManager = ведущий: после каждого хода выбирает спикера
groupchat = GroupChat(
agents=[user_proxy, researcher, analyst, writer],
messages=[],
max_round=12, # ПРЕДОХРАНИТЕЛЬ (обязателен)
speaker_selection_method="round_robin", # auto | round_robin | manual | своя
)
manager = GroupChatManager(groupchat=groupchat, llm_config=llm_config)
# запускает тот, у кого задача — через МЕНЕДЖЕРА (не напрямую к агенту)
user_proxy.initiate_chat(manager, message="...")
# ВЫБОР СПИКЕРА:
# "auto" — менеджер решает через LLM (гибко, недетерминированно, дороже)
# "round_robin" — по очереди (предсказуемо, дёшево) ← начни с него
# "manual" — выбирает человек
# transitions — ограничь, кто после кого может говорить
# Правила:
# • ВСЕГДА max_round; завершение по TERMINATE у финального агента
# • узкие, непересекающиеся роли участников
# • порядок известен → round_robin; "auto" → ограничивай переходы
# • группа дороже пары → роли и раунды держи компактными
Практическое задание
Собери команду в групповом чате:
Задание: обзор силами команды
- Создай 3–4 агента с узкими ролями (например,
researcher,analyst,writer) +user_proxy. Убедись, чтоsystem_messageне пересекаются. - Собери
GroupChatсmax_roundиspeaker_selection_method="round_robin", оберни вGroupChatManager, запусти черезuser_proxy.initiate_chat(manager, ...). - Проследи по логу, что слово идёт по очереди и каждый видит историю предыдущих. Где writer ставит
TERMINATE? - Переключи
speaker_selection_methodна"auto"и сравни: стал ли порядок осмысленнее или, наоборот, хаотичнее? Во сколько примерно вырос расход вызовов? - Намеренно убери
max_round(или поставь очень большим) и понаблюдай, как чат тянется/зацикливается — верни предохранитель. - Со звёздочкой: добавь агента-критика и ограничь переходы так, чтобы критик говорил только после писателя, и при его замечаниях слово возвращалось писателю.
Что дальше
Ты умеешь собирать и пару, и целую команду в чате. Один из самых ценных навыков AutoGen — автоматическое выполнение кода агентами (мы его касались с UserProxy). Следующий урок — про code execution детально: как, где и насколько безопасно агенты запускают код.