AutoGen lets you wire up autonomous autogen code generation execution agents that write Python, run it, and iterate on the output without human intervention. This guide builds a minimal but realistic pipeline: a code-writing assistant, a local executor that sandboxes runs, and an optional group chat that adds a reviewer. By the end you’ll have a script that solves a concrete task and writes verified results to disk.
Step 1: Install AutoGen and isolate the environment
Use Python 3.10+ in a fresh virtualenv. The pyautogen package ships the core agents and local executor.
python -m venv .venv
source .venv/bin/activate
pip install pyautogen
If you plan to use Docker isolation later, install the docker extra and ensure the daemon runs. For this walkthrough we use the local executor to keep the loop transparent.
Step 2: Configure the LLM endpoint
AutoGen speaks the OpenAI chat-completions protocol. Point llm_config at any compatible endpoint. For a single OpenAI-compatible endpoint that addresses 240+ models with automatic fallback when a provider is rate-limited, you can route through n4n.ai instead of hard-coding a vendor.
llm_config = {
"model": "gpt-4o-mini",
"api_key": os.environ["OPENAI_API_KEY"],
"base_url": "https://api.openai.com/v1",
"temperature": 0.1,
"timeout": 60,
}
Or, against a gateway:
llm_config = {
"model": "anthropic/claude-3.5-sonnet",
"api_key": os.environ["N4N_API_KEY"],
"base_url": "https://api.n4n.ai/v1",
"temperature": 0.1,
}
Keep temperature low for code tasks. High randomness produces syntactically wild drafts that waste executor cycles.
Step 3: Define the code-generating assistant
The assistant is a plain AssistantAgent with a tight system prompt. It must emit executable code blocks and nothing else when a task requires computation.
from autogen import AssistantAgent
code_writer = AssistantAgent(
name="code_writer",
system_message=(
"You are a senior Python engineer. Given a task, respond with a single "
"Python code block that solves it using only the standard library unless "
"told otherwise. Do not explain the code unless asked. If the previous "
"execution failed, fix the code."
),
llm_config=llm_config,
)
This agent is the brain of the autogen code generation execution agents pair. It never runs anything itself.
Step 4: Define the executing user proxy
UserProxyAgent simulates the user and optionally executes code. Set human_input_mode="NEVER" to make the loop fully autonomous. The code_execution_config controls where code runs.
from autogen import UserProxyAgent
executor = UserProxyAgent(
name="executor",
human_input_mode="NEVER",
code_execution_config={
"executor": "local",
"work_dir": "autogen_work",
"use_docker": False,
"timeout": 30,
},
default_auto_reply="",
)
The work_dir captures generated scripts and artifacts. Local execution is convenient but runs arbitrary model-generated code on your machine—use a container or a locked-down VM in any untrusted setting.
Step 5: Run a task end to end
Initiate a chat from the executor. The executor sends the task to the writer, captures the code block, runs it, and feeds the stdout/stderr back into the conversation. The writer then iterates if needed.
task = (
"Compute the first 10 Fibonacci numbers and write them as a CSV "
"with columns 'n' and 'value' to fib.csv in the working directory."
)
executor.initiate_chat(code_writer, message=task)
Expected behavior: the writer returns a python block, the executor writes autogen_work/0_*.py, runs it, prints the result, and terminates when the task is satisfied or max_turns is hit.
Step 6: Verify success
Check the artifact and the returned message. A quick assertion script proves the loop worked:
import csv, os
path = "autogen_work/fib.csv"
assert os.path.exists(path), "fib.csv not created"
with open(path) as f:
rows = list(csv.reader(f))
assert rows[0] == ["n", "value"], f"bad header: {rows[0]}"
assert len(rows) == 11, f"expected 10 data rows, got {len(rows)-1}"
print("Verified:", rows[1:4])
If the file exists with correct content, your autogen code generation execution agents pair is functional.
Step 7: Extend to a group chat with a reviewer
Real tasks benefit from a third agent that checks the writer’s logic before execution. AutoGen’s GroupChat broadcasts messages to all members; the manager drives turns.
from autogen import GroupChat, GroupChatManager, AssistantAgent
reviewer = AssistantAgent(
name="reviewer",
system_message=(
"You review Python code for correctness and security. Reply 'APPROVE' "
"if the code is safe and correct, otherwise explain the flaw in one line."
),
llm_config=llm_config,
)
group = GroupChat(
agents=[code_writer, reviewer, executor],
messages=[],
max_round=12,
speaker_selection_method="auto",
)
manager = GroupChatManager(group=group, llm_config=llm_config)
executor.initiate_chat(manager, message="Find all primes under 50 and save to primes.txt.")
The autogen code generation execution agents now operate inside a multi-agent conversation: writer drafts, reviewer gates, executor runs. Set max_round to bound cost.
Step 8: Handle errors and timeouts
Model-generated code fails. Wrap the executor config with sane limits and inspect exitcode.
code_execution_config={
"executor": "local",
"work_dir": "autogen_work",
"use_docker": False,
"timeout": 20,
"max_retries": 3,
}
If the assistant repeatedly errors, add a user_proxy auto-reply that summarizes the last traceback. The writer’s system prompt already asks for fixes; tightening the loop with explicit error context reduces wasted tokens.
Step 9: Production considerations
For sustained workloads, log every LLM call and code run. Gateways that provide per-token usage metering and honor client routing directives simplify cost tracking—forward provider cache-control hints so repeated prompts hit cache. When a provider degrades, an endpoint with automatic fallback keeps the autogen code generation execution agents running instead of throwing 429s.
Run the executor inside Docker by flipping use_docker=True and mounting work_dir as a volume. That contains filesystem and network escapes. Never expose local executors to untrusted model weights or prompts.
Step 10: Customize the task interface
Swap initiate_chat for an async loop if you’re serving requests:
import asyncio
from autogen import initiate_chat
async def solve(task: str):
await initiate_chat(executor, recipient=manager, message=task)
return open("autogen_work/last_result.txt").read()
Keep the agent objects singleton; rebuild GroupChat per task only if you need isolated message history.
The pattern above is the backbone for any autonomous coding tool: generate, execute, observe, repeat. With the group chat variant you get review and specialization without changing the execution core.