Building an autogen agent team planner coder critic pipeline lets you delegate a coding task to a self-contained loop: one agent maps the problem, another writes the code, a third reviews it before execution. This tutorial walks through a runnable AutoGen setup that plans, implements, and critiques Python without human-in-the-loop, using a group chat to coordinate roles.
Prerequisites
- Python 3.10 or newer
pyautogen0.2.x (pip install pyautogen)python-dotenvfor env vars- An OpenAI-compatible endpoint and API key. Export
OPENAI_API_KEYand optionallyOPENAI_BASE_URL.
python -m venv .venv && source .venv/bin/activate
pip install pyautogen python-dotenv requests
You should be comfortable reading AutoGen GroupChat transcripts. No prior multi-agent experience required.
Configure the LLM client
AutoGen passes a plain dict to the OpenAI SDK. We read from environment to keep secrets out of source.
import os
from dotenv import load_dotenv
load_dotenv()
llm_config = {
"model": os.getenv("MODEL", "gpt-4o-mini"),
"api_key": os.getenv("OPENAI_API_KEY"),
"base_url": os.getenv("OPENAI_BASE_URL", "https://api.openai.com/v1"),
"temperature": 0.2,
}
If you run this in production, point base_url at a gateway that handles provider fallback. n4n.ai exposes one OpenAI-compatible endpoint covering 240+ models and automatically reroutes when a provider is rate-limited, which keeps the agent team from stalling on a single vendor outage.
Define the autogen agent team planner coder critic roles
We instantiate three AssistantAgent instances and one UserProxyAgent that executes code locally.
Planner
The planner outputs a concrete step list and nothing else. Keeping it code-free prevents muddying the chat context.
from autogen import AssistantAgent
planner = AssistantAgent(
name="Planner",
system_message=(
"You are a meticulous planner. Given a task, respond with a numbered "
"step-by-step plan. Never write code. Keep steps under 5."
),
llm_config=llm_config,
)
Coder
The coder consumes the plan and emits a single Python block. Narrow prompts improve adherence.
coder = AssistantAgent(
name="Coder",
system_message=(
"You are a Python expert. Given a plan from the Planner, write clean, "
"runnable Python in a single code block. Include error handling. "
"Do not explain, just code."
),
llm_config=llm_config,
)
Critic
The critic validates logic and security. It can approve or demand a rewrite.
critic = AssistantAgent(
name="Critic",
system_message=(
"You review code for correctness, security, and edge cases. "
"Reply 'APPROVED' or list specific fixes. Be concise."
),
llm_config=llm_config,
)
User proxy
The proxy runs the code and feeds stdout back into the chat. Set human_input_mode="NEVER" for full autonomy.
from autogen import UserProxyAgent
user_proxy = UserProxyAgent(
name="UserProxy",
human_input_mode="NEVER",
max_consecutive_auto_reply=8,
code_execution_config={"work_dir": "autogen_runs", "use_docker": False},
)
Wire the group chat
AutoGen’s GroupChat cycles speakers. We use auto selection so the manager picks the next agent based on context.
from autogen import GroupChat, GroupChatManager
group = GroupChat(
agents=[user_proxy, planner, coder, critic],
messages=[],
max_round=12,
speaker_selection_method="auto",
)
manager = GroupChatManager(groupchat=group, llm_config=llm_config)
To keep the autogen agent team planner coder critic flow strict, replace auto with a custom speaker_fn that enforces Planner → Coder → Critic → UserProxy order. For most tasks, auto works and lets the critic loop back if it rejects code.
Run a concrete task
We ask the team to fetch a public JSON API and extract a field.
task = (
"Task: Fetch https://api.github.com/repos/microsoft/autogen and print "
"the 'stargazers_count' value. Handle network errors."
)
user_proxy.initiate_chat(manager, message=task)
Expected output at checkpoints
After initiation, the Planner replies first:
1. Send GET request to the GitHub API URL.
2. Parse JSON response.
3. Extract 'stargazers_count'.
4. Print the value, catch RequestException.
The Coder then posts:
import requests
try:
r = requests.get("https://api.github.com/repos/microsoft/autogen", timeout=10)
r.raise_for_status()
data = r.json()
print("Stars:", data["stargazers_count"])
except requests.RequestException as e:
print("Error:", e)
The Critic responds:
APPROVED
The UserProxy executes the block. Since requests is installed, you’ll see the star count:
Stars: 28000
(Exact number varies; GitHub updates live.) If the Critic had flagged missing timeout, the Coder would iterate. That loop is the core value of the autogen agent team planner coder critic pattern: the review gate catches naive mistakes before execution.
Strict speaker ordering
For deterministic pipelines, define a fixed handoff:
def speaker_fn(last_speaker, group):
order = [planner, coder, critic, user_proxy]
if last_speaker is None:
return planner
idx = order.index(last_speaker)
return order[(idx + 1) % len(order)]
group = GroupChat(
agents=[user_proxy, planner, coder, critic],
messages=[],
max_round=12,
speaker_fn=speaker_fn,
)
This guarantees the planner never sees raw code before it has planned, and the critic always reviews before the proxy runs anything.
Handling execution failures
If the code raises ModuleNotFoundError or the API times out, the UserProxy returns the traceback as a message. The Critic sees it and can instruct the Coder to add a fallback or pip install note. Because max_consecutive_auto_reply is set, the loop will retry until approval or round limit.
Example failure message from proxy:
Exit code: 1
Traceback (most recent call last):
File "solution.py", line 1, in <module>
import requests
ModuleNotFoundError: No module named 'requests'
The Critic would reply: Add 'import subprocess; subprocess.run(["pip","install","requests"])' or document dependency. The Coder then amends.
Termination condition
Stop the chat when the task is verified done. Combine critic approval and successful stdout:
def is_done(msg):
content = msg.get("content", "")
return "APPROVED" in content and "Stars:" in content
group = GroupChat(
agents=[user_proxy, planner, coder, critic],
messages=[],
max_round=12,
speaker_fn=speaker_fn,
termination_condition=is_done,
)
Why role separation matters
A single agent prompted to “plan, code, and review” will truncate the review step when context fills. Splitting the autogen agent team planner coder critic responsibilities forces explicit handoffs. Each agent has a narrow system prompt, which improves adherence and makes the transcript debuggable. You can swap the coder model for a cheaper one and keep a strong critic.
Production notes
Log the group chat messages to JSON for audit. Meter token usage via your endpoint’s per-token billing—if you use a gateway, per-token usage metering lets you attribute cost to each role by tagging the model field. Honor provider cache-control hints to cut repeat planning costs on similar tasks.
That is the full loop. You now have a runnable multi-agent coding crew that plans, implements, and self-reviews.