@shinyaz

Strands Agents SDK Multi-Agent — Autonomous Agent Collaboration with Swarm

Table of Contents

Introduction

In the introductory series we learned agent basics, and in the practical series we learned output control and behavior monitoring. In Part 5 of the intro series, we used the Agents as Tools pattern to coordinate multiple agents, but that pattern had the orchestrator controlling everything.

Just pass agents to Swarm and they autonomously hand off tasks to each other.

In this article, we'll try:

  1. Basics — Create and run a Swarm
  2. How handoffs work — Shared context and autonomous handoffs
  3. 4-agent Swarm — Autonomous route selection
  4. Safety mechanismsmax_handoffs in action

See the official documentation at Swarm.

Setup

Use the same environment from the introductory series. For a fresh setup:

Terminal
mkdir my_agent && cd my_agent
python -m venv .venv
source .venv/bin/activate
pip install strands-agents strands-agents-tools

All examples use the same model configuration and can be run as independent .py files. Write the common setup at the top, then add each example's code below it.

Python (common setup)
from strands import Agent
from strands.models import BedrockModel
from strands.multiagent import Swarm
 
bedrock_model = BedrockModel(
    model_id="us.anthropic.claude-sonnet-4-20250514-v1:0",
    region_name="us-east-1",
)

Basics — Creating and Running a Swarm

Let's have a researcher and writer collaborate on a task: "research a topic and summarize the findings."

With Agents as Tools, the orchestrator called specialized agents wrapped in @tool. With Swarm, you just pass agents as a list and they hand off to each other autonomously.

Python
researcher = Agent(
    name="researcher",
    model=bedrock_model,
    system_prompt="You are a research specialist. Research the given topic and hand off to the writer when you have enough information.",
    callback_handler=None,
)
 
writer = Agent(
    name="writer",
    model=bedrock_model,
    system_prompt="You are a writing specialist. Write a concise summary based on the research provided. Do not hand off to another agent.",
    callback_handler=None,
)
 
swarm = Swarm(
    [researcher, writer],
    entry_point=researcher,
    max_handoffs=10,
    max_iterations=10,
)
 
result = swarm("What is Amazon Bedrock? Summarize in 2-3 sentences.")

The Swarm constructor takes just a list of agents. entry_point specifies which agent runs first. max_handoffs and max_iterations are safety limits to prevent infinite loops. callback_handler=None on each agent disables streaming output to the console — all subsequent examples use the same setting.

Key differences from Agents as Tools:

Agents as ToolsSwarm
ControlOrchestrator decidesAgents decide autonomously
HandoffVia @tool wrapperhandoff_to_agent tool auto-injected
Context sharingOrchestrator relaysShared context auto-managed
Code@tool wrappers neededJust pass a list of agents
01_swarm_basic.py full code (copy-paste)
01_swarm_basic.py
from strands import Agent
from strands.models import BedrockModel
from strands.multiagent import Swarm
 
bedrock_model = BedrockModel(
    model_id="us.anthropic.claude-sonnet-4-20250514-v1:0",
    region_name="us-east-1",
)
 
researcher = Agent(
    name="researcher",
    model=bedrock_model,
    system_prompt="You are a research specialist. Research the given topic and hand off to the writer when you have enough information.",
    callback_handler=None,
)
 
writer = Agent(
    name="writer",
    model=bedrock_model,
    system_prompt="You are a writing specialist. Write a concise summary based on the research provided. Do not hand off to another agent.",
    callback_handler=None,
)
 
swarm = Swarm(
    [researcher, writer],
    entry_point=researcher,
    max_handoffs=10,
    max_iterations=10,
)
 
result = swarm("What is Amazon Bedrock? Summarize in 2-3 sentences.")
 
print(f"Status: {result.status}")
print(f"Node history: {[node.node_id for node in result.node_history]}")
print(f"Execution count: {result.execution_count}")
print(f"Execution time: {result.execution_time}ms")
 
