AutoGen GroupChat: Coordinating Multiple AI Agents
AutoGen GroupChat is a powerful orchestration pattern that allows multiple AI agents to collaborate in a shared conversation space to solve complex tasks. Instead of rigid, predefined pipelines, GroupChat enables dynamic, multi-turn discussions where agents with different roles, tools, and expertise can interact naturally to arrive at better solutions.
What Is AutoGen GroupChat?
At its core, GroupChat is a conversation manager that hosts multiple agents in a single chat thread. Each agent can be a different AI model, have access to different tools, or be assigned a specific role (like a planner, critic, coder, or reviewer). The GroupChat manager orchestrates the flow by selecting which agent speaks next based on configurable rules, allowing for emergent collaboration patterns that often outperform single-agent approaches.
Key components of the GroupChat architecture include:
- GroupChat object – defines the shared conversation container, holding the list of participants and the message history
- GroupChatManager – the orchestrator that selects the next speaker based on a speaker selection strategy
- Speaker selection function – a customizable callable that decides which agent speaks next (can be rule-based, LLM-based, or custom logic)
- Participating agents – individual ConversableAgent instances, each with their own system prompts, tools, and capabilities
Why GroupChat Matters
Single-agent systems often struggle with complex, multi-step tasks that require diverse skills. A coding agent might write great code but miss edge cases; a reviewer agent catches bugs but can't execute fixes. GroupChat solves this by enabling:
- Division of labor – assign planning, coding, testing, and reviewing to specialized agents
- Built-in critique and refinement – agents challenge each other's outputs, leading to higher quality results
- Dynamic tool access – only certain agents need code execution or search capabilities, reducing noise
- Emergent collaboration – agents can ask each other questions, request clarification, or delegate sub-tasks
- Reduced single-point-of-failure – if one agent produces a poor output, others can catch and correct it
This pattern shines in scenarios like complex software development, data analysis pipelines, creative writing with editing rounds, and multi-step research tasks where different perspectives lead to more robust outcomes.
Setting Up a Basic GroupChat
Let's walk through a complete example of setting up a GroupChat with three agents: a Planner, a Coder, and a Reviewer. This team will collaboratively solve a programming task.
Step 1: Install AutoGen
pip install pyautogen
Step 2: Configure the LLM
Create a configuration for your LLM endpoint. Here we use OpenAI, but AutoGen supports many providers.
import autogen
config_list = [
{
"model": "gpt-4",
"api_key": "your-openai-api-key-here",
"temperature": 0.7,
}
]
Step 3: Define Specialized Agents
Each agent gets a distinct system message that defines its role, personality, and constraints. The Planner strategizes, the Coder implements, and the Reviewer critiques.
planner = autogen.AssistantAgent(
name="Planner",
system_message="""You are a senior software architect and task planner.
Your role is to:
1. Analyze the user's request carefully
2. Break down complex tasks into clear, actionable steps
3. Propose a high-level plan before any code is written
4. Delegate coding tasks to the Coder agent with precise specifications
5. Do NOT write code yourself — focus on planning and coordination
When the task is complete, say 'PLAN_COMPLETE' to signal readiness for review.""",
llm_config={"config_list": config_list},
)
coder = autogen.AssistantAgent(
name="Coder",
system_message="""You are an expert Python developer.
Your role is to:
1. Receive specifications from the Planner
2. Write clean, well-documented, production-quality Python code
3. Include error handling and edge case coverage
4. Provide complete, runnable code blocks (not fragments)
5. Explain your implementation choices briefly
Only write code when the Planner has given you a clear specification.
When finished, say 'CODE_COMPLETE'.""",
llm_config={"config_list": config_list},
)
reviewer = autogen.AssistantAgent(
name="Reviewer",
system_message="""You are a meticulous code reviewer and quality assurance specialist.
Your role is to:
1. Review all code produced by the Coder
2. Check for bugs, security issues, performance problems, and style violations
3. Verify that the code matches the Planner's specification
4. Suggest concrete improvements
5. If code passes review, say 'APPROVED' and summarize what was accomplished
6. If issues are found, clearly list them so the Coder can fix them""",
llm_config={"config_list": config_list},
)
Step 4: Create the GroupChat and Manager
The GroupChat holds all agents and the message history. The GroupChatManager orchestrates the conversation using a speaker selection function.
from autogen import GroupChat, GroupChatManager
# Create the group chat with all participating agents
group_chat = GroupChat(
agents=[planner, coder, reviewer],
messages=[], # Will be populated as the conversation proceeds
max_round=15, # Safety limit to prevent infinite loops
speaker_selection_method="auto", # LLM-based speaker selection
allow_repeat_speaker=True, # Allow the same agent to speak consecutively if needed
)
# Create the manager that orchestrates the conversation
manager = GroupChatManager(
groupchat=group_chat,
llm_config={"config_list": config_list},
)
Step 5: Initiate the Conversation
A user proxy agent represents the human user and initiates the task. It can also execute code on behalf of agents when needed.
user_proxy = autogen.UserProxyAgent(
name="User",
system_message="You are the human user with the ability to execute Python code.",
code_execution_config={"work_dir": "coding_workspace", "use_docker": False},
human_input_mode="NEVER", # Fully automated; set to "TERMINATE" for human approval at end
)
# Start the group chat with a task
user_proxy.initiate_chat(
manager,
message="""
I need a Python script that:
1. Fetches data from a public API (https://api.github.com/repos/microsoft/autogen)
2. Parses the JSON response to extract: repo name, star count, open issues count, and primary language
3. Saves the extracted data to a local CSV file
4. Includes proper error handling for network failures and invalid responses
Please plan, code, and review this solution.
""",
)
Custom Speaker Selection Strategies
The default "auto" speaker selection uses an LLM to decide who speaks next, but you can implement custom logic for more control. Here are three common patterns:
Pattern 1: Strict Turn-Based Rotation
Useful when you want a predictable, pipeline-like flow (Planner → Coder → Reviewer → repeat).
def rotation_speaker_selection(last_speaker, group_chat):
"""Rotate through agents in a fixed order."""
agents = group_chat.agents
# Define the rotation order
order = ["Planner", "Coder", "Reviewer"]
# Find the index of the last speaker
try:
last_index = order.index(last_speaker.name) if last_speaker else -1
except ValueError:
last_index = -1
# Pick the next agent in rotation
next_index = (last_index + 1) % len(order)
return agents[group_chat.agent_names.index(order[next_index])]
group_chat = GroupChat(
agents=[planner, coder, reviewer],
messages=[],
max_round=15,
speaker_selection_method=rotation_speaker_selection,
)
Pattern 2: Role-Based Conditional Selection
Route messages based on content signals like "CODE_COMPLETE" or "APPROVED".
def conditional_speaker_selection(last_speaker, group_chat):
"""Select next speaker based on the content of the last message."""
if last_speaker is None:
return group_chat.agents_by_name("Planner")
last_message = group_chat.messages[-1]["content"] if group_chat.messages else ""
# After planning, route to coder
if "PLAN_COMPLETE" in last_message and last_speaker.name == "Planner":
return group_chat.agents_by_name("Coder")
# After coding, route to reviewer
elif "CODE_COMPLETE" in last_message and last_speaker.name == "Coder":
return group_chat.agents_by_name("Reviewer")
# If approved, stop or route back to user
elif "APPROVED" in last_message:
return None # End conversation
# If reviewer found issues, send back to coder
elif last_speaker.name == "Reviewer" and "APPROVED" not in last_message:
return group_chat.agents_by_name("Coder")
# Default: planner decides next steps
else:
return group_chat.agents_by_name("Planner")
group_chat = GroupChat(
agents=[planner, coder, reviewer],
messages=[],
max_round=15,
speaker_selection_method=conditional_speaker_selection,
)
Pattern 3: LLM-Based with Constraints
Use an LLM for nuanced decisions but restrict which agents are eligible based on context.
def constrained_llm_selection(last_speaker, group_chat):
"""Use LLM selection but restrict eligible speakers."""
# After the coder speaks, only the reviewer or planner can speak next
if last_speaker and last_speaker.name == "Coder":
eligible = ["Reviewer", "Planner"]
# Use a helper to pick among eligible agents via LLM
return autogen.speaker_selection.message_speaker_selection(
last_speaker, group_chat, eligible_agents=eligible
)
# Otherwise use default auto selection
return "auto"
group_chat = GroupChat(
agents=[planner, coder, reviewer],
messages=[],
max_round=15,
speaker_selection_method=constrained_llm_selection,
)
Advanced GroupChat Features
Integrating Tool-Using Agents
You can give specific agents access to tools like code execution, web search, or database queries. Here's how to equip the Coder with code execution capability:
coder_with_tools = autogen.AssistantAgent(
name="Coder",
system_message="""You are an expert Python developer with code execution abilities.
Write complete Python scripts and use the code_execution tool to run and verify them.""",
llm_config={"config_list": config_list},
code_execution_config={
"work_dir": "coding_workspace",
"use_docker": False,
"timeout": 60,
},
)
# The user proxy can also execute code requested by agents
user_proxy_with_exec = autogen.UserProxyAgent(
name="CodeExecutor",
system_message="You execute Python code and return results.",
code_execution_config={"work_dir": "coding_workspace", "use_docker": False},
human_input_mode="NEVER",
)
Adding a Critic with Different Model
Use a different, potentially more capable model for the reviewer to provide higher-quality feedback:
reviewer_config_list = [
{
"model": "gpt-4-turbo",
"api_key": "your-openai-api-key-here",
"temperature": 0.2, # Lower temperature for more consistent reviews
}
]
expert_reviewer = autogen.AssistantAgent(
name="ExpertReviewer",
system_message="""You are an elite code reviewer powered by GPT-4 Turbo.
Provide deep, insightful feedback on code quality, architecture, and best practices.""",
llm_config={"config_list": reviewer_config_list},
)
Nested GroupChats for Complex Workflows
For very complex tasks, you can nest a GroupChat inside another agent's logic. For example, a research agent could spawn a sub-group-chat for literature review:
research_sub_team = GroupChat(
agents=[researcher_agent, fact_checker_agent, synthesizer_agent],
messages=[],
max_round=8,
speaker_selection_method="auto",
)
def research_orchestrator_logic(agent, messages):
"""Custom agent that spawns a sub-group-chat for research tasks."""
sub_manager = GroupChatManager(groupchat=research_sub_team, llm_config=config_list)
# Run the sub-chat and collect results
result = user_proxy.initiate_chat(sub_manager, message=messages[-1]["content"])
return True, f"Research complete. Findings: {result}"
research_orchestrator = autogen.AssistantAgent(
name="ResearchOrchestrator",
system_message="You coordinate research sub-teams.",
llm_config={"config_list": config_list},
)
Best Practices for GroupChat
- Keep agent roles distinct and narrow – overlapping responsibilities create confusion. Each agent should have a clear, unique purpose spelled out in its system message.
- Use explicit termination signals – define clear keywords like "APPROVED", "COMPLETE", or "TERMINATE" so the conversation doesn't loop indefinitely. Combine this with
max_roundas a safety net. - Start with a simple speaker selection strategy – begin with "auto" or a simple rotation, then refine based on observed behavior. Over-engineered selection logic can create deadlocks.
- Log and observe conversations – enable verbose logging to understand the flow. Adjust agent prompts and selection logic based on real interaction patterns.
- Set appropriate temperature values – use lower temperatures (0.0–0.3) for reviewers and code generators; higher temperatures (0.5–0.8) for planners and creative agents.
- Limit the number of agents – 3 to 5 agents usually works best. Too many agents cause fragmented conversations and higher costs.
- Use
max_roundgenerously but not infinitely – set it high enough to complete the task (e.g., 15–20) but low enough to catch runaway loops early in development. - Consider cost implications – each round invokes one or more LLM calls. For cost-sensitive applications, use cheaper models for simpler agents and reserve expensive models for critical roles like review.
- Test with varied inputs – run your GroupChat setup against a diverse set of tasks to ensure the speaker selection logic generalizes well.
- Implement graceful fallbacks – if the conversation hits
max_roundwithout resolution, have a fallback agent summarize partial progress rather than losing all context.
Complete Working Example
Here's a fully self-contained script that implements a Planner-Coder-Reviewer GroupChat. Save it as groupchat_demo.py and run it with your API key.
import autogen
from autogen import GroupChat, GroupChatManager
# ---------- CONFIGURATION ----------
config_list = [
{
"model": "gpt-4",
"api_key": "sk-YOUR-API-KEY-HERE",
"temperature": 0.7,
}
]
# ---------- AGENT DEFINITIONS ----------
planner = autogen.AssistantAgent(
name="Planner",
system_message="""You are a senior software architect.
Your job: analyze the task, create a step-by-step plan, delegate to the Coder.
Never write code. End your turn with PLAN_COMPLETE when the plan is ready.""",
llm_config={"config_list": config_list},
)
coder = autogen.AssistantAgent(
name="Coder",
system_message="""You are an expert Python developer.
Write complete, runnable Python scripts based on the Planner's specification.
Include error handling, comments, and edge case handling.
End your turn with CODE_COMPLETE when done.""",
llm_config={"config_list": config_list},
)
reviewer = autogen.AssistantAgent(
name="Reviewer",
system_message="""You are a thorough code reviewer.
Check the code against the plan. Look for bugs, security issues, and style problems.
If the code passes, say APPROVED and summarize.
If it fails, list specific issues for the Coder to fix.""",
llm_config={"config_list": config_list, "temperature": 0.2},
)
user_proxy = autogen.UserProxyAgent(
name="User",
code_execution_config={"work_dir": "workspace", "use_docker": False},
human_input_mode="NEVER",
)
# ---------- SPEAKER SELECTION ----------
def smart_speaker_selection(last_speaker, group_chat):
"""Route based on conversation signals."""
if last_speaker is None:
return group_chat.agents_by_name("Planner")
last_msg = group_chat.messages[-1]["content"]
name = last_speaker.name
if "PLAN_COMPLETE" in last_msg and name == "Planner":
return group_chat.agents_by_name("Coder")
elif "CODE_COMPLETE" in last_msg and name == "Coder":
return group_chat.agents_by_name("Reviewer")
elif "APPROVED" in last_msg:
return None # Stop the conversation
elif name == "Reviewer" and "APPROVED" not in last_msg:
return group_chat.agents_by_name("Coder")
else:
return group_chat.agents_by_name("Planner")
# ---------- GROUP CHAT SETUP ----------
group_chat = GroupChat(
agents=[planner, coder, reviewer],
messages=[],
max_round=20,
speaker_selection_method=smart_speaker_selection,
allow_repeat_speaker=True,
)
manager = GroupChatManager(
groupchat=group_chat,
llm_config={"config_list": config_list},
)
# ---------- LAUNCH ----------
task = """
Create a Python script that:
1. Connects to a SQLite database (create it if it doesn't exist)
2. Creates a table 'employees' with columns: id, name, department, salary
3. Inserts 5 sample employee records
4. Queries and prints all employees in the 'Engineering' department
5. Calculates and prints the average salary across all employees
Use proper error handling and close database connections cleanly.
"""
user_proxy.initiate_chat(manager, message=task)
Handling Errors and Edge Cases
GroupChat conversations can encounter several failure modes. Here's how to handle them robustly:
import logging
# Enable detailed logging to debug conversation flow
logging.basicConfig(level=logging.INFO)
autogen.logging.basicConfig(level=autogen.logging.INFO)
# Wrap the conversation in try/except
try:
result = user_proxy.initiate_chat(
manager,
message="Your complex task here",
max_turns=30, # Additional safety limit on total turns
)
except Exception as e:
print(f"GroupChat failed: {e}")
# Fallback: extract partial results from group_chat.messages
partial_output = group_chat.messages
print(f"Partial conversation saved with {len(partial_output)} messages")
# You can parse partial_output for any usable artifacts
Conclusion
AutoGen GroupChat transforms AI agent systems from single-prompt interactions into rich, collaborative multi-agent workflows. By assigning specialized roles, implementing thoughtful speaker selection strategies, and following best practices around agent design and conversation limits, you can build systems that plan, execute, critique, and refine — producing outputs that are more robust, more accurate, and more nuanced than any single agent could achieve alone. Start with simple configurations, observe the emergent behaviors, and iteratively refine your agent team. The patterns you develop will form the backbone of sophisticated AI-powered automation pipelines.