Agentic Design Patterns
Tool use, reflection, planning and multi-agent collaboration — the four reusable shapes, what each fixes, and what each costs.
Agent designs converge on a handful of patterns. They are not alternatives to pick between; they compose. What matters is knowing which failure each one addresses, because adding a pattern you do not need just adds turns, tokens and latency.
Tool use
The foundational pattern: the model is given callable functions and decides which to invoke. It fixes the model's two structural weaknesses — it does not know current state, and it cannot change anything. Everything else in this lesson assumes it.
The engineering work is almost entirely in tool design. Few tools, sharply described, with narrow inputs and small, already-filtered outputs. Twenty overlapping tools produce worse behaviour than six well-separated ones, because tool selection is a discrimination problem.
Reflection
The agent critiques its own output and revises it. In its simplest form this is a second call with the instruction "review this draft against these criteria and list the problems", followed by a third that applies the fixes. A stronger variant separates the roles: a generator agent and a distinct critic agent with its own rubric.
Reflection pays where quality is subjective and there is a rubric to judge against — code, long-form writing, plans. It pays badly where correctness is objectively checkable, because a compiler, a schema validator or a test suite is cheaper and never wrong. The failure mode is agreeable self-review: given a vague rubric, models tend to approve their own work, so make the criteria concrete and let the critic see the evidence rather than only the answer.
Planning
The agent decomposes the goal into ordered sub-tasks before acting, then works through them and re-plans on surprises. It fixes greedy behaviour on long tasks, and it gives you an artefact you can log, show to a user or approve before execution. The cost is a full extra reasoning turn and a tendency to over-decompose simple requests. A common guard is to plan only when the request is above a complexity threshold.
Multi-agent collaboration
Several specialised agents, each with its own instructions and tool set, coordinated by a supervisor. Amazon Bedrock Agents supports multi-agent collaboration, where a supervisor agent delegates to associated collaborator agents; a routing mode is available for simple requests that map cleanly to a single collaborator. In the Strands Agents SDK the equivalent shapes are agents-as-tools, plus swarm, graph and workflow primitives.
Use it when the sub-domains need genuinely different tools, instructions or permissions — and when one agent's tool list has grown unwieldy. Do not use it to make an architecture diagram look impressive. Every hand-off is another model call, another chance to lose context, and a harder trace to debug. A single well-scoped agent beats a committee of vague ones almost every time.
| Pattern | Fixes | Costs |
|---|---|---|
| Tool use | No live data, no ability to act | Wrong tool selection; needs a security boundary |
| Reflection | Sloppy or unchecked output | Extra turns; self-approval bias |
| Planning | Greedy, incoherent long tasks | Extra turn; over-decomposition |
| Multi-agent | Too many tools or domains for one agent | Latency, cost, context loss at hand-offs |
Example
from strands import Agent, tool
# Specialists become tools of the supervisor - the "agents as tools" pattern.
@tool
def billing_specialist(query: str) -> str:
"""Answer invoice, refund and payment questions using billing systems."""
agent = Agent(
system_prompt="You handle billing only. Always look data up before answering.",
tools=[get_invoice, list_payments],
)
return str(agent(query))
@tool
def network_specialist(query: str) -> str:
"""Diagnose connectivity problems using outage and line-test tools."""
agent = Agent(
system_prompt="You handle network faults only. Run a line test before concluding.",
tools=[check_outages, run_line_test],
)
return str(agent(query))
@tool
def critic(draft: str) -> str:
"""Review a customer reply against the rubric and list concrete problems."""
agent = Agent(system_prompt=(
"Check: is every figure sourced from a tool result? Is the tone polite? "
"Is the next step explicit? Reply with a bullet list of problems, or 'OK'."
))
return str(agent(draft))
supervisor = Agent(
system_prompt=(
"Route each customer issue to the right specialist. For anything spanning both, "
"plan the steps first. Before replying, send your draft to the critic and fix what it finds."
),
tools=[billing_specialist, network_specialist, critic],
)
supervisor("I was charged twice this month and my broadband keeps dropping.")When to use it
- A code-review assistant generates a patch, runs the test suite, and only reflects on the failures rather than on its own opinion of the code.
- A contact centre supervisor agent routes billing questions to one collaborator and network faults to another, each with separate tool permissions.
- A report generator plans sections up front so a human can approve the outline before any expensive research runs.
Discussion