You have an agent that searches flights. Another one checks the weather. Another one enforces corporate policies. How do you make them work together?
Strands Agents offers 5 patterns for coordinating multiple agents. Each one solves a different problem. The key difference: who decides the execution order. The model, the agents themselves, or you in code.
In this post I walk through each pattern with code, show the differences in a comparison table, and give you a decision framework to pick the right one.
All examples use Strands Agents (June 2026). The complete code is at github.com/ricardoceci/curso-strands-agentcore-2026/tree/main/clase-3.
The Running Example: Corporate Travel Agent
Every example uses the same case: a corporate travel agent that coordinates flight search, weather lookup, and recommendation generation. Three capabilities, three specialized agents.
from strands import Agent, tool
@tool
def search_flights(origin: str, destination: str, date: str) -> dict:
"""Search one-way flights via Duffel sandbox."""
# ... Duffel API call
return {"route": f"{origin} -> {destination}", "offers": [...]}
@tool
def get_weather(city: str, target_date: str) -> dict:
"""Get weather forecast for a city on a specific date."""
# ... Open-Meteo API call
return {"city": city, "max_temp_c": 28, "precipitation_mm": 0.5}
Pattern 1: Agents as Tools
An orchestrator agent uses other agents as if they were tools. The orchestrator decides when to delegate and to whom.
How It Works
You pass the sub-agent directly in the main agent's tools array. The SDK converts it to a tool automatically. When the orchestrator's model decides it needs that capability, it invokes the sub-agent. Everything runs in the same Python process.
For more control, use .as_tool() to customize the tool name and description, or the @tool decorator to wrap the call entirely.
# Specialized sub-agent for weather
weather_agent = Agent(
tools=[get_weather],
system_prompt="You are a weather expert. Respond concisely.",
)
# The main agent receives the sub-agent directly in tools[]
travel_agent = Agent(
tools=[search_flights, weather_agent], # <-- the SDK converts it to a tool
system_prompt="You are a corporate travel assistant.",
)
response = travel_agent("Flights from EZE to MIA on Aug 20. What's the weather like?")
When to Use It
When you have a few sub-agents with clearly distinct capabilities and you want the main model to decide when to call each one. This is the most direct pattern. It requires the least coordination.
When NOT to Use It
If you need agents to communicate with each other (not only with the orchestrator) or if execution order matters. In those cases, Graph or Swarm work better.
Pattern 2: Swarm
A group of agents that coordinate autonomously through handoffs (control transfers). Each agent decides when to pass work to another.
How It Works
Strands equips each agent in the Swarm with coordination tools: a handoff tool to transfer control, and a shared context that all agents can read. The agents decide the execution order themselves.
from strands.multiagent import Swarm
flight_agent = Agent(
name="flight_agent",
tools=[search_flights],
system_prompt="You search flights. When done, hand off to weather_agent.",
)
weather_agent = Agent(
name="weather_agent",
tools=[get_weather],
system_prompt="You check weather at the destination.",
)
summary_agent = Agent(
name="summary_agent",
system_prompt="You combine flights and weather into a clear recommendation.",
)
swarm = Swarm([flight_agent, weather_agent, summary_agent])
response = swarm("I need to travel from Buenos Aires to Miami on August 20")
When to Use It
When the problem breaks down into parts that different specialists handle better, and the order can vary by task. Swarm works best for problems where you don't know in advance which agent should act first.
When NOT to Use It
If you need a predictable, repeatable execution flow. Swarm decides the order at runtime. Two runs of the same prompt can follow different paths.
Pattern 3: Graph
A directed graph where each node is an agent and edges define the execution flow. You define the structure, the framework executes in order.
How It Works
GraphBuilder gives you an API to define nodes (agents) and edges (connections). The framework passes output from one node as input to the next. It supports acyclic graphs (pipelines) and cyclic graphs (refinement loops), giving you flexibility to implement review iterations between agents.
from strands.multiagent import GraphBuilder
graph = (
GraphBuilder()
.add_node("search", flight_agent)
.add_node("weather", weather_agent)
.add_node("summary", summary_agent)
.add_edge("search", "weather")
.add_edge("weather", "summary")
.build()
)
response = graph("Travel from Buenos Aires to Miami, August 20")
When to Use It
When the workflow has a strict order that should not change. For example: always search flights first, then check weather, then generate the recommendation. If the pipeline is the same every time, Graph is the right pattern.
When NOT to Use It
If you need flexibility in execution order. A Graph with many depth levels also adds latency, because each node waits for the previous one.
Pattern 4: Workflow
A task graph with explicit dependencies and automatic parallel execution. Each task is assigned to an agent with a specific system_prompt.
How It Works
Unlike Graph (which operates with agents as nodes), Workflow operates with tasks. Each task has an ID, description, dependencies, and priority. The framework resolves execution order, parallelizes what it can, and passes results between tasks.
from strands import Agent
from strands_tools import workflow
agent = Agent(tools=[workflow])
agent.tool.workflow(
action="create",
workflow_id="travel_planning",
tasks=[
{
"task_id": "search_flights",
"description": "Find the 5 cheapest flights from EZE to MIA on Aug 20",
"system_prompt": "You are a flight search expert.",
"priority": 5,
},
{
"task_id": "check_weather",
"description": "Check weather in Miami for August 20",
"system_prompt": "You are a weather expert.",
"priority": 5,
},
{
"task_id": "generate_report",
"description": "Combine flights and weather into an executive report",
"dependencies": ["search_flights", "check_weather"],
"system_prompt": "You are a corporate travel analyst.",
"priority": 3,
},
],
)
agent.tool.workflow(action="execute", workflow_id="travel_planning")
In this example, search_flights and check_weather run in parallel (no dependencies between them). generate_report waits for both to finish.
When to Use It
When you have a repeatable process with steps that can run in parallel. Workflow is the closest pattern to a traditional data pipeline: explicit dependencies, deterministic execution, results flowing between tasks.
When NOT to Use It
If you need agents to make decisions about what to do next. Workflow executes exactly what you defined, with no autonomy.
Pattern 5: A2A (Agent-to-Agent)
An open protocol (created by Google, now at the Linux Foundation) for agents to communicate over HTTP. Agents can be written in different frameworks, on different servers.
How It Works
An agent is exposed as an A2A server with an Agent Card (JSON metadata at /.well-known/agent-card.json). Another agent consumes it as a client. Communication happens over HTTP/JSON.
Server:
from strands import Agent
from strands.multiagent.a2a import A2AServer
import uvicorn
weather_agent = Agent(
name="weather_agent",
description="Checks weather forecasts by city and date",
tools=[get_weather],
)
a2a_server = A2AServer(agent=weather_agent)
app = a2a_server.to_fastapi_app()
uvicorn.run(app, host="0.0.0.0", port=9000)
Client:
from strands import Agent
from strands.agent.a2a_agent import A2AAgent
remote_weather = A2AAgent(
agent_url="http://localhost:9000",
)
# Use it as a node in a Graph
graph = (
GraphBuilder()
.add_node("search", flight_agent)
.add_node("weather", remote_weather)
.add_edge("search", "weather")
.build()
)
When to Use It
When agents live on different servers, are written in different frameworks (Strands, LangGraph, CrewAI), or belong to different teams or organizations. A2A is the only pattern that crosses the local process boundary.
When NOT to Use It
If all agents run in the same process. A2A adds network latency (50-1000ms per call, per community benchmarks). For local communication, the other patterns are orders of magnitude faster.
Comparing the 5 Multi-Agent Patterns
| Aspect | Agents as Tools | Swarm | Graph | Workflow | A2A |
|---|---|---|---|---|---|
| Who decides order | Orchestrator model | Agents (handoffs) | You (edges) | You (dependencies) | N/A (protocol) |
| Communication | In-process | In-process | In-process | In-process | HTTP/JSON |
| Latency | Microseconds | Microseconds | Microseconds | Microseconds | 50-1000ms |
| Parallel execution | Not native | Agent-decided | Supported | Automatic | N/A |
| Cyclic graphs | No | No | Yes | No | No |
| Cross-framework | No | No | No | No | Yes |
| Composable | Yes (as tool) | Yes (Graph node) | Yes (nested Graph) | No | Yes (Graph node) |
Decision Framework
When choosing a pattern, follow these questions:
Are the agents in the same process?
If not: A2A (the only one that crosses the network).
Does execution order matter?
If yes, is it always the same?: Graph (fixed structure).
If yes, with parallel tasks?: Workflow (dependencies + parallelism).
Do agents need to decide on their own who acts?
If yes: Swarm (autonomous handoffs).
Is it direct delegation from an orchestrator to specialists?
If yes: Agents as Tools (the most direct).
None fits perfectly?
Patterns compose with each other. A Graph can have a Swarm as a node. An agent with tools can include a remote A2AAgent. Strands lets you mix patterns without constraints.
Frequently Asked Questions
Does Swarm use A2A internally?
No. Swarm uses Python function calls within the same process. The confusion comes from both involving "communication between agents," but Swarm is local (microseconds) and A2A is remote (HTTP).
Does Graph support conditional execution?
Yes. Edges can have conditions evaluated at runtime. This gives you graphs that behave like decision trees: based on a node's output, the flow takes one path or another.
Can I combine patterns?
Yes, and this is one of Strands' strengths. A Swarm can live as a node inside a Graph. A Graph can use a remote A2AAgent as a node. An agent with tools can include another agent as a tool. Composition is unrestricted.
Which one is most token-efficient?
Agents as Tools and Graph consume fewer tokens because coordination is deterministic. Swarm can consume more because agents reason about who to hand off to. A2A adds HTTP protocol overhead.
Does Workflow replace Graph?
No. Workflow is a Strands tool (from strands-agents-tools), while Graph is a native SDK orchestrator. Workflow operates with tasks, Graph operates with agents. If you need each node to be a full agent with its own system prompt and tools, use Graph. If you need a task pipeline with dependencies, use Workflow.
Conclusion
The 5 patterns don't compete with each other. Each one solves a different coordination need. The key is to start with the most direct one that works for your case (probably Agents as Tools) and scale toward more complex patterns when you need them.
If you want to see these patterns implemented live with the Corporate Travel Agent case, the full code is in the course repository:
github.com/ricardoceci/curso-strands-agentcore-2026
Top comments (0)