Проблема: кто говорит следующим?

В диалоге двух агентов маршрутизация тривиальна — реплики ходят туда-обратно. Но добавь третьего, и появляется развилка: после того как исследователь выдал факты, кто продолжит — аналитик (считать) или критик (проверять)? Если просто пустить всех «по кругу», получится неестественно: критику нечего проверять, пока аналитик не сделал выводы.

Значит, групповому разговору нужен ведущий — тот, кто после каждой реплики решает, чья очередь. Это та же роль супервайзера из модуля 03, только в разговорной парадигме AutoGen: не маршрутизатор графа, а «модератор беседы».

ℹ️ GroupChat = чат + модератор

AutoGen разбивает задачу на две сущности: GroupChat — это сам «чат-рум»: список участников и общая история сообщений. GroupChatManager — ведущий, который этим чатом управляет: после каждого хода выбирает следующего спикера и передаёт ему слово. Агенты разговаривают не друг с другом напрямую, а «через комнату».

Как устроен групповой разговор

Механика такая: все агенты сложены в GroupChat с общей историей. GroupChatManager запускает разговор и крутит цикл: выбрать спикера → дать ему слово → его реплика попадает в общую историю → выбрать следующего — пока не сработает условие завершения.

100%
колёсико — масштаб  ·  зажать и тянуть — перемещение
GroupChatManager выбирает спикера GroupChat · общая история все сообщения видны всем участникам researcher ищет факты analyst делает выводы writer оформляет critic проверяет выбранный говорит → цикл: manager выбирает спикера → тот пишет в общую историю → следующий выбор

Стратегии выбора спикера

Самое важное в GroupChatкак менеджер выбирает следующего говорящего. Это задаётся параметром speaker_selection_method:

"auto" (по умолчанию)
Менеджер сам — через LLM — решает, кто уместнее говорить дальше, по контексту. Гибко, но недетерминированно и стоит лишнего вызова модели.
"round_robin"
Строго по очереди, по списку участников. Предсказуемо и дёшево — когда порядок ролей фиксирован (конвейер).
"manual"
Спикера на каждом ходу выбирает человек. Максимум контроля, для отладки и важных решений.
своя функция / переходы
Можно задать кастомную логику выбора или ограничить, кто после кого может говорить (allowed_or_disallowed_speaker_transitions).
auto — гибко, round_robin — надёжно

Начинай с того, что предсказуемо. Если порядок ролей известен (исследователь → аналитик → писатель → критик), round_robin проще, дешевле и стабильнее, чем гонять LLM-менеджер на каждом ходу. "auto" бери, когда порядок реально зависит от контента и не фиксирован заранее. А чтобы LLM-менеджер не «промахивался», ограничь допустимые переходы между спикерами — это резко повышает управляемость.

Полный пример: команда в групповом чате

GroupChat + GroupChatManager
python
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 выигрывает, когда нужен точный, воспроизводимый поток управления с явными переходами и состоянием. Многие в проде комбинируют идеи обоих.

Типичные ошибки

Ошибка 1: нет max_round

Без лимита ходов групповой чат может крутиться долго и дорого. max_round — обязательный предохранитель; задавай его небольшим.

Ошибка 2: "auto" без ограничений переходов

LLM-менеджер на «auto» может выбирать спикеров хаотично и зацикливать двоих. Ограничь допустимые переходы или возьми round_robin, если порядок известен.

Ошибка 3: размытые роли участников

Если у агентов пересекающиеся system_message, менеджер путается, кому дать слово, а агенты дублируют работу. Роли в чате должны быть узкими и разными.

Ошибка 4: TERMINATE некому сказать

Если завершение завязано на TERMINATE, но ни в одном системном промпте это слово не упомянуто, чат не остановится «по смыслу» и упрётся только в max_round. Назначь финального агента и пропиши ему сигнал.

Шпаргалка

GroupChat — всё в одном месте
python
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" → ограничивай переходы
#  • группа дороже пары → роли и раунды держи компактными

Практическое задание

Собери команду в групповом чате:

Задание: обзор силами команды

  1. Создай 3–4 агента с узкими ролями (например, researcher, analyst, writer) + user_proxy. Убедись, что system_message не пересекаются.
  2. Собери GroupChat с max_round и speaker_selection_method="round_robin", оберни в GroupChatManager, запусти через user_proxy.initiate_chat(manager, ...).
  3. Проследи по логу, что слово идёт по очереди и каждый видит историю предыдущих. Где writer ставит TERMINATE?
  4. Переключи speaker_selection_method на "auto" и сравни: стал ли порядок осмысленнее или, наоборот, хаотичнее? Во сколько примерно вырос расход вызовов?
  5. Намеренно убери max_round (или поставь очень большим) и понаблюдай, как чат тянется/зацикливается — верни предохранитель.
  6. Со звёздочкой: добавь агента-критика и ограничь переходы так, чтобы критик говорил только после писателя, и при его замечаниях слово возвращалось писателю.

Что дальше

Ты умеешь собирать и пару, и целую команду в чате. Один из самых ценных навыков AutoGen — автоматическое выполнение кода агентами (мы его касались с UserProxy). Следующий урок — про code execution детально: как, где и насколько безопасно агенты запускают код.