Claude API Multi-Agent Orchestration Tutorial
Multi-agent orchestration means coordinating several specialized Claude calls — each with a distinct role, prompt, and sometimes different tools — to solve a task that a single prompt handles poorly. Instead of one giant system prompt trying to do research, writing, and validation at once, you split the work: a planner agent breaks down the task, worker agents execute sub-tasks, and a reviewer agent checks the output before it reaches the user.
This tutorial walks through the actual architecture patterns, shows working code for a simple orchestrator built on the Claude API, and covers the failure modes that trip people up — infinite delegation loops, context bloat, and state tracking across agents.
Why orchestrate instead of using one prompt
A single Claude call is efficient for well-scoped tasks: answer this question, summarize this document, classify this ticket. Orchestration pays off when the task has multiple distinct phases that benefit from different instructions, different temperatures, or different tool access:
- Research → synthesis → fact-check, where the fact-checker should be skeptical and the synthesizer should be creative.
- Planning → execution → validation, common in coding agents where one model writes a plan, another executes file edits, and a third verifies against tests.
- Parallel specialists, like a support bot that routes to a billing agent, a technical agent, or an escalation agent depending on intent.
The core idea: each agent gets a narrow, well-defined job and a prompt tuned for that job. The orchestrator is the code (not a model) that decides which agent runs next and what gets passed between them.
Three orchestration patterns
1. Sequential pipeline. Agent A's output becomes Agent B's input. Simplest to build and debug — good default for research-then-write or extract-then-format tasks.
2. Router / dispatcher. One classification call decides which specialist agent handles the request. Cheap and fast if the router prompt is small, since it avoids running every agent on every request.
3. Supervisor with delegation. A supervisor agent has tool definitions representing other agents ("call_research_agent", "call_writer_agent") and decides dynamically which to invoke, possibly looping until it's satisfied. This is the most flexible pattern but also the easiest to get wrong — without a hard iteration cap, a supervisor can delegate back and forth indefinitely.
For most production use cases, start with sequential or router patterns. Reach for the supervisor pattern only when the task genuinely requires dynamic decision-making about which agent to call next.
Building a sequential pipeline
Here's a three-agent pipeline: a researcher that gathers facts, a writer that drafts a response, and a reviewer that checks tone and accuracy.
async function callAgent(systemPrompt, userMessage, model = "claude-sonnet-4-5") {
const res = await fetch("https://api.subtoapi.app/v1/messages", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.SUBTOAPI_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
model,
max_tokens: 1024,
system: systemPrompt,
messages: [{ role: "user", content: userMessage }]
})
});
const data = await res.json();
return data.content[0].text;
}
async function runPipeline(topic) {
const research = await callAgent(
"You are a research agent. List 5 concrete, verifiable facts about the topic. No opinions.",
topic
);
const draft = await callAgent(
"You are a writer. Turn the research notes into a 200-word explainer for a non-technical reader.",
research
);
const reviewed = await callAgent(
"You are a reviewer. Check the draft for factual consistency with the source notes. Return the corrected draft, or the original if no issues.",
`Source notes:\n${research}\n\nDraft:\n${draft}`
);
return reviewed;
}
Each agent is a separate API call with its own system prompt. Because SubToAPI exposes Claude through a standard /v1/messages endpoint with an application API key, you can run this pipeline from a browser, a serverless function, or a background worker without routing raw Anthropic credentials through your app — see the quickstart and messages docs for the full request shape.
Adding a supervisor with tool use
When the orchestrator should decide dynamically, model the other agents as tools and let Claude call them:
{
"tools": [
{
"name": "research_agent",
"description": "Gathers factual information on a topic",
"input_schema": {
"type": "object",
"properties": { "topic": { "type": "string" } },
"required": ["topic"]
}
},
{
"name": "writer_agent",
"description": "Drafts prose from research notes",
"input_schema": {
"type": "object",
"properties": { "notes": { "type": "string" } },
"required": ["notes"]
}
}
]
}
The supervisor model returns a tool_use block naming which agent to call and with what input. Your code executes the corresponding callAgent function, feeds the result back as a tool_result, and loops until the supervisor returns a final text answer instead of another tool call. Details on the request/response format for tool calls are in the tools docs.
Cap the loop explicitly — e.g., stop after 6 tool-call rounds and force a final answer — so a confused supervisor can't burn tokens indefinitely.
Managing state and context across agents
As agents multiply, two problems show up fast:
- Context bloat. Don't pass the full conversation history to every agent. Pass only what that agent needs — a reviewer needs the draft and source facts, not the entire chat log.
- State tracking. Keep an explicit object (in your orchestrator code, not in a prompt) tracking which agents have run, their outputs, and any retry counts. This makes debugging a failed run far easier than trying to reconstruct state from transcript logs.
If your agents need to stream partial output back to a UI — useful for a supervisor that's visibly "thinking" between delegations — SubToAPI supports streaming responses; see streaming for the event format.
Common failure modes
- Delegation loops: a supervisor keeps calling the same agent without converging. Fix with a hard round cap and a "must finalize" instruction after N rounds.
- Prompt drift: sub-agent prompts accumulate ad-hoc instructions over time until they contradict each other. Keep each agent's system prompt in version control and test it in isolation.
- Cost surprises: every agent call is a full API request. A five-agent pipeline on every user message costs roughly 5x a single call — route cheaper or shorter requests to a router pattern instead of running all agents by default.
Questions
Do I need a separate API key per agent? No — a single application key (like a sub_live_ key from SubToAPI) can authenticate every agent's call. Agents are a code-level abstraction, not a credential boundary.
Should each agent use the same Claude model? Not necessarily. Simple routing or classification agents can use a smaller/faster model, while synthesis or reasoning-heavy agents benefit from a stronger one — just keep the model name consistent per agent across runs for predictable behavior.
How do I prevent runaway costs in a supervisor pattern? Set a hard cap on delegation rounds, log token usage per agent call, and prefer sequential or router patterns unless dynamic delegation is actually required for the task.