4.0 From one agent to a team
Agentic AI on AWS, hands-on labs by Shivank Agrawal

Agents that
work together

Section 4. One agent with tools goes a long way. When a job is too big, too varied or too slow for one agent, you build a team: a supervisor with workers, agents used as tools, swarms that hand work around, and graphs that route it along fixed paths.

Folder section-04-multi-agent-patterns Notebooks 01_supervisor_worker 02_agent_as_tool 03_graph_pattern 04_swarm_pattern Model: Claude Sonnet 4.6 on Amazon Bedrock
Swipe sideways to see the full diagram
one agent with tools the right team for the job, or none 1Why ateam 2Supervisorlab 1 3Agent as toollab 2 4How agentstalk 5Swarmlab 4 6Graphlab 3 7Or justone agent
The journey in this section. We start with why teams help, build four team shapes in four notebooks, and finish with the most important skill: knowing when you don't need a team at all.
4.0

From one agent to a team

When a software team takes on a hard problem, nobody does everything alone. Architects, developers and testers each do what they're best at. A hospital works the same way, with doctors, nurses, specialists and administrators. The same idea applies to AI agents.

In Sections 1 to 3 you built single agents with tools and memory. For most use cases, one well-equipped agent is enough. But what if the problem is too big or too varied for one agent to handle well?

In this section you move from one agent to several. You'll see why one agent isn't always enough, then build the main ways of coordinating a team: a supervisor delegating to workers, agents reused as tools, swarms that hand work to each other, and graphs that route work along fixed paths. Along the way you'll learn when each pattern makes sense, and when it doesn't.

✦Think of it like this

A wedding in India. One person can't book the hall, manage the caterer, handle the decorators, coordinate the mehendi artist and greet 500 guests. So there's a wedding planner (the coordinator) and specialists who each own one job. The planner doesn't cook; the caterer doesn't decorate. Multi-agent systems are built on exactly this division of labour.

What you'll learn here

  1. When one agent isn't enough
  2. What multi-agent patterns are
  3. How agents communicate: sequential, parallel and collaborative
  4. Common orchestration patterns: supervisor–worker, agent as tool, swarm and graph
  5. When multi-agent is not the answer

Before you start

  1. 1

    A working Strands setup from Sections 1 to 3

    Virtual environment, AWS credentials with Amazon Bedrock access, and check_setup.py passing.

  2. 2

    Basic Python functions and classes

  3. 3

    An AWS account with Bedrock permissions

    Every notebook calls Claude Sonnet 4.6 on Bedrock. Nothing else is created in your account, so there's nothing to clean up.

  4. 4

    REST APIs and JSON (helpful, not required)

  5. 5

    An IDE

    VS Code, JupyterLab or Kiro, whichever you've been using.

  6. 6

    A free Tavily API key for notebook 1

    The news and sentiment agents search the web with Tavily. An Alpha Vantage key is optional; without it, financial data comes from Yahoo Finance, which needs no key.

NotebookPatternExampleOn this page
01_supervisor_worker.ipynbSupervisor–workerMarket research: news, financial and sentiment workers coordinated by a supervisor4.3
02_agent_as_tool.ipynbAgent as toolTutoring: a teacher delegates to math, writing and science tutors4.4
03_graph_pattern.ipynbGraphE-commerce orders routed through risk, fraud, inventory, shipping and refund steps4.7
04_swarm_pattern.ipynbSwarmGame level design: four specialists hand work to each other4.7
terminal
pip install -r requirements.txt
export TAVILY_API_KEY="tvly-..."          # notebook 1 (free key at tavily.com)
export ALPHA_VANTAGE_API_KEY="..."        # optional
jupyter lab
iWhat's in requirements.txt

strands-agents and strands-agents-tools (the agents, plus the ready-made Tavily search tool), yfinance (free Yahoo Finance data), alpha_vantage (optional market data), pandas and boto3.

4.1

When one agent isn't enough

Before the patterns, the why: when should several agents work together instead of one super-agent doing everything?

The problem with single agents

Imagine asking one agent to research the latest AI trends, analyse competitors' pricing, write a technical specification, generate the code, review that code for security issues, and build a presentation for executives. That's a lot to ask. These are the warning signs that one agent is carrying too much:

Context overload

It tries to track too many different tasks at once and loses focus, the you met in Section 3.

Jack of all trades, master of none

Results are mediocre across every task instead of excellent and accurate in specific areas.

No parallelisation

Everything happens one step after another, even when tasks could run at the same time.

Hard to debug

When something goes wrong, it's hard to pinpoint which part of the process failed.

The multi-agent solution

Picture a busy restaurant. One person could take orders, cook, serve and wash up, but it would be slow. Instead there's a host, servers, chefs and dishwashers, each focused on what they do best. Together they deliver a smooth experience.

Multi-agent systems work the same way. Instead of one very complex agent, you build several specialised agents that cooperate. Under the hood, a coordinator agent receives the request, breaks it into subtasks, and delegates each one to the right specialist. The specialists do their work and report back, and the coordinator stitches the results into one response.

Swipe sideways to see the full diagram
One agent Agentdoes everything Research Writing Analysis Coding overloaded, sequential, hard to debug A team Coordinatorsplits and combines Researchagent Writingagent Analysisagent Codingagent focused, parallel where possible, easy to debug
One generalist vs a team of specialists. The coordinator breaks the request into subtasks and delegates; each specialist does one job well and reports back.

Benefits of the multi-agent approach

  1. 1

    Specialisation

    Each agent becomes an expert in its domain, with a focused prompt and the right tools.

  2. 2

    Parallel processing

    Independent tasks run at the same time, saving time.

  3. 3

    Better debugging

    You can isolate and fix problems in one specific agent.

  4. 4

    Scalability

    Add new agents as the system grows, without rewriting everything.

Try it

The same six jobs, one agent vs a team

Single agent
Research AI trends
Competitor pricing
Technical spec
Generate code
Security review
Executive deck
06111722 min

Total time

22 min

Context the busiest agent carries

all 6 jobs in one context
One agent, six hats. Everything runs one after another, the context fills with research notes, prices, spec, code and slides, and quality drops as it loses focus. If the security review finds a problem, you're searching one huge transcript for the cause.
4.2

What are multi-agent patterns?

A is a structured way of organising several AI agents to work towards a common goal.

Think of an orchestra: strings, brass, woodwind and percussion each play their part, together, under a conductor. And just as music can be organised in different ways (a small chamber group, a large symphony, a jazz band that improvises), there are different patterns for organising agents. Each solves a particular kind of problem, and choosing the right one makes your system faster and easier to build.

Every multi-agent design answers four questions:

Swipe sideways to see the full diagram
1 Orchestration How does information flow between agents? central conductor agents talk directly 2 Specialisation Each agent gets a focused role, expertise and tools. A research agent shouldn't also do data visualisation. Let specialists specialise. 3 Collaboration How do agents share and build on each other's work? research agent output analysis agent becomes input 4 Coordination Who decides the order of work? • A workflow you define (a classical score) • Agents decide as they go (jazz improvisation)
Four questions behind every pattern. Orchestration, specialisation, collaboration and coordination. Each pattern in this section is a different set of answers to them.
AspectThe questionTwo ends of the spectrum
OrchestrationHow will information flow between agents?A central coordinator (a conductor) ↔ agents talking directly (a jazz group)
SpecialisationWhat is each agent's focused role and toolset?One narrow job per agent ↔ broader generalists
CollaborationHow do agents share information and build on each other's work?Output of one becomes input of the next ↔ ongoing discussion
CoordinationWho decides the order of work?A workflow you define (a classical score) ↔ agents figure it out (improvisation)

These four aspects underpin every pattern ahead. We start with the simplest and most common one.

4.3

Lab: the supervisor–worker pattern

Your first multi-agent pattern, and the most common one in production. One agent coordinates; specialist agents do the work.

In the pattern, one agent acts as the coordinator. It receives the request, decides which specialists to call, delegates the work, and combines their results into one response. The workers focus on their tasks and report back to the supervisor.

A story in three versions

You're building a market-research assistant. An investor asks: "Should I invest in electric vehicle companies?"

  1. 1

    Version 1: one agent

    It scans recent news, analyses stock performance, checks social media sentiment, reads analyst reports and compares competitors. About five minutes per question. Fine for a few questions a day. Then your manager says it must handle hundreds of questions an hour.

  2. 2

    Version 2: three agents in parallel

    A news agent scans EV news, a financial agent analyses stock performance, a sentiment agent checks social media. The tasks are independent, so they run at the same time: ideally about three times faster. It works! But the investor now gets three separate answers:

News agent

"Several large automakers announced new battery plants. One EV start-up reported production delays."

Financial agent

"EV stocks are up this quarter on average. Valuations of pure-play EV makers are high; one is burning cash fast."

Sentiment agent

"Social media sentiment is mixed. Retail investors are bullish; charging infrastructure is a common worry."

The investor stares at this wall of unconnected facts and asks: "So… should I invest or not?" Each agent did its job perfectly, but nobody synthesised the information into a recommendation.

  1. 3

    Version 3: add a supervisor

    The supervisor receives the question and thinks: "This person needs news context, financial analysis and market sentiment. I have three workers for exactly those." It calls all three at once, rephrasing the question for each, then weaves their answers into one recommendation.