for node_id, node_result in result.results.items():
    print(f"\n--- {node_id} ---")
    print(f"  Status: {node_result.status}")
    if node_result.result and node_result.result.message:
        for block in node_result.result.message.get('content', []):
            if 'text' in block:
                print(f"  Output: {block['text'][:150]}...")
                break
Terminal
python -u 01_swarm_basic.py

Result

Output
Status: Status.COMPLETED
Node history: ['researcher', 'writer']
Execution count: 2
Execution time: 12314ms
 
--- researcher ---
  Status: Status.COMPLETED
 
--- writer ---
  Status: Status.COMPLETED
  Output: Amazon Bedrock is a fully managed AWS service that provides access to foundation models from leading AI companies...

The researcher ran first, and once research was complete, it handed off to the writer. The node_history confirms the execution order.

Note that the researcher's text output is empty. Instead of returning text, it called the handoff_to_agent tool to hand off to the writer. The final text output comes from the writer, which finished without handing off.

How Handoffs Work

Swarm automatically injects a handoff_to_agent tool into each agent. Agents autonomously decide "which agent should handle this next" and call this tool to hand off.

The shared context managed by Swarm includes:

  • Original task — The user's input
  • Handoff history — Which agents ran in what order
  • Shared knowledge — Information accumulated by each agent
  • Available agents — Candidates for handoff

Each agent references this context to decide which agent to hand off to next. Developers don't need to write handoff logic.

Key fields in the result object:

FieldDescription
result.statusExecution status (COMPLETED, FAILED, etc.)
result.node_historyOrdered history of executed nodes
result.execution_countTotal execution count
result.execution_timeTotal execution time (milliseconds)
result.resultsPer-node results (node_idNodeResult)

The node_history showing ['researcher', 'writer'] confirms the researcher → writer handoff order. With 3+ agents, the handoff order may vary based on LLM judgment.

4-Agent Swarm — Autonomous Route Selection

Let's have 4 agents — researcher → architect → coder → reviewer — collaborate on "designing a REST API." With 2 agents the handoff order was predictable, but with more agents the LLM autonomously chooses the route.

Python
researcher = Agent(
    name="researcher", model=bedrock_model,
    system_prompt="You are a research specialist. Research the topic and hand off to the most appropriate next agent.",
    callback_handler=None,
)
architect = Agent(
    name="architect", model=bedrock_model,
    system_prompt="You are a system architecture specialist. Design a high-level architecture. Hand off to the coder when done.",
    callback_handler=None,
)
coder = Agent(
    name="coder", model=bedrock_model,
    system_prompt="You are a coding specialist. Write pseudocode based on the architecture. Hand off to the reviewer when done.",
    callback_handler=None,
)
reviewer = Agent(
    name="reviewer", model=bedrock_model,
    system_prompt="You are a code review specialist. Review and provide a final summary. Do not hand off.",
    callback_handler=None,
)
 
swarm = Swarm(
    [researcher, architect, coder, reviewer],
    entry_point=researcher,
    max_handoffs=10,
    max_iterations=10,
)
 
result = swarm("Design a simple REST API for a todo app")
02_swarm_team.py full code (copy-paste)
02_swarm_team.py
from strands import Agent
from strands.models import BedrockModel
from strands.multiagent import Swarm
 
bedrock_model = BedrockModel(
    model_id="us.anthropic.claude-sonnet-4-20250514-v1:0",
    region_name="us-east-1",
)
 
researcher = Agent(
    name="researcher", model=bedrock_model,
    system_prompt="You are a research specialist. Research the topic and hand off to the most appropriate next agent.",
    callback_handler=None,
)
architect = Agent(
    name="architect", model=bedrock_model,
    system_prompt="You are a system architecture specialist. Design a high-level architecture. Hand off to the coder when done.",
    callback_handler=None,
)
coder = Agent(
    name="coder", model=bedrock_model,
    system_prompt="You are a coding specialist. Write pseudocode based on the architecture. Hand off to the reviewer when done.",
    callback_handler=None,
)
reviewer = Agent(
    name="reviewer", model=bedrock_model,
    system_prompt="You are a code review specialist. Review and provide a final summary. Do not hand off.",
    callback_handler=None,
)
 
