The multi-agent debate pattern solves a specific problem: getting past the single-model blind spot on tasks where reasoning paths diverge. You spin up multiple agents with the same prompt, let them argue, then aggregate their positions into a final answer. Used correctly, it trades extra latency and tokens for measurable gains in reasoning consistency on non-deterministic tasks.
When to use the multi-agent debate pattern
Reach for this pattern only when the task has a verifiable or at least arguable answer space. Factual retrieval with a single source of truth does not benefit. Code generation, strategic analysis, and open-ended planning do.
If you can’t define what “winning” the debate means, skip it. The pattern adds cost; justify it with error reduction you can observe in eval. A good sniff test: you have a baseline single-agent failure rate above 15% on a sample set and the errors look like missing perspectives.
What not to debate
Don’t deploy the multi-agent debate pattern for straight translation, regex extraction, or any task where the output is checked by a deterministic oracle. The oracle alone is cheaper and more reliable.
Step 1: Define agent roles and prompts
Don’t just clone the same system prompt N times. Assign distinct perspectives: e.g., “skeptic”, “builder”, “devil’s advocate”. Keep the task spec identical; vary the framing.
ROLES = {
"optimist": "You favor feasible, action-oriented solutions. Defend the practical path.",
"skeptic": "You challenge assumptions and surface failure modes. Attack weak reasoning.",
"neutral": "You summarize tradeoffs without advocating. Weigh evidence only."
}
Each agent receives the same user query plus its role instruction. This seeds divergence. The roles should be mutually exclusive in incentive, not just tone.
Step 2: Run parallel generation with fallback
Fire the first round concurrently. Use an OpenAI-compatible client. If you route through a gateway such as n4n.ai, you can address 240+ models behind one endpoint and get automatic fallback when a provider is degraded—useful when one agent’s model throws a 429.
import asyncio, openai
async def call_agent(client, model, role, query):
resp = await client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": ROLES[role]},
{"role": "user", "content": query}
],
temperature=0.7,
)
return role, resp.choices[0].message.content
async def first_round(query, models):
clients = [openai.AsyncOpenAI(base_url="https://api.n4n.ai/v1") for _ in models]
tasks = [call_agent(c, m, r, query) for c, m, r in zip(clients, models, ROLES)]
return await asyncio.gather(*tasks)
Pin different models per role to avoid correlated failures. If all agents use the same weights, they’ll make the same mistakes. A practical mix: one large reasoning model, one mid-size general model, one small fast model.
Step 3: Structure the debate round
One round of independent answers is not a debate. Feed each agent the others’ outputs and ask for a rebuttal. Limit to one or two rounds; more burns tokens with diminishing returns.
async def debate_round(client, model, role, query, prior):
ctx = "\n\n".join(f"[{r}] said: {t}" for r, t in prior if r != role)
resp = await client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": ROLES[role]},
{"role": "user", "content": f"Query: {query}\n\nOpposing views:\n{ctx}\n\nRefute or concede."}
],
)
return role, resp.choices[0].message.content
Keep the rebuttal prompt strict: require explicit “concede” or “hold” statements. Free-form arguing dilutes signal. Run this round in parallel per agent after the first round completes.
Step 4: Implement voting or aggregation
After debate, collect final positions. Voting can be naive (majority label) or weighted (confidence score parsed from output). For code tasks, execute the proposed solutions and test instead of voting.
def extract_verdict(text):
if "concede" in text.lower():
return "concede"
return "hold"
def aggregate(rounds):
votes = [extract_verdict(t) for _, t in rounds]
if votes.count("concede") >= 2:
survivors = [r for r, t in rounds if extract_verdict(t) == "hold"]
return survivors[0] if survivors else rounds[0]
return max(rounds, key=lambda x: len(x[1])) # fallback: longest reasoning
Weight by token logprobs if your endpoint returns them. Don’t over-engineer; a simple rule beats a fuzzy classifier. If two agents hold and one concedes, inspect the surviving texts for contradiction before synthesizing.
Step 5: Terminate and synthesize
Stop after fixed rounds. Hand the surviving positions to a synthesizer agent with a tight prompt: produce the final answer citing which agent view prevailed and why.
async def synthesize(client, model, query, finalists):
views = "\n".join(f"- {r}: {t[:500]}" for r, t in finalists)
resp = await client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": "Produce a concise final answer. Cite which view won."},
{"role": "user", "content": f"Task: {query}\nSurviving views:\n{views}"}
],
)
return resp.choices[0].message.content
The synthesizer should not introduce new reasoning. Its job is compression and attribution.
Common pitfalls and tradeoffs
Token cost scales linearly. Three agents, two rounds, plus synthesizer is ~7x a single call. Meter per-token usage and set ceilings. If you use a gateway that provides per-token metering, pipe those numbers to your cost dashboard.
Echo chamber. If you use the same model family for all roles, they converge. Mix architectures (e.g., a reasoning model with a fast chat model).
Latency. Parallel calls help, but the debate round is sequential per agent. Budget 2-3x single-agent latency even with concurrency.
Garbage aggregation. Voting on text without structured verdicts yields noise. Always force a machine-parseable signal.
Over-debate. More than two rounds rarely changes outcomes. Cap it.
Correlated failures
When a provider outage hits, all agents on that provider fail. Use fallback or multi-provider routing. Gateways like n4n.ai honor client routing directives and forward provider cache-control hints, so you can pin roles to different providers and cache the static role prefixes.
Production checklist
- Log each agent’s raw output for replay.
- Set per-agent timeouts; fail open to a single-agent fallback.
- Prefix static role prompts to exploit cache-control and cut repeat token cost.
- Monitor concede/hold ratios; a healthy debate shows movement.
- Alert on zero survivors (all concede) — means prompt contradiction.
The multi-agent debate pattern is a lever, not a default. Pull it when the cost of being wrong exceeds the cost of the extra calls.