Swipe sideways to see the full diagram
User question Supervisor agentplans, delegates, synthesises Response News agent"What's happening in theEV industry this month?" Financial agent"How financially healthy arethe major EV companies?" Sentiment agent"What's the marketsentiment around EVs?" delegatereport back ✕✕
All communication goes through the supervisor. Workers do specialised tasks and report back; they never talk to each other (the red ✕s). Each worker gets a question rephrased for its speciality.

All three workers run at the same time. Two minutes later the supervisor has every perspective and answers with one recommendation, something like: "The EV sector shows strong growth, but valuations are high and some companies face production problems. Established makers look steadier than newer entrants. With a high risk tolerance the sector looks promising; if you prefer stability, wait for valuations to settle." One coherent answer, and the investor can decide.

Workers stay independent

The news agent doesn't care what the financial agent is doing. Each focuses on its expertise and reports back.

Debugging is straightforward

Wrong financial data? Check the financial agent. Old news? Check the news agent. The supervisor handles synthesis, not domain logic, so bugs stay isolated.

New skills are easy to add

Need regulatory analysis? Create a regulatory agent and tell the supervisor about it. Existing workers don't change.

Try it

Workers on their own vs with a supervisor

  • InvestorShould I invest in EV companies?
  • news_agentSeveral large automakers announced new battery plants. One EV start-up reported production delays.
  • financial_agentEV stocks are up this quarter on average. Pure-play EV makers trade at high valuations; one is burning cash fast.
  • sentiment_agentMixed sentiment. Retail investors bullish; institutions cautious; charging infrastructure is a common worry.
  • Investor“So… should I invest or not?” 3 correct answers, no synthesis, no recommendation.

Run the notebook: 01_supervisor_worker.ipynb

The notebook builds exactly this assistant with real data: Tavily web search for news and sentiment, and Yahoo Finance (through yfinance) for prices and fundamentals. Cell numbers on this page count code cells only, so they skip the notebook's text cells.

cell 1
%pip install -q -r requirements.txt
cell 2: model
import os
from strands.models.bedrock import BedrockModel

MODEL_ID = os.getenv("BEDROCK_MODEL_ID", "global.anthropic.claude-sonnet-4-6")
REGION = os.getenv("AWS_REGION", os.getenv("AWS_DEFAULT_REGION", "us-east-1"))
os.environ.setdefault("AWS_REGION", REGION)

model = BedrockModel(model_id=MODEL_ID, region_name=REGION)
print(f"Using {MODEL_ID} in {REGION}")

One BedrockModel object, shared by every agent in the notebook. All four notebooks start with this same cell.

Configure API keys

Set them in your shell before starting Jupyter (recommended), or uncomment the two lines in this cell:

cell 3
# os.environ["TAVILY_API_KEY"] = "tvly-..."
# os.environ["ALPHA_VANTAGE_API_KEY"] = "..."

if not os.getenv("TAVILY_API_KEY"):
    print("⚠️  TAVILY_API_KEY not set — the news and sentiment agents cannot search the web.")
else:
    print("✓ TAVILY_API_KEY is configured")

if not os.getenv("ALPHA_VANTAGE_API_KEY"):
    print("ℹ️  ALPHA_VANTAGE_API_KEY not set — financial data comes from yfinance (free, no key).")
else:
    print("✓ ALPHA_VANTAGE_API_KEY is configured")
!Keep keys out of notebooks you share

An API key pasted into a cell travels with the notebook file. Prefer export in your shell, so the key lives only in your environment.

cell 4: imports
import yfinance as yf
from strands import Agent, tool
from strands_tools.tavily import tavily_search

tavily_search is a ready-made tool from strands-agents-tools. It reads TAVILY_API_KEY from the environment and supports options such as time_range ("day", "week", "month", "year") and max_results.

Custom financial tools (Yahoo Finance)

cell 5
def _num(value, money=False, pct=False):
    """Format numbers safely — Yahoo sometimes leaves fields empty."""
    if not isinstance(value, (int, float)):
        return "N/A"
    if pct:
        return f"{value * 100:.2f}%"
    return f"${value:,.2f}" if money else f"{value:,.2f}"


@tool
def get_stock_price(symbol: str) -> str:
    """Get the current stock price and key metrics using Yahoo Finance.

    Args:
        symbol: Stock ticker symbol (e.g., 'AAPL', 'TSLA', 'MSFT')
    """
    try:
        info = yf.Ticker(symbol).info
        return (
            f"Stock: {symbol}\n"
            f"Current Price: {_num(info.get('currentPrice') or info.get('regularMarketPrice'), money=True)}\n"
            f"Market Cap: {_num(info.get('marketCap'), money=True)}\n"
            f"P/E Ratio: {_num(info.get('trailingPE'))}\n"
            f"52 Week High: {_num(info.get('fiftyTwoWeekHigh'), money=True)}\n"
            f"52 Week Low: {_num(info.get('fiftyTwoWeekLow'), money=True)}\n"
            f"Average Volume: {_num(info.get('averageVolume'))}\n"
            f"Sector: {info.get('sector', 'N/A')}\n"
            f"Industry: {info.get('industry', 'N/A')}"
        )
    except Exception as e:
        return f"Error fetching stock data for {symbol}: {e}"


@tool
def get_stock_history(symbol: str, period: str = "1mo") -> str:
    """Get historical stock price data.

    Args:
        symbol: Stock ticker symbol (e.g., 'AAPL', 'TSLA')
        period: One of 1d, 5d, 1mo, 3mo, 6mo, 1y, 2y, 5y, 10y, ytd, max
    """
    try:
        hist = yf.Ticker(symbol).history(period=period)
        if hist.empty:
            return f"No historical data available for {symbol}"
        start_price = hist["Close"].iloc[0]
        end_price = hist["Close"].iloc[-1]
        change_pct = (end_price - start_price) / start_price * 100
        return (
            f"Historical Data for {symbol} ({period}):\n"
            f"Starting Price: ${start_price:.2f}\n"
            f"Ending Price: ${end_price:.2f}\n"
            f"Change: {change_pct:+.2f}%\n"
            f"Highest: ${hist['High'].max():.2f}\n"
            f"Lowest: ${hist['Low'].min():.2f}\n"
            f"Average Volume: {hist['Volume'].mean():,.0f}\n\n"
            f"Recent 5-day trend:\n{hist[['Close', 'Volume']].tail().to_string()}"
        )
    except Exception as e:
        return f"Error fetching historical data for {symbol}: {e}"


@tool
def get_company_financials(symbol: str) -> str:
    """Get company financial metrics: revenue, margins, growth and leverage.

    Args:
        symbol: Stock ticker symbol (e.g., 'AAPL', 'TSLA')
    """
    try:
        info = yf.Ticker(symbol).info
        return (
            f"Financial Metrics for {symbol}:\n"
            f"Revenue: {_num(info.get('totalRevenue'), money=True)}\n"
            f"Revenue Growth: {_num(info.get('revenueGrowth'), pct=True)}\n"
            f"Gross Profit: {_num(info.get('grossProfits'), money=True)}\n"
            f"Profit Margin: {_num(info.get('profitMargins'), pct=True)}\n"
            f"Operating Margin: {_num(info.get('operatingMargins'), pct=True)}\n"
            f"EBITDA: {_num(info.get('ebitda'), money=True)}\n"
            f"Earnings Growth: {_num(info.get('earningsGrowth'), pct=True)}\n"
            f"Return on Equity: {_num(info.get('returnOnEquity'), pct=True)}\n"
            f"Debt to Equity: {_num(info.get('debtToEquity'))}\n"
            f"Free Cash Flow: {_num(info.get('freeCashflow'), money=True)}"
        )
    except Exception as e:
        return f"Error fetching financial data for {symbol}: {e}"


print(get_stock_price(symbol="AAPL"))  # tools are still plain functions you can call
  1. a

    _num(...): a defensive formatter

    Yahoo Finance sometimes leaves fields empty. Instead of crashing on None, the tool prints "N/A". The leading underscore marks it as a private helper, not a tool.

  2. b

    Three focused @tool functions

    Current price and key metrics, price history over a period, and company fundamentals. Each returns a plain-text summary the model can read, and each catches errors and returns them as text so one failed lookup doesn't break the whole run.

  3. c

    Test before you give it to an agent

    The last line calls a tool directly. A decorated tool is still a normal Python function, so you can check its output first.

outputillustrative numbers
Stock: AAPL
Current Price: $…
Market Cap: $…
P/E Ratio: …
52 Week High: $…
52 Week Low: $…
Average Volume: …
Sector: Technology
Industry: Consumer Electronics

Optional: an Alpha Vantage tool

cell 6
from alpha_vantage.timeseries import TimeSeries


@tool
def get_alpha_vantage_quote(symbol: str) -> str:
    """Get the latest stock quote from the Alpha Vantage API.

    Args:
        symbol: Stock ticker symbol (e.g., 'AAPL')
    """
    key = os.getenv("ALPHA_VANTAGE_API_KEY")
    if not key:
        return "ALPHA_VANTAGE_API_KEY is not set."
    ts = TimeSeries(key=key, output_format="pandas")
    data, _ = ts.get_quote_endpoint(symbol=symbol)
    return data.to_string()


