Why multi-agent workflows?
A single agent works well for focused tasks, but complex jobs—research, code generation with review, or multi-step data processing—benefit from specialization. Instead of overloading one prompt with every responsibility, you split the work across several agents, each with a narrow role. This keeps prompts shorter, reduces error rates, and makes each step easier to test and debug.
The most common structure is the orchestrator-worker pattern: one coordinating agent decides what needs to happen and delegates subtasks to worker agents. The orchestrator collects results, decides whether more work is needed, and assembles the final output.
Designing agent roles
Start by writing down the distinct responsibilities in your workflow. A good rule of thumb: if a task requires a different set of tools, a different tone, or a different definition of "done," it probably deserves its own agent.
For a research assistant you might define:
- Planner — breaks a question into sub-questions.
- Researcher — gathers information for each sub-question.
- Synthesizer — merges findings into a coherent answer.
Give each agent a system prompt that states its role, its inputs, and the exact shape of its output. Constraining outputs to a predictable format is what makes handoffs reliable.
PLANNER_PROMPT = """You are a research planner.
Given a user question, return 2-4 focused sub-questions.
Respond ONLY with a JSON array of strings."""
RESEARCHER_PROMPT = """You are a researcher.
Given one sub-question, produce a concise factual summary.
Cite which claims are uncertain."""
Wiring the orchestrator
The orchestrator is ordinary application code that calls Claude for each step and passes structured data between agents. Because the planner emits JSON, you can parse it and fan out researcher calls, then feed the collected results to the synthesizer.
import json
from anthropic import Anthropic
client = Anthropic()
def run_agent(system, user):
resp = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
system=system,
messages=[{"role": "user", "content": user}],
)
return resp.content[0].text
def workflow(question):
plan = json.loads(run_agent(PLANNER_PROMPT, question))
findings = [run_agent(RESEARCHER_PROMPT, sub) for sub in plan]
combined = "\n\n".join(findings)
return run_agent(SYNTHESIZER_PROMPT, combined)
Keep the orchestration logic in your code rather than asking a single agent to manage everything. Deterministic control flow—loops, retries, parsing—is more predictable in Python than inside a prompt.
Making it robust
Agents fail in ways single functions don't. Plan for it:
- Validate every handoff. Wrap
json.loadsin try/except and re-prompt on malformed output, or ask the model to correct its format. - Set boundaries. Cap the number of researcher calls and total iterations so a runaway plan can't spiral.
- Log intermediate outputs. When the final answer is wrong, you want to see which agent introduced the error.
- Run workers in parallel when they're independent. Since researcher calls don't depend on each other, dispatch them concurrently to cut latency.
Only reach for multiple agents when the added coordination pays off. If a task fits comfortably in one prompt with tool use, a single agent is simpler and cheaper. Multi-agent shines when subtasks are genuinely distinct and benefit from focused context.
Key takeaways
- Split complex work into agents with narrow, well-defined roles.
- Use an orchestrator-worker pattern with control flow living in your code, not a prompt.
- Enforce structured outputs (like JSON) so handoffs between agents stay reliable.
- Add validation, retries, and iteration limits to handle agent failures.
- Parallelize independent workers, and prefer a single agent when the task is simple.
Original tutorial synthesized from the source: Build a multi-agent workflow.
No comments yet
Be the first to share your take.