Claude Agent SDK: Multi-Agent Tutorial

· 6 min read

The Claude Agent SDK provides the building blocks for creating multi-agent systems where specialized agents collaborate to solve complex problems. This tutorial covers the core concepts, from defining individual agents to orchestrating teams that execute in sequence, parallel, or coordinated patterns. By the end, you will understand how to structure agent teams in TypeScript and integrate them into your applications.

Overview

A multi-agent system in the Claude Agent SDK consists of three core primitives:

The SDK does not impose a specific architecture. You can build sequential pipelines, parallel fan-outs, coordinator patterns, or any combination. The primitives are flexible enough to support any topology.

When to Use It

Multi-agent systems are the right choice when:

Multi-agent systems add complexity. If a single prompt can solve your problem well, use a single prompt. Reach for multi-agent architecture when the task genuinely benefits from decomposition.

Getting Started

Defining an Agent

An agent definition in the SDK is a configuration object that specifies the agent's role, input expectations, and output format:

import { defineAgent } from "@anthropic/agent-sdk";

const researchAgent = defineAgent({
  name: "research-agent",
  model: "claude-sonnet-4-20250514",
  systemPrompt: `You are a Research Agent. Your role is to gather and
    structure information on a given topic.

    INPUT: A research topic and specific questions to answer.
    OUTPUT: A structured research brief with:
    - Key findings (5-10 bullet points with sources)
    - Data points (quantitative facts with confidence levels)
    - Knowledge gaps (what you could not find or verify)`,
  outputFormat: "structured",
});

The systemPrompt is where you define the agent's expertise and behavior. Be specific about input expectations and output format -- this is the contract that other agents and your orchestration logic depend on.

Defining a Team

A team groups agents together and specifies how they interact:

import { defineTeam } from "@anthropic/agent-sdk";

const analysisTeam = defineTeam({
  name: "market-analysis",
  agents: [researchAgent, analysisAgent, recommendationAgent],
  orchestration: "sequential",
});

The orchestration field determines the execution pattern. The SDK supports three built-in patterns:

Running a Team

Execute a team with a single call:

const result = await analysisTeam.run({
  input: {
    topic: "AI infrastructure market 2026",
    questions: [
      "What is the current market size?",
      "Who are the top 5 players by revenue?",
      "What are the growth projections for the next 3 years?",
    ],
  },
});

console.log(result.output);
console.log(result.metadata.executionTime);
console.log(result.metadata.agentOutputs); // individual agent results

The result.metadata.agentOutputs field gives you access to each agent's individual output, which is useful for debugging and for cases where you want to present the breakdown alongside the final synthesis.

Parallel Execution

For teams where agents operate independently on the same input, use parallel orchestration:

const feedbackTeam = defineTeam({
  name: "feedback-analysis",
  agents: [sentimentAgent, featureRequestAgent, churnRiskAgent],
  orchestration: "parallel",
  merge: (outputs) => {
    // Custom merge logic
    return {
      sentiment: outputs["sentiment-agent"],
      features: outputs["feature-request-agent"],
      churnRisk: outputs["churn-risk-agent"],
      summary: synthesize(outputs),
    };
  },
});

The merge function is where you control how parallel outputs combine. Without a custom merge function, the SDK concatenates outputs in agent order. A custom merge function lets you structure the combined output, resolve conflicts between agents, and add synthesis logic.

Coordinator Pattern

The coordinator pattern is the most flexible. The first agent decides how to delegate:

const coordinatorAgent = defineAgent({
  name: "coordinator",
  model: "claude-sonnet-4-20250514",
  systemPrompt: `You are a Coordinator Agent. Analyze the incoming request
    and determine which specialist agents to invoke.

    Available specialists: research, analysis, writing, strategy.

    For each specialist you invoke, specify:
    - The agent name
    - The specific input to pass
    - The expected output format

    After receiving specialist outputs, synthesize them into a final response.`,
  canDelegate: true,
});

const adaptiveTeam = defineTeam({
  name: "adaptive-team",
  agents: [coordinatorAgent, researchAgent, analysisAgent, writingAgent, strategyAgent],
  orchestration: "coordinator",
});

With canDelegate: true, the coordinator agent can selectively invoke other agents based on its analysis of the input. This means the same team can handle different types of requests by activating different subsets of agents.

Error Handling

Multi-agent systems need robust error handling because a failure in one agent can cascade:

const resilientTeam = defineTeam({
  name: "resilient-analysis",
  agents: [researchAgent, analysisAgent, recommendationAgent],
  orchestration: "sequential",
  onAgentError: (agentName, error, previousOutputs) => {
    if (agentName === "recommendation-agent") {
      // Fall back to analysis output without recommendations
      return { fallback: true, output: previousOutputs["analysis-agent"] };
    }
    throw error; // Re-throw for critical agents
  },
});

The onAgentError handler gives you control over failure modes. You can fall back to partial results, retry with modified input, or fail fast depending on which agent encountered the error and how critical it is.

Integration with Agent Teams

The SDK's multi-agent primitives are designed to support the kind of agent teams you build for real business problems. Here is how the SDK concepts map to practical team design:

Agent roles map to business functions. A "Research Agent" in the SDK corresponds to the research function in a market analysis team. Define each agent's system prompt around a specific business capability, not a generic technical function.

Teams map to workflows. A "Due Diligence Team" in the SDK is a team definition with agents covering financial analysis, legal review, and market assessment. The orchestration pattern (sequential, parallel, or coordinator) depends on the dependencies between these functions.

Output formats map to deliverables. The structured output from a team run should match the deliverable format your end users expect. If the business need is a report, the final merge step should produce report-formatted output, not raw agent outputs.

// A complete team definition for a practical use case
const dueDiligenceTeam = defineTeam({
  name: "due-diligence",
  agents: [
    financialAnalysisAgent,  // Analyzes financial statements
    legalReviewAgent,        // Reviews legal structure and risks
    marketAssessmentAgent,   // Evaluates market position
  ],
  orchestration: "parallel",
  merge: (outputs) => ({
    executiveSummary: generateSummary(outputs),
    financialAnalysis: outputs["financial-analysis"],
    legalReview: outputs["legal-review"],
    marketAssessment: outputs["market-assessment"],
    riskMatrix: combineRisks(outputs),
    recommendation: generateRecommendation(outputs),
  }),
});

The key insight is that the SDK handles the infrastructure -- execution, data passing, error handling -- while you focus on defining what each agent does and how the outputs combine. The business logic lives in the agent prompts and the merge functions, not in orchestration boilerplate.

When designing your agent teams, start with the deliverable your users need, work backward to identify the analyses required, and map each analysis to an agent. The SDK patterns (sequential, parallel, coordinator) then follow naturally from the dependencies between those analyses.

Skip the setup -- generate agent teams instantly -->