financial_tools = [get_stock_price, get_stock_history, get_company_financials, tavily_search]
if os.getenv("ALPHA_VANTAGE_API_KEY"):
    financial_tools.append(get_alpha_vantage_quote)

Use this instead of, or alongside, Yahoo Finance if you have a key. Other data providers worth knowing include Polygon.io, Finnhub and Financial Modeling Prep. The financial agent's toolbox is built conditionally: the Alpha Vantage tool is only added when the key exists, so the agent never sees a tool that can't work.

The worker agents

cell 7
news_agent = Agent(
    name="news_agent",
    description="Researches recent news and developments about companies and industries.",
    model=model,
    system_prompt="""You are a news research specialist. Search for recent news and developments about companies and industries.

When searching:
- Focus on recent news (use time_range='week' or 'month')
- Prefer reliable sources such as major news outlets
- Summarize key developments and trends
- Include specific facts, dates, and figures when available""",
    tools=[tavily_search],
    callback_handler=None,
)

financial_agent = Agent(
    name="financial_agent",
    description="Analyzes stock prices, price history, and company financial metrics.",
    model=model,
    system_prompt="""You are a financial analysis specialist. Analyze financial metrics, stock performance, and company valuations.

When analyzing:
- Use get_stock_price for current prices and key metrics
- Use get_stock_history for price trends
- Use get_company_financials for revenue, earnings, and growth
- Compare companies within the same sector and give specific numbers""",
    tools=financial_tools,
    callback_handler=None,
)

sentiment_agent = Agent(
    name="sentiment_agent",
    description="Analyzes market and investor sentiment from forums, social media, and commentary.",
    model=model,
    system_prompt="""You are a market sentiment analyst. Analyze market sentiment from social media, forums, and investor discussions.

When analyzing sentiment:
- Look for both bullish and bearish opinions
- Identify common concerns and excitement points
- Distinguish retail from institutional sentiment
- Summarize the overall market mood""",
    tools=[tavily_search],
    callback_handler=None,
)
print("✓ Worker agents created")
ArgumentWhat it does here
nameBecomes the tool name the supervisor sees: letters, digits, underscores or hyphens, like news_agent.
descriptionBecomes the tool description: how the supervisor knows when to call this worker.
system_promptThe worker's job description, with concrete instructions about which tools to use and how.
toolsEach worker gets only the tools for its speciality. News and sentiment share Tavily search; finance gets the Yahoo Finance tools.
callback_handler=NoneSilences the worker's own streaming output, so you only see the supervisor's answer instead of four voices talking at once.

The supervisor agent

cell 8
supervisor = Agent(
    name="research_supervisor",
    model=model,
    system_prompt="""You are a market research coordinator. When asked about investment opportunities:

1. Work out what information is needed
2. Delegate to the specialist agents:
   - news_agent: recent developments and industry news
   - financial_agent: financial metrics and performance data
   - sentiment_agent: market sentiment and investor opinions
3. Synthesize their responses into one balanced recommendation

This is educational analysis, not financial advice — say so briefly at the end.""",
    tools=[news_agent.as_tool(), financial_agent.as_tool(), sentiment_agent.as_tool()],
)
print("✓ Supervisor created")

