AutoGen’s code-executing agents become significantly more useful when you can swap the underlying model without rewriting agent logic. This tutorial shows how to route autogen code execution gpt-5.1 n4n.ai calls through a single OpenAI-compatible endpoint that handles fallback, metering, and provider cache hints automatically. You’ll end up with a drop-in replacement for openai.ChatCompletion that your existing AutoGen configuration can use unchanged.
Step 1: Install dependencies
Use Python 3.10 or newer. Create a virtual environment and install the current AutoGen release plus the OpenAI client library.
python -m venv .venv
source .venv/bin/activate
pip install -U pip
pip install "pyautogen>=0.2.30" openai python-dotenv
Verify the imports work:
import autogen
from openai import OpenAI
print(autogen.__version__)
You should see a version string like 0.2.30 or newer.
Step 2: Configure the n4n.ai endpoint
n4n.ai exposes an OpenAI-compatible base URL. Set it alongside your API key in a .env file so you never hardcode credentials.
cat > .env <<'EOF'
N4N_API_KEY=sk-your-n4n-key
N4N_BASE_URL=https://api.n4n.ai/v1
EOF
Load these values in your application bootstrap:
import os
from dotenv import load_dotenv
load_dotenv()
N4N_API_KEY = os.getenv("N4N_API_KEY")
N4N_BASE_URL = os.getenv("N4N_BASE_URL")
if not N4N_API_KEY or not N4N_BASE_URL:
raise RuntimeError("Missing N4N_API_KEY or N4N_BASE_URL in environment")
Step 3: Create a shared OpenAI client pointed at n4n.ai
AutoGen agents accept an llm_config dictionary that ultimately gets passed to the OpenAI client. Construct a single client instance and reuse it across agents to benefit from connection pooling and consistent headers.
from openai import OpenAI
n4n_client = OpenAI(
api_key=N4N_API_KEY,
base_url=N4N_BASE_URL,
default_headers={
"HTTP-Referer": "https://your-domain.example", # optional, for provider analytics
"X-Title": "autogen-code-execution-demo",
},
)
The default_headers are optional but recommended; some upstream providers use them for routing and abuse prevention.
Step 4: Define the model routing directive
n4n.ai honors a model field that can be a specific provider model slug or a routing directive. For GPT-5.1, use the canonical slug openai/gpt-5.1. You can also request automatic fallback by omitting the provider prefix, but explicit routing makes behavior predictable.
MODEL = "openai/gpt-5.1"
If you want n4n.ai to choose the best available model in the same capability tier, use gpt-5.1 without the provider prefix. The gateway will respect cache-control hints returned by the upstream provider and surface them in the response headers.
Step 5: Build the llm_config for AutoGen
AutoGen expects an llm_config with at least model, api_key, base_url, and optionally client if you want to inject your pre-configured client. Passing the client directly avoids duplicate HTTP connection pools.
llm_config = {
"model": MODEL,
"api_key": N4N_API_KEY,
"base_url": N4N_BASE_URL,
"client": n4n_client,
"temperature": 0.2,
"timeout": 120,
"cache_seed": 42, # enables AutoGen's built-in response caching
}
cache_seed activates AutoGen’s in-memory cache keyed by request payload. This is separate from provider-level caching but complements it.
Step 6: Create a code-executing user proxy agent
AutoGen’s UserProxyAgent with code_execution_config runs code in a sandbox. Point it at the same llm_config so the LLM calls that drive code generation also route through n4n.ai.
from autogen import UserProxyAgent
user_proxy = UserProxyAgent(
name="user_proxy",
human_input_mode="NEVER",
max_consecutive_auto_reply=3,
code_execution_config={
"work_dir": "coding",
"use_docker": False, # set True if you have Docker and want isolation
"timeout": 60,
},
llm_config=llm_config,
)
use_docker=False runs code in a local subprocess. For production workloads, set use_docker=True and provide a Docker image with your required dependencies.
Step 7: Create an assistant agent that writes code
The assistant agent receives the task, asks the LLM for code, and the user proxy executes it. Both agents share the same llm_config so every model call — planning, coding, debugging — goes through the gateway.
from autogen import AssistantAgent
assistant = AssistantAgent(
name="assistant",
system_message=(
"You are a Python developer. Write clean, well-commented code to solve the user's task. "
"Prefer standard library modules. Return only the code block, no markdown formatting."
),
llm_config=llm_config,
)
Step 8: Register a termination condition
AutoGen conversations need a way to stop. A simple heuristic: terminate when the user proxy sees a result printed to stdout or when the assistant emits a final answer marker.
def is_termination_msg(msg: dict) -> bool:
content = msg.get("content", "")
return "TERMINATE" in content or "result:" in content.lower()
user_proxy.register_reply(
trigger=AssistantAgent,
reply_func=lambda *args, **kwargs: None, # no-op, we just want the termination check
config={"termination_check": is_termination_msg},
)
Step 9: Run a sample task
Kick off a conversation with a task that requires code execution — for example, computing a Fibonacci sequence with memoization and printing the 30th value.
task = (
"Write a Python function that computes the nth Fibonacci number using memoization. "
"Print the 30th Fibonacci number and the execution time in milliseconds. "
"End your response with 'TERMINATE'."
)
chat_result = user_proxy.initiate_chat(assistant, message=task)
Run the script:
python run_autogen.py
Step 10: Verify success
You should see output similar to:
user_proxy (to assistant):
Write a Python function that computes the nth Fibonacci number using memoization. Print the 30th Fibonacci number and the execution time in milliseconds. End your response with 'TERMINATE'.
assistant (to user_proxy):
import time
from functools import lru_cache
@lru_cache(maxsize=None)
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
start = time.perf_counter()
result = fib(30)
elapsed_ms = (time.perf_counter() - start) * 1000
print(f"fib(30) = {result}")
print(f"elapsed = {elapsed_ms:.3f} ms")
TERMINATE
user_proxy (to assistant):
exitcode: 0
stdout:
fib(30) = 832040
elapsed = 0.042 ms
TERMINATE
Key verification points:
- Exit code 0 — the sandbox executed without error.
- Correct result —
fib(30) = 832040matches the known value. - TERMINATE marker — the conversation ended cleanly.
- Latency — the round-trip through n4n.ai to GPT-5.1 and back should be under a few seconds for this prompt size.
Step 11: Inspect gateway metadata (optional)
n4n.ai returns provider metadata in response headers. You can access them via the OpenAI client’s with_raw_response wrapper if you need to log which upstream model actually served the request, cache status, or token counts.
from openai import OpenAI
raw = n4n_client.chat.completions.with_raw_response.create(
model=MODEL,
messages=[{"role": "user", "content": "ping"}],
max_tokens=5,
)
print(raw.headers.get("x-provider")) # e.g., "openai"
print(raw.headers.get("x-cache-status")) # e.g., "HIT" or "MISS"
print(raw.headers.get("x-tokens-used")) # total tokens for the request
This is useful for observability pipelines but not required for basic operation.
Step 12: Enable automatic fallback for resilience
If you want the gateway to fail over to another provider when GPT-5.1 is rate-limited or degraded, remove the provider prefix from the model string and let n4n.ai handle routing.
# Fallback-enabled model string
MODEL_FALLBACK = "gpt-5.1"
llm_config_fallback = {
**llm_config,
"model": MODEL_FALLBACK,
}
The gateway will select an available model in the same tier (e.g., Claude 3.5 Sonnet, Gemini 1.5 Pro) and surface the actual provider in x-provider response headers. Your AutoGen agents require no code changes — only the model string differs.
Step 13: Meter per-token usage in your application
n4n.ai meters usage per token and exposes cumulative counters via the admin API. For in-process tracking, accumulate usage fields from each response.
total_prompt_tokens = 0
total_completion_tokens = 0
def track_usage(response):
global total_prompt_tokens, total_completion_tokens
usage = response.usage
if usage:
total_prompt_tokens += usage.prompt_tokens
total_completion_tokens += usage.completion_tokens
# Monkey-patch the client create method for automatic tracking
original_create = n4n_client.chat.completions.create
def tracking_create(*args, **kwargs):
resp = original_create(*args, **kwargs)
track_usage(resp)
return resp
n4n_client.chat.completions.create = tracking_create
After a batch of tasks, print the totals:
print(f"Prompt tokens: {total_prompt_tokens}")
print(f"Completion tokens: {total_completion_tokens}")
These numbers match what you’ll see in the n4n.ai dashboard, making cost allocation straightforward.
Step 14: Package as a reusable module
Extract the configuration into a module your team can import. This avoids copy-paste drift across notebooks and services.
# autogen_n4n.py
import os
from dotenv import load_dotenv
from openai import OpenAI
from autogen import UserProxyAgent, AssistantAgent
load_dotenv()
N4N_API_KEY = os.getenv("N4N_API_KEY")
N4N_BASE_URL = os.getenv("N4N_BASE_URL")
MODEL = os.getenv("N4N_MODEL", "openai/gpt-5.1")
if not N4N_API_KEY or not N4N_BASE_URL:
raise RuntimeError("Set N4N_API_KEY and N4N_BASE_URL in environment")
n4n_client = OpenAI(
api_key=N4N_API_KEY,
base_url=N4N_BASE_URL,
default_headers={"X-Title": "autogen-shared"},
)
llm_config = {
"model": MODEL,
"api_key": N4N_API_KEY,
"base_url": N4N_BASE_URL,
"client": n4n_client,
"temperature": 0.2,
"timeout": 120,
"cache_seed": 42,
}
def make_agents(work_dir: str = "coding"):
user_proxy = UserProxyAgent(
name="user_proxy",
human_input_mode="NEVER",
max_consecutive_auto_reply=3,
code_execution_config={"work_dir": work_dir, "use_docker": False, "timeout": 60},
llm_config=llm_config,
)
assistant = AssistantAgent(
name="assistant",
system_message="Write clean Python code. Return only the code block. End with TERMINATE.",
llm_config=llm_config,
)
return user_proxy, assistant
Now any script can do:
from autogen_n4n import make_agents
user_proxy, assistant = make_agents()
user_proxy.initiate_chat(assistant, message="Compute factorial of 20. TERMINATE")
Step 15: Run in a CI/CD pipeline
For automated testing, run the same script in a headless environment. Ensure the sandbox directory is writable and the API key is injected via secrets.
# .github/workflows/autogen-test.yml
name: autogen-code-execution
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- run: pip install -r requirements.txt
- env:
N4N_API_KEY: ${{ secrets.N4N_API_KEY }}
N4N_BASE_URL: ${{ secrets.N4N_BASE_URL }}
run: python -m pytest tests/test_autogen.py -v
A minimal test:
# tests/test_autogen.py
from autogen_n4n import make_agents
def test_fibonacci():
user_proxy, assistant = make_agents(work_dir="/tmp/autogen_test")
result = user_proxy.initiate_chat(
assistant,
message="Print fib(10). TERMINATE",
)
assert "55" in result.chat_history[-1]["content"]
Troubleshooting common issues
| Symptom | Cause | Fix |
|---|---|---|
401 Unauthorized |
Invalid or missing N4N_API_KEY |
Verify key in dashboard, check .env loading |
404 Not Found |
Wrong N4N_BASE_URL |
Must be https://api.n4n.ai/v1 (trailing /v1) |
503 Service Unavailable |
Upstream provider down | Use fallback model string gpt-5.1 without provider prefix |
| Code execution timeout | timeout too low in code_execution_config |
Increase to 120s for heavy computations |
| Docker permission denied | use_docker=True without docker group |
Run usermod -aG docker $USER or use use_docker=False |
Next steps
- Add structured logging around
initiate_chatto capture latency percentiles per task type. - Integrate the
x-cache-statusheader into your observability stack to measure cache hit rates. - Experiment with
temperature=0for deterministic code generation when reproducibility matters. - For multi-agent workflows, share a single
n4n_clientinstance across all agents to reuse HTTP/2 connections.
You now have a production-ready path from AutoGen code-executing agents to GPT-5.1 via n4n.ai, with fallback, metering, and caching handled at the gateway layer.