Multi-agent¶
"Multi-agent" means running more than one LLM role in the same system, each with a narrower job description. The reason to do it is usually one of two: a single agent gets confused when the task mixes concerns (planning + execution, writing + reviewing), or you want genuine parallelism (independent attempts, then pick the best).
Before reaching for multi-agent, ask: can one agent with more tools do this? If yes, stay single-agent. Every additional agent is an extra round-trip — more tokens, more latency, more debugging.
Common patterns¶
Sequential pipeline¶
flowchart LR
U[User input] --> A[Agent A]
A -->|structured handoff| B[Agent B]
B --> O[Final output]
Agent A produces structured output that Agent B consumes. Canonical example: a planner that turns a vague request into a list of steps, and an executor that runs the steps with tools.
Coordinator + workers¶
flowchart TB
U[User input] --> C[Coordinator]
C --> W1[Worker: math]
C --> W2[Worker: lookup]
C --> W3[Worker: codegen]
W1 --> C
W2 --> C
W3 --> C
C --> O[Final output]
A coordinator reads the request, routes subtasks to specialized workers, and assembles the answers. The coordinator holds the "big picture" memory; each worker is fresh for each subtask.
Critic / debate¶
flowchart LR
T[Task] --> W[Writer]
W -->|draft| Cr[Critic]
Cr -->|issues or approved| W
Cr -->|approved| O[Final output]
A writer produces a draft; a critic reviews it and either approves or returns issues. The writer revises until the critic is satisfied, or until a round cap is hit. This buys quality at the cost of roughly 2× the tokens and latency.
Parallel / swarm¶
flowchart LR
T[Task] --> A1[Agent 1]
T --> A2[Agent 2]
T --> A3[Agent 3]
A1 --> R[Aggregator]
A2 --> R
A3 --> R
R --> O[Final output]
n agents attack the same task independently, then an aggregator (which can itself be an agent, a voting function, or a human) picks or merges. Good for tasks with verifiable outputs (code that compiles and passes tests; math problems with a checkable answer).
Worked example: writer + critic¶
A two-agent loop where a writer drafts a technical explanation and a critic reviews it, returning structured feedback. The writer revises until the critic approves, or until a round cap is hit.
Pick your provider¶
All three providers we cover use the openai SDK; only the client and model differ.
SJTU's OpenAI-compatible gateway at models.sjtu.edu.cn exposes deepseek-chat and other models (campus-network / VPN only). Same code shape as DeepSeek — just swap the key env var and the base URL.
Shared code¶
import json
import os
from dotenv import load_dotenv
load_dotenv()
# client and model come from one of the tabs above
def writer_agent(task: str, feedback: str | None = None) -> str:
messages = [
{
"role": "system",
"content": "You write concise, accurate technical explanations. One paragraph, no bullets.",
},
{"role": "user", "content": task},
]
if feedback:
messages.append(
{"role": "user", "content": f"Revise the previous draft. Issues to fix: {feedback}"}
)
resp = client.chat.completions.create(model=model, messages=messages, temperature=0)
return resp.choices[0].message.content
def critic_agent(task: str, draft: str) -> dict:
messages = [
{
"role": "system",
"content": (
"You review technical explanations for accuracy and clarity. "
'Reply with JSON: {"approved": bool, "issues": [string]}. '
"Approve only if the draft is factually correct and clear. "
"Issues must be specific and actionable."
),
},
{"role": "user", "content": f"Task: {task}\n\nDraft: {draft}"},
]
resp = client.chat.completions.create(
model=model,
messages=messages,
response_format={"type": "json_object"},
temperature=0,
)
return json.loads(resp.choices[0].message.content)
def collaborate(task: str, max_rounds: int = 3) -> str:
feedback = None
draft = ""
for round_num in range(max_rounds):
draft = writer_agent(task, feedback)
review = critic_agent(task, draft)
if review["approved"]:
return draft
feedback = "; ".join(review["issues"])
return draft # give up, return the last draft
if __name__ == "__main__":
print(collaborate("Explain a PID controller in one paragraph."))
The writer knows nothing about the critic's existence — it just sees "revise based on these issues". That separation is the whole point: two system prompts, two responsibilities, structured handoff.
Design decisions¶
- Handoff format. Prefer structured data (JSON) between agents, not free-form text. The example uses
{"approved": bool, "issues": [str]}for exactly this reason. JSON mode / tool calls make the schema enforceable. - Shared vs. private memory. Sequential pipelines usually keep each agent's memory private — the previous agent's output is passed explicitly. Coordinators often keep a shared running log and pass relevant slices to each worker. Don't pool all agents into one
messageslist; it destroys the specialization you paid for. - Round caps everywhere. Writer + critic, coordinator + workers, debate — every multi-agent loop needs a max_rounds to prevent runaway. Return the best-so-far if the cap is hit rather than raising.
- Deterministic sampling. Keep
temperature = 0on every agent in a multi-agent system unless variety is the point (swarm / brainstorming). Debugging a stochastic chain of agents is brutal. - Log each agent's messages. When the system is wrong, the fix is almost always in one specific agent's prompt. Dump every agent's turn to a log, so you can tell which one misfired.
Gotchas¶
- Cost and latency multiply. Two agents = roughly 2× tokens and 2× wall time per iteration. Three agents, or a debate loop running three rounds, can turn a 3-second call into 20 seconds.
- Responsibility drift. Without a sharp boundary, agents start doing each other's job (writer critiques its own draft; critic starts rewriting). Enforce boundaries in the system prompts ("do not modify the draft yourself — only list issues").
- Same-model blind spots. If every agent uses the same model, they share the same failure modes. A critic run on the same model as the writer may miss the same hallucination the writer made. Consider mixing providers or model sizes for critic/writer pairs.
- Debugging nightmare. When a 4-agent system produces a wrong answer, the bad step may be any of the four. Good logging and deterministic sampling are not optional.
- More agents ≠ better. Research papers routinely show diminishing returns (or regressions) past 2-3 agents for most tasks. Start with one; add a second only when you can state what it uniquely adds.
Further reading¶
- Building Effective Agents (Anthropic) — covers the same patterns (routing, parallelization, orchestrator-workers, evaluator-optimizer) with production-grade guidance on when each is worth the complexity.
Next¶
- LLM + Control — capstone examples applying these agent patterns to control-systems problems.