swarm = Swarm(
    [researcher, architect, coder, reviewer],
    entry_point=researcher,
    max_handoffs=10, max_iterations=10,
)
 
result = swarm("Design a simple REST API for a todo app")
 
print(f"Status: {result.status}")
print(f"Node history: {[n.node_id for n in result.node_history]}")
print(f"Execution count: {result.execution_count}")
print(f"Execution time: {result.execution_time}ms")
Terminal
python -u 02_swarm_team.py

Result

Output
Status: Status.COMPLETED
Node history: ['researcher', 'architect', 'coder', 'reviewer']
Execution count: 4
Execution time: 83638ms

The 4 agents autonomously handed off in the order researcher → architect → coder → reviewer. This order wasn't specified by the developer — each agent decided "who should handle this next" based on the shared context. Depending on the task, the researcher might hand off directly to the coder.

Safety Mechanisms — max_handoffs in Action

Let's see "what happens when max_handoffs is set too low" with the same 4-agent Swarm.

Set max_handoffs=2 to limit handoffs.

Python
swarm = Swarm(
    [researcher, architect, coder, reviewer],
    entry_point=researcher,
    max_handoffs=2,
    max_iterations=10,
)
 
result = swarm("Design a simple REST API for a todo app")
03_swarm_limit.py full code (copy-paste)
03_swarm_limit.py
from strands import Agent
from strands.models import BedrockModel
from strands.multiagent import Swarm
 
bedrock_model = BedrockModel(
    model_id="us.anthropic.claude-sonnet-4-20250514-v1:0",
    region_name="us-east-1",
)
 
researcher = Agent(
    name="researcher", model=bedrock_model,
    system_prompt="You are a research specialist. Research the topic and hand off to the architect.",
    callback_handler=None,
)
architect = Agent(
    name="architect", model=bedrock_model,
    system_prompt="You are an architecture specialist. Design architecture and hand off to the coder.",
    callback_handler=None,
)
coder = Agent(
    name="coder", model=bedrock_model,
    system_prompt="You are a coding specialist. Write code and hand off to the reviewer.",
    callback_handler=None,
)
reviewer = Agent(
    name="reviewer", model=bedrock_model,
    system_prompt="You are a review specialist. Review and provide final summary. Do not hand off.",
    callback_handler=None,
)
 
swarm = Swarm(
    [researcher, architect, coder, reviewer],
    entry_point=researcher,
    max_handoffs=2, max_iterations=10,
)
 
result = swarm("Design a simple REST API for a todo app")
 
print(f"Status: {result.status}")
print(f"Node history: {[n.node_id for n in result.node_history]}")
print(f"Execution count: {result.execution_count}")
Terminal
python -u 03_swarm_limit.py

Result

Output
Status: Status.FAILED
Node history: ['researcher', 'architect']
Execution count: 2

With max_handoffs=2, the Swarm stopped after researcher → architect (2 handoffs) with Status.FAILED. The coder and reviewer were never reached.

In production, estimate the number of handoffs needed for your task and set max_handoffs accordingly. Too low and the task won't complete; too high and you risk infinite loops. max_iterations limits total agent executions (handoffs + internal loops within each agent) and is used alongside max_handoffs.

Summary

  • Just pass agents to Swarm for autonomous collaboration — No @tool wrappers or orchestrator needed. Just a list of agents and an entry_point.
  • Handoffs are auto-managed via handoff_to_agent tool — Automatically injected into each agent. Agents autonomously decide handoff targets. No need to write handoff logic.
  • node_history tracks execution order — See which agents ran in what order for debugging and optimization.
  • max_handoffs and max_iterations ensure safety — Prevent infinite loops. Always set these in production.

Share this post

Shinya Tahara

Shinya Tahara

Solutions Architect @ AWS

I'm a Solutions Architect at AWS, providing technical guidance primarily to financial industry customers. I share learnings about cloud architecture and AI/ML on this site.The views and opinions expressed on this site are my own and do not represent the official positions of my employer.

Related Posts