agent.as_tool() wraps a worker so the supervisor can call it like any other tool. (Passing the agents directly in tools=[...] does the same thing; you'll see that in the next lab.) By default each call starts the worker from a clean slate, so one question's research doesn't leak into the next. The supervisor's prompt tells it how to delegate and how to synthesise, and it ends with a guardrail: this is education, not financial advice.

Run the multi-agent system

cell 9
question = "Should I invest in electric vehicle companies?"
print(f"Question: {question}\n")

response = supervisor(question)
outputillustrative, shortened
Question: Should I invest in electric vehicle companies?

I'll gather recent news, financial data and market sentiment, then combine them.
Tool #1: news_agent
Tool #2: financial_agent
Tool #3: sentiment_agent
EV investment: a balanced view

News: large automakers keep expanding EV and battery capacity; some newer EV makers face production delays.

Financials: sector revenue is growing, but valuations of pure-play EV makers are high and several are not yet profitable.

Sentiment: retail investors are mostly bullish; institutional investors are cautious about valuations.

Recommendation: established manufacturers look steadier than newer entrants. With a high risk tolerance the sector looks promising; if you prefer stability, wait for valuations to normalise.

This is educational analysis, not financial advice.

Notice the three tool calls. Claude usually asks for all three workers in a single turn, and Strands runs tool calls from the same turn by default, so the three workers really do research in parallel. Your run will quote real, current figures from the live searches.

Try different questions

cell 10
questions = [
    "What's the outlook for renewable energy stocks?",
    "Is the semiconductor industry a good investment right now?",
]

for q in questions:
    print(f"\n{'=' * 80}\nQuestion: {q}\n{'=' * 80}")
    supervisor(q)

Same supervisor, same workers, different sectors. Nothing about the team is specific to EVs; the supervisor works out what each question needs.

Specialisation

Each worker has one job and the right tools for it.

Coordination

The supervisor decides whom to ask and combines the answers.

Modularity

Add a new worker without touching the others.

</>Making it production-ready

Add retries and caching for API calls, respect rate limits, run asynchronously, and add tracing so you can see every call (Section 7).

The trade-offs of supervisor–worker

Swipe sideways to see the full diagram
1 Bottleneck supervisor every decision goes through one agent Fixes • more supervisor copies (scale out)• cache repeat answers, prompt caching• load balancing, async processing 2 Single point of failure supervisor ✕ workers idle if it crashes, the whole system stops Fixes • health checks, automatic restarts• checkpoints to resume from last state• redundant supervisors with failover 3 No direct worker talk sentiment financial via supervisor When it matters • fine for simple workflows• negotiations need collaborative communication (4.6)
Three costs of having one boss. Each has well-known fixes, which is why the pattern still dominates in production.
  1. 1

    The supervisor is a

    Every decision flows through one agent. In production you address this with (run several supervisor instances), caching (repeated questions return instantly) and . For high volume, add load balancing and asynchronous processing.

  2. 2

    It's a

    If the supervisor crashes, the system stops. You need health checks, automatic restarts, and checkpoint management so the supervisor resumes from its last known state. For critical systems, run redundant supervisors with a mechanism.

  3. 3

    Workers can't collaborate directly

    If the sentiment agent discovers something the financial agent should know, it has to go through the supervisor. That's fine for simple workflows; for real negotiation you need collaborative communication, covered in 4.6.

iWhy it's still the favourite

Most multi-agent systems don't need complex negotiation. They need clear accountability, simple communication and easy debugging. That's why supervisor–worker is the most common pattern in production.

4.4

Lab: make agents reusable with "agent as tool"

Build a specialist once, give it a clear description, and any other agent can discover and call it like an ordinary tool.

Supervisor–worker works well, but if every specialist is built from scratch for one particular supervisor, you rebuild it again and again. The pattern fixes that: you wrap an agent with a description of what it does, and other agents can call it just like a regular tool. Treating components as modular, reusable tools lets a system grow without rigid dependencies between its parts.

When an agent receives a task, it reads the available tool descriptions and picks the right one, exactly as you saw with tools in Section 2. The only difference is that these tools are agents.

✦Think of it like this

A hospital's specialist doctors. The cardiologist isn't hired by one GP; any doctor in the hospital can refer a patient to them. The referral desk only needs to know "cardiologist: heart problems". Build the specialist once, and every department can use them.

Swipe sideways to see the full diagram
Student ∫ 2x dx, from 1 to 3 8 Main agentreads tooldescriptions available tools Mathagent Writingagent Scienceagent call 8
The tools are agents. The main agent doesn't know calculus; it knows that "math agent: solves equations" fits the question. Writing and science agents sit unused until a question needs them.

The example: a tutoring assistant

Students ask about different subjects, and you have specialist tutors for math, writing and science. Instead of writing routing logic like "if the question contains 'equation', call the math tutor", you wrap each specialist as a tool and let the teacher agent decide which one to use.

Run the notebook: 02_agent_as_tool.ipynb

Cells 1 and 2 are the same install and model cells as notebook 1. Then:

cell 3
from strands import Agent

Specialist agents

Each specialist gets a name and a description. When an agent is used as a tool, the name becomes the tool name and the description tells the teacher when to call it.

cell 4
math_tutor = Agent(
    name="math_tutor",
    description="Solves mathematical equations and explains math concepts step by step",
    model=model,
    system_prompt="You are a math tutor. Solve math problems and explain your solutions clearly, step by step.",
    callback_handler=None,
)

writing_coach = Agent(
    name="writing_coach",
    description="Helps with writing, grammar, and essay structure",
    model=model,
    system_prompt="You are a writing coach. Help with writing, grammar, and essay structure. Provide constructive feedback.",
    callback_handler=None,
)

science_helper = Agent(
    name="science_helper",
    description="Explains scientific concepts and principles in simple terms",
    model=model,
    system_prompt="You are a science tutor. Explain scientific concepts clearly using simple language and real-world examples.",
    callback_handler=None,
)

The teacher ()

Pass the specialist agents straight into tools=[...]; Strands wraps each one as a callable tool for you.

cell 5
teacher = Agent(
    model=model,
    system_prompt="""You are a teacher who helps students by delegating to specialist tutors.
Never solve problems yourself. Always delegate to the appropriate specialist:
- math_tutor: for math problems and equations
- writing_coach: for writing, grammar, and essays
- science_helper: for science questions

After receiving the specialist's response, present it to the student in a friendly way.""",
    tools=[math_tutor, writing_coach, science_helper],
)
?Two ways to say the same thing

Notebook 1 wrote tools=[news_agent.as_tool(), …]. Here it's tools=[math_tutor, …]. When Strands finds an agent in the tools list, it calls .as_tool() for you with the default settings. Use .as_tool(name=..., description=...) explicitly when you want to override the name or description.

Test with different questions

cell 6
# Math → math_tutor
response = teacher("Can you help me solve this quadratic equation: x^2 + 5x + 6 = 0?")
outputillustrative
I'll help you with that quadratic equation! Let me connect you with our math specialist.
Tool #1: math_tutor

Great! Here's what our math tutor explained:

To solve x² + 5x + 6 = 0, we can use factoring.

Step 1: Look for two numbers that multiply to 6 and add to 5.
        Those numbers are 2 and 3 (since 2 × 3 = 6 and 2 + 3 = 5).

Step 2: Factor the equation: (x + 2)(x + 3) = 0

Step 3: Solve each factor:
        If x + 2 = 0, then x = −2
        If x + 3 = 0, then x = −3

Solution: x = −2 or x = −3

You can check both answers by substituting them back into the original equation; both make it equal zero!
Would you like help with another problem?

The teacher has no hard-coded rule like "if math question, call the math tutor". It saw three tools, read their descriptions, and chose math_tutor because the question matched "solves mathematical equations". Then, as its prompt asks, it presented the tutor's answer in a friendly way.

cell 7
# Writing → writing_coach
response = teacher("How do I write a strong thesis statement for my essay about climate change?")
cell 8
# Science → science_helper
response = teacher("Why does ice float on water?")

Expect Tool #1: writing_coach for the thesis question and Tool #1: science_helper for the ice question (ice is less dense than liquid water because its molecules lock into an open crystal structure).

Try it

Which tutor does the teacher call?

math_tutor

Solves mathematical equations and explains math concepts step by step

writing_coach

Helps with writing, grammar, and essay structure

science_helper

Explains scientific concepts and principles in simple terms

history_tutor

Explains historical events, causes and consequences

not registered

Pick a question.

Why this is so flexible

Want a history tutor? Create a history_tutor agent and add it to the teacher's tools. The teacher automatically knows it exists. No routing logic to update, no new if statements.

And it goes deeper. Specialists can have their own tools, including other agents, creating layers of expertise. Your math_tutor might use a calculator_agent and a graph_plotter_agent. And the same math_tutor can be reused by a teacher agent, a tutoring-assistant agent and a homework-grader agent:

Swipe sideways to see the full diagram
Teacher agent Tutoring assistant Homework grader uses as tooluses as tooluses as tool Math tutor agentbuilt once, reused three times uses as tooluses as tool Calculator agent Graph plotter agent
Layers of expertise. One specialist serves many callers, and can itself call other specialists. Each layer only needs to know the descriptions of the layer below.
iSupervisor–worker vs agent as tool

They look alike, and in Strands both use agents as tools. The difference is intent. Supervisor–worker is about coordination: fan out, then synthesise one answer. Agent as tool is about reuse: a self-contained specialist that any orchestrator can pick up, while the orchestrator stays in control of the conversation.

4.5

How data flows through a team of agents

You've built two patterns. Now zoom out and follow one request as it moves through a multi-agent system, step by step.

The request: "What's the best laptop for video editing under ₹1,80,000?"

Swipe sideways to see the full diagram
Userinput Routersplits, rephrases Specs agentneeds for 4K editing Price agentcurrent retailer prices Review agentcustomer feedback "can we stretch the budget?" Aggregatorcombines Answer
One question, many hands. A router fans the request out, specialists work in parallel (and occasionally consult each other), and an aggregator merges everything into one reply.
Step through

Follow the laptop question

Pick step 1.
  1. 1

    The request arrives

    The question enters the system as raw text. Nothing has happened yet.

  2. 2

    The router makes decisions

    It reads the question and thinks: "This person needs product recommendations, price comparisons and technical specs. I know which agents can help." It sends work to the specs agent (knows what video editing needs), the price agent (searches current prices across retailers) and the review agent (analyses customer feedback). It doesn't forward the question blindly; it rephrases it for each. The specs agent gets "What CPU and GPU are needed for 4K video editing?"; the price agent gets "Find laptops under ₹1,80,000 with these specs."

  3. 3

    The agents do their thing

    All three work at the same time: one works out requirements, one searches retailer listings, one reads thousands of reviews. Each agent can keep its own memory of the conversation (in Strands, wrap it with as_tool(preserve_context=True); the default starts each call fresh), so if you mentioned your editing software earlier, the specs agent remembers.

  4. 4

    Agents talk to each other (sometimes)

    The price agent finds a laptop at ₹1,65,000, but the specs agent realises it doesn't have enough RAM for 4K. The price agent asks: "If we stretch the budget to ₹1,90,000, can we get something that works?" Agents negotiate and refine based on what the others find. (In a strict supervisor–worker setup this exchange goes through the supervisor; in collaborative setups, covered next, agents talk directly.)

  5. 5

    Results are combined

    An aggregator (often the supervisor) collects: specs agent: "At least 32 GB RAM, a recent mid-range dedicated GPU and a fast multi-core CPU." Price agent: "Three laptops match: ₹1,72,000, ₹1,79,000 and ₹1,86,000." Review agent: "The ₹1,79,000 one is rated 4.5 stars, with praise for rendering speed."

  6. 6

    You get your answer

    "I recommend Laptop B at ₹1,79,000. It meets the specs for 4K editing, fits your budget, and users specifically praise its rendering performance." It feels like one agent answered, but three specialists collaborated behind the scenes.

A single agent would have to know video-editing requirements, search several retailers, analyse reviews and synthesise everything itself: slower, more expensive and more likely to miss something. With several agents, each is an expert in its area, and they work in parallel. That raises the obvious next questions: how do agents share information, and how do you decide whether they work in sequence, in parallel or together?

4.6

How agents talk to each other

Agents working in isolation aren't a system; they're just separate programs. Communication is what turns them into a team.

Agents communicate in three main ways. Each solves a different problem and fits a different situation.

Sequential communication

Think of writing a research paper. You can't write the conclusion before the research, and you can't edit what hasn't been written. Some things must happen in order. In communication, one agent finishes and hands its results to the next.

Swipe sideways to see the full diagram
Researchagent findings Writingagent draft Editingagent Final output time research 10 min writing 15 min edit 5 10 + 15 + 5 = 30 minutes
A relay race. Each agent waits for the previous one; total time is the sum of every step.

The research agent might spend 10 minutes gathering information, the writing agent 15 minutes drafting, and the editing agent 5 minutes polishing: 30 minutes in total. The writing agent literally cannot start without the research, and the editor needs a complete draft.

+Use it when

There are real dependencies: step B needs step A's output. Bonus: only one agent calls the LLM at a time, which helps if your account has API .

−The cost

Time adds up with no overlap. And if the writing agent fails after 10 minutes of research, that time is wasted: everything downstream stops and the pipeline has to restart.

Parallel communication

Now picture planning a conference: one person books the venue, another arranges catering, a third handles marketing. None depends on the others, so they happen at the same time. In communication, several agents work simultaneously on different parts of a problem, and their results are combined when all have finished.

Swipe sideways to see the full diagram
User query runs simultaneously Pricing agent5 min Feedback agent5 min Trends agent5 min results collected Combined results 5 minutes, not 15
Everyone at once. Total time is the time of the slowest agent, not the sum.

Say you're analysing a market before a product launch and need three kinds of analysis. One agent scrapes a competitor's website and builds a pricing matrix (5 minutes). Another reads thousands of customer reviews of similar products, finding patterns in complaints and praise (5 minutes). A third analyses search trends, social media mentions and industry reports (5 minutes). Run them one after another and you wait 15 minutes; run them in parallel and you wait 5, the time of the slowest agent.

Parallel works best when tasks are independent: agent 1 doesn't need agent 2's results. It's also useful for accuracy, with several agents checking the same thing from different angles.

Try it

Sequential vs parallel timing

Sequential

Agent A
A
Agent B
B
Agent C
C
08152330 min

Parallel

Agent A
A
Agent B
B waits for A
Agent C
C waits
08152330 min
Sequential: 30 min. Parallel: impossible here. B needs A's output and C needs B's, so the work is forced into a sequence. Untick the dependency to see parallel speed-up.

Parallel for accuracy: let agents vote

Imagine a content-moderation system. Three agents independently check whether a post breaks community guidelines. Agent 1 says safe, agent 2 says safe, agent 3 says unsafe. Two of three vote safe, so the post is approved.

Agents make mistakes, but if they're independent they don't all make the same mistakes. If two of three agree, you can trust the result more than any single opinion; if all three flag something, you can be very confident it needs review. The maths backs this up: if each agent is wrong 5% of the time, independently, a majority vote of five agents is wrong only about 0.12% of the time, because at least three would have to be wrong together.

Swipe sideways to see the full diagram
Post Agent 1safe Agent 2safe Agent 3unsafe Vote2 safe · 1 unsafe Approve
Majority voting. One agent's mistake is outvoted by the other two, as long as their mistakes are independent.
Voting ruleHow it decidesFits
Simple majorityMore than half agreeContent moderation
UnanimousAll agents must agreeHigh-stakes calls such as a medical-diagnosis assistant
WeightedSome votes count moreLegal document review, where the specialist agent's vote weighs more
!Voting only works with independent agents

If every agent uses the same model, the same data source and the same reasoning, they'll make the same mistakes and voting adds nothing. You need diversity: different models, different data sources, different approaches.

Try it

How much does voting help?

Number of voting agents

One agent alone is wrong

5.00%

Majority vote is wrong

0.12%
43× fewer wrong decisions. The vote is only wrong when at least 3 of 5 agents are wrong on the same item, which is much rarer than one being wrong.

Collaborative communication

Think about designing a building. The architect proposes a design; the structural engineer says it won't bear the load; the architect adjusts; the interior designer suggests changes for better flow. They go back and forth until the design satisfies every constraint. In communication, agents talk to each other, share insights, negotiate trade-offs and refine their work together.

Here three agents review code: a developer agent wrote a function that processes user data, a security agent checks for vulnerabilities, and a performance agent makes sure it's fast enough. Step through their negotiation:

Swipe sideways to see the full diagram
Shared coderevised each round Developer agent Security agent Performance agent negotiate trade-offs, round after round
A real conversation. Unlike sequential (one direction) or parallel (no talking), collaborative agents push back on each other until every concern is met.
Step through

A code review negotiation

Security: openPerformance: openMemory use: not checked
    Read the whole conversation
    1. Developer: I've written a function that processes user data quickly.
    2. Security: This is vulnerable to SQL injection. You need to sanitise inputs.
    3. Developer: If I add sanitisation, performance drops by 40%.
    4. Performance: 40% slower is unacceptable. We have strict latency requirements.
    5. Security: Then use parameterised queries. They're secure and fast.
    6. Developer: Good idea. Let me refactor.
    7. Performance: Wait, you're loading the entire dataset into memory. Stream it instead.
    8. Developer: Done. All three concerns addressed.
    9. All agents review the updated code.
    10. Security: Secure now. Performance: Meets latency requirements. Developer: Code is ready.

    This back-and-forth doesn't happen in sequential or parallel setups. Sequential passes information one way; parallel agents work without talking. Collaboration is a real conversation that continues until the solution satisfies every agent's requirements, here balancing security, performance and maintainability. And it does work better on hard problems: experiments with multi-agent discussion show that iterative debate catches errors and explores alternatives a single agent would miss.

    +Use it when

    Agents must balance trade-offs with no single right answer: security vs performance, cost vs quality, speed vs accuracy. Decisions where one agent's recommendation affects another's.

    −The cost

    Several rounds of discussion means several rounds of LLM calls. One agent might answer in 10 seconds; three collaborating might take 30 to 40. It's slower, costlier, and harder to troubleshoot: finding which round introduced a bad decision takes more work than debugging a simple pipeline.

    TechniqueInformation flowsTimeBest for
    SequentialOne direction, A → B → CSum of all stepsReal dependencies; tight rate limits
    ParallelOut to everyone, then combinedThe slowest stepIndependent tasks; accuracy through voting
    CollaborativeBack and forth, in roundsSeveral rounds of callsTrade-offs with no single right answer

    Sequential, parallel and collaborative are the building blocks. Next you'll see how whole systems are organised around them.

    4.7

    Common orchestration patterns

    Supervisor–worker is the pattern most organisations use, but it isn't the only one. Two more solve very different problems: swarms and graphs.

    Each uses the communication building blocks you just learned, arranged for a specific kind of problem. A swarm lets agents decide who goes next; a graph makes you decide, in code, ahead of time. We cover the swarm (notebook 04) before the graph (notebook 03) because the graph is easiest to understand by contrast; you can run the two notebooks in either order.

    Swarm: agents hand work to each other

    A builds a whole system out of collaborative communication. The hard part of collaboration is coordination: who talks to whom, when, and how do you stop agents talking in circles? A swarm answers with : agents explicitly pass control to each other.

    ✦Think of it like this

    A game-design team building a stealth mission in an abandoned space station. The level designer creates the floor plan and a rough 3D . In playtesting, the game designer finds players get lost, so it goes back to the level designer, who adds landmarks and lighting. Then the narrative designer objects: bright lighting contradicts the story of a creepy, abandoned station. The level designer switches to dim emergency lights and environmental storytelling. Now the difficulty balancer finds the level too easy with clearer navigation, so back to the level designer for tougher enemy placement, without removing the visual cues. The path loops and branches based on what each specialist finds. Nobody could have predicted it up front.

    In a swarm you'd have four agents, level_designer, game_designer, narrative_designer and difficulty_balancer, each with its own expertise. There's no supervisor and no fixed sequence. When an agent finishes its part, it decides who should go next and hands off the task with context about what's been done.

    Swipe sideways to see the full diagram
    Briefing for the next agent • the handoff message• the original task• who has worked on it so far• notes passed along in handoffs• the other agents, and what they do level_designerlayout, visuals narrative_designerstory, atmosphere game_designerplaytests, final review difficulty_balancerdifficulty, pacing handoff_to_agent(...) entry point →
    No boss, just handoffs. Any agent can pass control to any other. Whoever picks up the task receives a briefing built by the swarm: the handoff message, the original task, who has worked on it, and any notes passed along.

    Run the notebook: 04_swarm_pattern.ipynb

    After the usual install and model cells:

    cell 3: imports and handoff logging
    import logging
    
    from strands import Agent
    from strands.multiagent import Swarm
    
    # Show each handoff as it happens
    logging.getLogger("strands.multiagent").setLevel(logging.DEBUG)
    logging.basicConfig(format="%(levelname)s | %(name)s | %(message)s", handlers=[logging.StreamHandler()])

    The two logging lines switch on Strands' multi-agent debug messages, so you can watch every handoff live.

    cell 4: specialist agents
    level_designer = Agent(
        name="level_designer",
        model=model,
        callback_handler=None,
        system_prompt="""You are a Level Designer in a game design swarm.
    Your role is to create level layouts, environments, and visual elements.
    Focus ONLY on layout and visual design. Do NOT write narrative or balance difficulty.
    After completing your layout, hand off to narrative_designer for story elements
    and difficulty_balancer for gameplay tuning.
    When receiving feedback from other agents, revise your design accordingly.""",
    )
    
    game_designer = Agent(
        name="game_designer",
        model=model,
        callback_handler=None,
        system_prompt="""You are a Game Designer in a game design swarm.
    Your role is to playtest designs for fun, usability, and player confusion.
    Focus ONLY on gameplay feel and player experience. Do NOT design layouts or write narrative.
    When you find issues, hand off to the appropriate specialist to fix them.
    When the design is ready, give the final summary and do not hand off.""",
    )
    
    narrative_designer = Agent(
        name="narrative_designer",
        model=model,
        callback_handler=None,
        system_prompt="""You are a Narrative Designer in a game design swarm.
    Your role is to create story elements, character backstories, and atmospheric details.
    Focus ONLY on narrative. Do NOT redesign layouts or adjust difficulty.
    After adding narrative elements, hand off to difficulty_balancer for balance review
    or game_designer for playtesting feedback.""",
    )
    
    difficulty_balancer = Agent(
        name="difficulty_balancer",
        model=model,
        callback_handler=None,
        system_prompt="""You are a Difficulty Balancer in a game design swarm.
    Your role is to evaluate and tune difficulty progression, enemy placement, and pacing.
    Focus ONLY on balance. Do NOT redesign layouts or write narrative.
    When you find layout or narrative issues, hand off to the appropriate agent.
    After balancing, hand off to game_designer for a final playtest review.""",
    )

    Read the prompts closely: each one says what the agent does, what it must not do ("Do NOT write narrative"), and whom to hand off to. The game designer's prompt contains the exit: "When the design is ready, give the final summary and do not hand off." A swarm finishes when an agent completes its turn without handing off.

    Create the swarm

    The swarm gives every agent a handoff_to_agent tool and a shared view of the work so far. For example, the game designer might call:

    a handoff, as the model calls it
    handoff_to_agent(
        agent_name="difficulty_balancer",
        message="Patrol patterns too predictable - need more variation",
    )
    cell 5
    swarm = Swarm(
        [level_designer, game_designer, narrative_designer, difficulty_balancer],
        entry_point=level_designer,
        max_handoffs=20,
        max_iterations=20,
        execution_timeout=1200.0,
        node_timeout=300.0,
        repetitive_handoff_detection_window=8,
        repetitive_handoff_min_unique_agents=3,
    )
    print("✓ Swarm created")
    SettingValueWhat it protects against
    entry_pointlevel_designerWhich agent starts. A layout has to exist before anyone can review it.
    max_handoffs20Caps how many times control can be passed.
    max_iterations20Caps the total number of agent turns. Without these limits, agents could loop forever. (In the current Strands version both are counted as completed agent turns, so they behave alike; setting both is belt and braces.)
    execution_timeout1200.0 sWall-clock cap for the whole swarm (20 minutes).
    node_timeout300.0 sWall-clock cap for any single agent's turn (5 minutes).
    repetitive_handoff_detection_window8: two agents bouncing the task back and forth without progress. The swarm looks at the last 8 turns; if fewer than 3 different agents appear, it stops. So if the level and narrative designers trade the task 8 times without anyone else, the loop is detected and the swarm ends.
    repetitive_handoff_min_unique_agents3

    Run the swarm (takes a few minutes)

    cell 6
    result = swarm("""Design a stealth mission level in an abandoned space station.
    The level needs to support multiple playstyles (aggressive stealth, patient stealth, and ghost runs).
    Include at least 3 distinct zones with different difficulty levels,
    narrative elements that explain why the station was abandoned,
    and ensure the difficulty curve is appropriate for mid-game players.""")
    
    print("=" * 80)
    print("HANDOFF CHAIN:")
    for node in result.node_history:
        print(f"  → {node.node_id}")
    print(f"\nStatus: {result.status} | iterations: {result.execution_count} | time: {result.execution_time / 1000:.0f}s")
    outputillustrative; your path will differ
    DEBUG | strands.multiagent.swarm | current_node=<level_designer>, iteration=<1> | executing node
    DEBUG | strands.multiagent.swarm | from_node=<level_designer>, to_node=<narrative_designer> | handoff detected
    DEBUG | strands.multiagent.swarm | current_node=<narrative_designer>, iteration=<2> | executing node
    DEBUG | strands.multiagent.swarm | from_node=<narrative_designer>, to_node=<difficulty_balancer> | handoff detected
    DEBUG | strands.multiagent.swarm | current_node=<difficulty_balancer>, iteration=<3> | executing node
    DEBUG | strands.multiagent.swarm | from_node=<difficulty_balancer>, to_node=<game_designer> | handoff detected
    DEBUG | strands.multiagent.swarm | current_node=<game_designer>, iteration=<4> | executing node
    DEBUG | strands.multiagent.swarm | from_node=<game_designer>, to_node=<level_designer> | handoff detected
    ...
    DEBUG | strands.multiagent.swarm | node=<game_designer> | no handoff occurred, marking swarm as complete
    DEBUG | strands.multiagent.swarm | status=<Status.COMPLETED> | swarm execution completed
    DEBUG | strands.multiagent.swarm | node_history_length=<11>, time=<486.46>s | metrics
    ================================================================================
    HANDOFF CHAIN:
      → level_designer
      → narrative_designer
      → difficulty_balancer
      → game_designer
      → level_designer
      → game_designer
      → …
      → game_designer
    
    Status: Status.COMPLETED | iterations: 11 | time: 486s

    Read the chain as a story. The level designer drew the layout and handed off to the narrative designer for story elements, who added the backstory and passed it to the difficulty balancer for tuning, who handed off to the game designer for playtesting. The game designer found navigation problems in zone 2 and sent it back to the level designer. That back-and-forth continued for 11 turns until the game designer approved the final design. Nobody programmed this sequence. The agents worked it out from what needed to happen next.

    cell 7: show the final design
    from IPython.display import Markdown, display
    
    last_node = result.node_history[-1].node_id
    display(Markdown(str(result.results[last_node].result)))

    result.node_history lists every turn in order; the last entry is the agent that finished (usually the game designer with its final summary). result.results maps each agent's name to its last output, which this cell renders as Markdown.

    How a handoff works under the hood

    Handoffs happen through tool calls. When you create a Swarm, every agent automatically gets a handoff_to_agent tool, and the swarm keeps a shared record of the run. Say the game designer finishes playtesting and finds enemy patrols are too predictable. That's a difficulty problem, not a playtesting problem, so it needs someone who can tune the challenge. When its turn began, the swarm gave the game designer a formatted briefing that includes:

    1. 1

      The handoff message

      What the previous agent said it needs, for example "Add landmarks in zone 2".

    2. 2

      The original task

    3. 3

      The agents who have worked on it so far

      For example level_designer → game_designer.

    4. 4

      What previous agents contributed

      As "shared knowledge from previous agents": whatever notes an agent chose to pass in the handoff's optional context argument.

    5. 5

      The other available agents

      By name, plus each one's description if you gave it one. The game designer reads: the level designer creates layouts and visuals; the narrative designer creates story and atmosphere; the difficulty balancer tunes difficulty, enemy placement and pacing.

    The patrol problem matches the difficulty balancer, so the game designer calls handoff_to_agent(agent_name="difficulty_balancer", message="Patrol patterns too predictable - need more variation"). Now the difficulty balancer is in control and receives the same formatted context, including what the game designer found. The LLM makes each routing decision by matching the problem to what each agent does.

    !Write handoffs like a good shift-change note

    Each agent's own conversation is reset before its turn, so a returning level designer doesn't automatically see its earlier layout. Knowledge travels in the handoff message (and optional context). Prompting agents to summarise what they did and what's needed when they hand off makes swarms work much better.

    iTip: give swarm agents a description

    The lab's agents rely on their names and prompts. Adding description="Tunes difficulty, enemy placement and pacing" to each Agent(...) puts that text in every teammate's list of available agents, which makes handoff choices more reliable.

    Try it

    Run a swarm, one turn at a time

    Swarm log

    • Entry point: level_designer. Press Next turn.

    Briefing the next agent receives

    User Request: Design a stealth mission level in an abandoned space station… Other agents available for collaboration: Agent name: game_designer. Agent name: narrative_designer. Agent name: difficulty_balancer. If you don't hand off to another agent, the swarm will consider the task complete.

    Last 8 turns: unique agents

    0 unique in the last 0 turns (stop if under 3 across 8)
    +Use a swarm for

    Creative and iterative work where you can't predict the path up front. Sometimes the layout passes every reviewer first time; sometimes it bounces around as new problems appear. You define the agents and their strengths; they work out who handles each issue.

    −Don't use one when

    You need a fixed sequence where certain checks always happen in a specific order. That's the graph pattern's job.

    Graph: you define the paths

    The is built on a : data flows along defined paths from one node to the next. There are two flavours:

    Swipe sideways to see the full diagram
    DAG: directed, acyclicarrows only point forward, never loop back risk check fraud check shipping Once an order clears fraud detection,it never goes back to the risk check. Cyclic graphdata can loop back to earlier nodes developer reviewer code issues found done Loops until the reviewer approves.
    Forward-only vs loops. Production workflows mostly use , so that's the focus here. (Strands also supports cyclic graphs, with safety limits such as a cap on total node executions and timeouts.)

    "Isn't that what a swarm does?" The key difference: in a swarm, agents decide the path; in a graph, you define the paths up front. Before the example, the building blocks:

    Nodes

    Anything that processes data. In Strands a node can be a single agent (like a fraud-detection agent), a swarm of agents, another graph (graphs can be nested), or custom business logic: your own deterministic code wrapped as a node.

    Edges

    The connections. An edge says "when node A finishes, pass its output to node B". Edges can carry , for example "only follow this edge if the order is over $1,000".

    Dependencies

    If node B depends on node A, A must finish before B starts. The graph manages this and runs nodes in the right order. When several arrows lead into one node (like inventory check below), it runs as soon as one incoming arrow fires.

    The example: processing e-commerce orders

    Orders arrive all day. Some are small purchases from regular customers; some are big orders from brand-new accounts; some ship somewhere that doesn't match the billing address. You can't treat them all the same way.

    You could use supervisor–worker: the supervisor reads each order and decides where to send it. It works, until your payment processor asks, "How do you guarantee high-value orders always get fraud review?" With a supervisor, the routing happens inside the LLM's reasoning. You can log it, but the decision logic isn't explicit in your code.

    A graph makes the routing explicit. The risk analyser runs first; high-value orders go to manual review; suspicious ones go to fraud detection; clean, low-risk orders go straight to the inventory check. The decision tree is visible in your code, and anyone can see exactly what happens to each kind of order.

    Swipe sideways to see the full diagram
    Order received Risk analyzerrisk_analysis HIGH_VALUE Manual reviewmanual_review SUSPICIOUS Advanced fraud checkfraud_check LOW_RISK No extra checkedge goes straight to inventory Inventory checkinventory_check IN_STOCK Shippinglabel, dispatch OUT_OF_STOCK Refundcustomer refunded
    Every path drawn in advance. Three ways in, one meeting point at inventory, two possible endings. The labels on the edges are the exact words the routing code looks for. The dashed box isn't a node: low-risk orders go straight from risk analysis to the inventory check.
    1. 1

      High-value orders go to manual review first

    2. 2

      Suspicious orders go to advanced fraud detection

      Red flags such as a billing and shipping mismatch, or a brand-new account placing a large order.

    3. 3

      Low-risk orders from trusted customers skip the checks

      They go straight to inventory.

    4. 4

      All three paths meet at the inventory check

      In stock: shipping generates a label and the package goes out. Out of stock: refund processing notifies the customer and returns the payment. Every order ends in one of these two states.

    Directed means arrows point one way: from the risk analyser to fraud check, never backwards. Acyclic means no loops: you can't go risk analyser → fraud check → inventory → back to risk analyser, which could cycle forever. That structure guarantees every order eventually reaches an end state, shipped or refunded.

    That's why graphs are great for compliance and auditability. When your payment processor asks about fraud prevention, you point at the graph. The logic lives in code, not hidden in LLM reasoning. A large order from a new customer always follows the same path; it doesn't vary with how an LLM reads the situation that day.

    ?So where does the LLM fit?

    The graph defines the flow; each node is still an agent that uses an LLM for its task. The risk analyser understands the order in natural language, the fraud agent reasons about suspicious patterns, the inventory agent interprets stock data. You define the routing; the LLMs do the reasoning at each step.

    Run the notebook: 03_graph_pattern.ipynb

    After the usual install and model cells:

    cell 3
    from strands import Agent
    from strands.multiagent import GraphBuilder

    The two "decision" agents end their answer with a fixed line (RISK_CATEGORY: ..., STOCK_STATUS: ...). The routing functions read only that line, so an explanation that merely mentions another category can't send the order down the wrong path.

    cell 4: specialised agents
    risk_analyzer = Agent(
        name="risk_analyzer",
        model=model,
        callback_handler=None,
        system_prompt="""Analyze the order's risk level and pick exactly ONE category:
    - HIGH_VALUE: orders over $1,000
    - SUSPICIOUS: mismatched billing/shipping country, brand-new account with a large order, or known fraud patterns
    - LOW_RISK: regular orders from trusted customers
    If more than one applies, SUSPICIOUS wins over HIGH_VALUE.
    Give a one-paragraph explanation, then finish with a final line in exactly this format:
    RISK_CATEGORY: <HIGH_VALUE|SUSPICIOUS|LOW_RISK>""",
    )
    
    manual_review_agent = Agent(
        name="manual_review_agent",
        model=model,
        callback_handler=None,
        system_prompt="Review high-value orders. Verify customer identity, check order history, and approve or flag for further review.",
    )
    
    fraud_detection_agent = Agent(
        name="fraud_detection_agent",
        model=model,
        callback_handler=None,
        system_prompt="Run fraud detection on suspicious orders: known fraud patterns, velocity checks, and device fingerprinting. Decide whether to proceed.",
    )
    
    inventory_agent = Agent(
        name="inventory_agent",
        model=model,
        callback_handler=None,
        system_prompt="""Check inventory for the order items. Assume laptops, books and phones are in stock and
    anything described as 'limited edition' or 'pre-order' is out of stock.
    Explain briefly, then finish with a final line in exactly this format:
    STOCK_STATUS: <IN_STOCK|OUT_OF_STOCK>""",
    )
    
    shipping_agent = Agent(
        name="shipping_agent",
        model=model,
        callback_handler=None,
        system_prompt="Generate a shipping label and process the shipment. Confirm a tracking number and estimated delivery date.",
    )
    
    refund_agent = Agent(
        name="refund_agent",
        model=model,
        callback_handler=None,
        system_prompt="Process a refund for out-of-stock items. Notify the customer and initiate the payment reversal.",
    )
    
    print("✓ All agents created")
    iTwo lab conveniences

    The risk rules use dollars ($1,000) to match the sample orders. And the inventory agent pretends to check stock using a simple rule (laptops, books and phones in stock; "limited edition" and "pre-order" out of stock). In a real system that node would call your inventory database as a tool.

    Routing conditions

    Each condition reads the previous node's output and returns True or False. The logic is plain Python, not hidden inside model reasoning.

    cell 5
    import re
    
    
    def decision(state, node_id: str, label: str) -> str:
        """Return the value of the final 'LABEL: VALUE' line written by a node."""
        text = str(state.results.get(node_id, ""))
        matches = re.findall(rf"{label}\s*:\s*([A-Z_]+)", text.upper())
        return matches[-1] if matches else ""
    
    
    def is_high_value(state):
        return decision(state, "risk_analysis", "RISK_CATEGORY") == "HIGH_VALUE"
    
    
    def is_suspicious(state):
        return decision(state, "risk_analysis", "RISK_CATEGORY") == "SUSPICIOUS"
    
    
    def is_low_risk(state):
        return decision(state, "risk_analysis", "RISK_CATEGORY") == "LOW_RISK"
    
    
    def is_in_stock(state):
        return decision(state, "inventory_check", "STOCK_STATUS") == "IN_STOCK"
    
    
    def is_out_of_stock(state):
        return decision(state, "inventory_check", "STOCK_STATUS") == "OUT_OF_STOCK"
    
    
    print("✓ Routing conditions defined")
    1. a

      state.results

      The graph's record of every node's output so far, keyed by node ID. str(...) turns a node's result into its text.

    2. b

      The

      RISK_CATEGORY\s*:\s*([A-Z_]+) finds "RISK_CATEGORY", optional spaces, a colon, optional spaces, then captures a word in capitals and underscores. .upper() makes it case-insensitive, and matches[-1] takes the last match, the required final line, so earlier mentions in the explanation are ignored.

    3. c

      Five tiny conditions

      One per edge that needs a decision. Each is a one-line, testable Python function.

    Build the graph

    cell 6
    builder = GraphBuilder()
    
    # Nodes
    builder.add_node(risk_analyzer, "risk_analysis")
    builder.add_node(manual_review_agent, "manual_review")
    builder.add_node(fraud_detection_agent, "fraud_check")
    builder.add_node(inventory_agent, "inventory_check")
    builder.add_node(shipping_agent, "shipping")
    builder.add_node(refund_agent, "refund")
    
    # Conditional edges out of risk analysis
    builder.add_edge("risk_analysis", "manual_review", condition=is_high_value)
    builder.add_edge("risk_analysis", "fraud_check", condition=is_suspicious)
    builder.add_edge("risk_analysis", "inventory_check", condition=is_low_risk)
    
    # Review / fraud check → inventory
    builder.add_edge("manual_review", "inventory_check")
    builder.add_edge("fraud_check", "inventory_check")
    
    # Inventory → ship or refund
    builder.add_edge("inventory_check", "shipping", condition=is_in_stock)
    builder.add_edge("inventory_check", "refund", condition=is_out_of_stock)
    
    builder.set_entry_point("risk_analysis")
    graph = builder.build()
    print("✓ Graph built")
    
    
    def show_path(result):
        path = " → ".join(node.node_id for node in result.execution_order)
        print(f"Status: {result.status}\nPath:   {path}")
        last = result.execution_order[-1].node_id
        print(f"\nFinal step ({last}):\n{result.results[last].result}")
    output
    UserWarning: … no max_node_executions or execution_timeout set …
    ✓ Graph built

    The warning is expected. Strands is reminding you that this graph has no overall execution limit; for a forward-only graph like this one that's fine, because every run ends at shipping or refund. For cyclic graphs, set limits with builder.set_max_node_executions(...) or an execution timeout.

    add_node(agent, "node_id") registers each agent under a short ID. add_edge(from, to, condition=...) draws an arrow; with a condition, the arrow is only followed when the function returns True. Edges without a condition are always followed. set_entry_point says where every run starts, and build() validates the setup (at least one node, a valid entry point) and returns a runnable graph. show_path prints the route an order took, using result.execution_order, and the last node's output.

    Process orders: each one takes a different path

    cell 7
    # High value → manual review → inventory → shipping
    result = graph("Order #12345: $1,500 laptop from an existing customer with 3 previous orders; billing and shipping address match")
    show_path(result)
    outputillustrative
    Status: Status.COMPLETED
    Path:   risk_analysis → manual_review → inventory_check → shipping
    
    Final step (shipping):
    Shipping label generated for Order #12345 (1 × laptop). Tracking number: …
    Estimated delivery: 3–5 business days.
    cell 8
    # Low risk → inventory → shipping
    result = graph("Order #67890: $45 book from a returning customer with 50+ previous orders")
    show_path(result)
    outputillustrative
    Status: Status.COMPLETED
    Path:   risk_analysis → inventory_check → shipping
    cell 9
    # Suspicious → fraud check → inventory → refund (limited edition is out of stock)
    result = graph(
        "Order #11111: $800 limited edition headphones, account created 5 minutes ago, "
        "shipping to a different country than the billing address"
    )
    show_path(result)
    outputillustrative
    Status: Status.COMPLETED
    Path:   risk_analysis → fraud_check → inventory_check → refund
    
    Final step (refund):
    Refund initiated for Order #11111: limited edition headphones are out of stock. The customer has been notified …

    Same graph, three orders, three different paths, and each path is fully explained by the edges you wrote. Run the same order again and it takes the same path.

    Try it

    Send an order through the graph

    Set up an order, then process it. The path lights up in the diagram above.

    Use graphs wherever you have an established procedure: e-commerce order processing, compliance workflows, approval chains, content moderation, or anywhere you must prove that certain checks always happen in a certain order. Don't use one when the path can't be predicted up front; that's a swarm's job.

    Choosing a pattern

    PatternWho decides the path?Best forTrade-off
    Supervisor–workerThe supervisor agentCentralised coordination with one synthesised answer; parallel researchSupervisor is a bottleneck and a single point of failure
    Agent as toolThe orchestrator picks from available tools, and stays in controlReusable agents across different systems; simple delegationAgents only communicate through the orchestrator; nested calls add latency
    SwarmThe agents, through handoffsCreative or iterative work where the path can't be predictedHarder to debug; the order of work varies between runs
    Graph (DAG)You, in code (conditional edges)Fixed, auditable procedures and compliance workflowsEvery possible path must be defined up front
    </>Patterns combine

    Most production systems mix them. A supervisor might coordinate workers that run in parallel; a graph node might itself be a swarm; a specialist used as a tool might be a small graph. Match the pattern to your constraints, one layer at a time.

    4.8

    When multi-agent is not the answer

    You now know supervisor–worker, swarms and graphs. Here's what doesn't get said often enough: most problems don't need multiple agents.

    It's a common story. Someone learns about multi-agent systems and immediately rebuilds a working single-agent app as five agents coordinating through a graph. The demo looks impressive. Then it goes live.

    Debugging becomes a nightmare. Which agent failed? Was it agent three's input or agent two's output? The logs show five execution paths and you're tracing which one ran. The single agent used to answer in 3 seconds; the multi-agent version takes 12 because of coordination overhead. And the error rate went up, because there are now five points of failure instead of one.

    Swipe sideways to see the full diagram
    One agent + good tools Agent tools Response time3 s Points of failure1 Paths to debug1 Five agents in a graph Response time12 s Points of failure5 Paths to debug5
    Complexity has a price. Coordination overhead, more ways to fail, and much harder debugging. Pay it only when you get something real in return.
    ✦Think of it like this

    You don't hire a committee to fix a leaking tap. A good plumber with the right toolkit is faster, cheaper and easier to hold accountable. You call in a team for building a house, not for every job.

    A single agent with good tools beats a poorly designed multi-agent system. Before you design something complex, try giving one agent the right tools. Can it call your APIs? Query your databases? Run code? Read your documentation? If you structure the tools well, most problems fit in one agent's context window.

    The patterns in this section solve real problems, but they aren't default architectures. You'll know you need multiple agents when you hit actual limits:

    1. 1

      The context window keeps filling up

      You're processing thousands of documents and the agent loses track.

    2. 2

      You need true parallelism

      Waiting for three sequential 30-second API calls is too slow for your users.

    3. 3

      The expertise genuinely doesn't fit in one prompt

      The roles need such different instructions and tools that one prompt becomes a muddle.

    iThe rule of thumb

    Start with one agent, give it tools, and test it. Only add agents when one agent clearly can't cope. Three agents that work reliably beat ten that don't.

    Try it

    Do you need a team? Which one?

    1. Can one agent with good tools already do the job well?

    2. Do parts of the work need genuinely different expertise, prompts or tools?

    3. Must certain steps always happen in a fixed, auditable order?

    4. Can you predict the path the work will take?

    5. Do you need one combined answer from several independent specialists?

    Answer the questions above.
    4.9

    Recap and self-check

    You can now build teams of agents, and, just as importantly, decide when not to.

    You started with the basic question of when several agents beat one. You built a supervisor that fans questions out to news, financial and sentiment workers and synthesises one answer, and a teacher that reuses specialist tutors as tools. You followed data through a multi-agent system and learned the three ways agents communicate: sequential for dependencies, parallel for speed (and voting for accuracy), and collaborative for negotiating trade-offs. Then you organised whole systems: a swarm that hands work around when the path can't be predicted, and a graph with explicit, auditable routes. Most production systems combine these patterns; the skill is matching the pattern to your constraints.

    You should now be able to explain

    IdeaIn one line
    Signs you need a teamContext overload, mediocre results everywhere, no parallelism, hard to debug
    Four aspectsOrchestration, specialisation, collaboration, coordination
    Supervisor–workerA coordinator fans out to specialists, who never talk to each other, then synthesises one answer
    agent.as_tool()Turns an agent into a tool; its name and description tell the caller when to use it
    Agent as toolBuild a specialist once, reuse it anywhere; the orchestrator stays in control
    Sequential / parallel / collaborativeSum of times / slowest time / several rounds of calls
    VotingIndependent agents outvote each other's mistakes; correlated agents don't
    SwarmAgents hand off with handoff_to_agent, share context, and stop when nobody hands off; limits prevent loops
    GraphNodes, edges with conditions, dependencies; routing lives in code, so it's auditable
    When not toOne agent with good tools first; add agents only at a real limit

    When something goes wrong

    What you seeWhat it usually means and how to fix it
    "TAVILY_API_KEY not set", or the news agent says it can't searchExport the key before starting Jupyter, or set it in the commented lines of the keys cell, then re-run the cells that create the agents.
    Financial numbers show "N/A"Yahoo Finance left that field empty for this ticker. _num handles it; the agent works with what's available.
    ThrottlingException from BedrockParallel workers and swarms make many calls quickly. Wait and retry, run fewer questions at once, or ask for a higher quota.
    The teacher answers the question itselfIts prompt says "Never solve problems yourself". Check the prompt ran unchanged and the tutors are in tools=[...].
    A graph run stops after risk_analysisNo condition matched: the risk analyser didn't end with a valid RISK_CATEGORY: line. Print result.results["risk_analysis"].result to see what it wrote.
    The swarm stops early (Status.FAILED) with a repetitive-handoff, max-handoffs or timeout reasonThe safety limits did their job. Make the prompts clearer about who to hand off to and when to finish, or raise the limits slightly.
    The swarm takes several minutesNormal: 10 or more full agent turns. Each costs model calls, so don't run it in a loop.
    iNothing to clean up

    These notebooks only call Bedrock (and the Tavily and Yahoo Finance APIs). They create no AWS resources, so there's nothing to delete. The cost is model usage, which is highest for the swarm.

    Self-check

    Ten quick questions. Pick an answer to see why it's right or wrong.

    1. Which is NOT one of the warning signs that one agent is carrying too much?

    2. Three parallel workers each returned a correct answer, but the investor still asked “So, should I invest?” What was missing?

    3. In supervisor–worker, how does the sentiment agent share a finding with the financial agent?

    4. What do an agent's name and description become when you use it as a tool?

    5. You want to add a history tutor to the teacher. What do you change?

    6. Agents take 10, 15 and 5 minutes, and none depends on another. How long does parallel execution take?

    7. Five moderation agents use the same model, same data and same prompt. Does majority voting cut errors much?

    8. How does a Strands swarm know it is finished?

    9. Two swarm agents keep passing the task back and forth. Which settings stop that?

    10. Your payment processor asks you to prove that high-value orders always get reviewed. Which pattern makes that easiest?

    Score: 0 of 10 answered

    →Up next: Section 5, MCP and A2A

    So far your agents have lived in one notebook. Next you'll connect them across processes with two open protocols: MCP, which connects an agent to tools and data served by other programs, and A2A, which lets independent agents discover and call each other. Folder: section-05-mcp-and-a2a.

    A–Z

    Glossary

    Every underlined word on this page, in one place.

    Agent as tool

    Wrapping an agent so other agents can call it like a normal tool. Its name and description tell callers when to use it.

    Blockout

    In game design, a rough 3D draft of a level built from simple shapes, used to test layout before any detailed art.

    Bottleneck

    The narrowest point in a system, where work queues up because everything must pass through it.

    Collaborative communication

    Agents talk back and forth, critique each other and negotiate until a solution satisfies all their constraints.

    Concurrently

    At the same time. Strands runs the tool calls a model requests in one turn concurrently by default, so independent workers don't wait for each other.

    Context rot

    The drop in accuracy when a model's context is stuffed with too much or irrelevant material: it loses focus, misses details and makes mistakes.

    DAG (directed acyclic graph)

    A directed graph with no loops: arrows only point forward, so every run is guaranteed to reach an end.

    Directed graph

    A set of nodes connected by arrows that point one way, from one node to the next.

    Edge condition

    A small function attached to a graph edge that returns True or False. The edge is followed only when it returns True.

    Failover

    Automatically switching to a standby copy when the main one fails.

    Graph pattern

    A pattern where you define, in code, the nodes (steps) and edges (allowed paths with conditions) that work must follow.

    Handoff

    One agent explicitly passing control of the task to another agent, with a message about what it needs.

    Horizontal scaling

    Handling more load by running more copies of a component side by side, rather than making one copy bigger.

    Multi-agent pattern

    A reusable way of organising several AI agents to work towards one goal: who talks to whom, who decides the order, and how results are combined.

    Orchestrator

    The agent (or code) that decides which other agents or tools to call, in what order, and combines the results.

    Parallel communication

    Several agents work at the same time on independent parts of a problem; results are combined at the end. Total time is the slowest step.

    Ping-pong (in a swarm)

    Two agents passing the same task back and forth without making progress. Strands detects it by counting unique agents in recent turns.

    Prompt caching

    Reusing the processed form of a long, repeated prompt prefix (such as a big system prompt) so later calls are faster and cheaper.

    Rate limit

    A cap on how many requests (or tokens) you may send to an API per minute. Going over it gets your calls throttled.

    Regular expression (regex)

    A compact pattern language for finding text, such as "the word after RISK_CATEGORY:".

    Sequential communication

    Agents work one after another; each passes its output to the next. Total time is the sum of the steps.

    Single point of failure

    One component whose failure stops the whole system.

    Supervisor–worker

    A pattern where one coordinating agent delegates subtasks to specialist worker agents and combines their results. Workers only talk to the supervisor.

    Swarm

    A pattern with no central coordinator: agents hand control to each other through handoffs, sharing one context, until one finishes without handing off.

    © 2026 Shivank Agrawal, Future with Shivank. Agentic AI on AWS, Section 4. Course code is provided under the MIT License.

    AWS service names, tool names and library versions change often. When something here differs from what you see, the current documentation wins.