Your first agent
The Strands Agents SDK is an open source framework (built by AWS) for building AI agents with a "model-driven" approach: the model decides what to do at each step, and the SDK handles the execution loop (the agent loop) for you. It works with any provider β Bedrock, Anthropic, and also OpenAI directly.
1. Install the dependencies
2. Write your first agent
An agent in Strands needs just two things: a model and (optionally) tools. Here's what "Hello World" looks like:
You run python agent.py and you already have a working conversational agent. No manual loops, no hand-rolled function-call parsing β the SDK handles the whole question β reasoning β answer cycle.
Change the model_id to a different OpenAI model (a cheaper one, for example) and compare response speed. Then change the prompt to ask the agent to always answer in list format.
System prompt and the agent loop
Every time you talk to an agent, Strands runs the agent loop: it sends your message + history + available tools to the model, the model decides whether to answer directly or call a tool, and the cycle repeats until the model gives a final answer. The system_prompt is what shapes how the agent thinks on every turn of that cycle.
Parameters you'll use often
temperatureβ lower (0.0β0.3) for precise tasks/support, higher (0.7+) for creativitymax_tokensβ response length limit, important for controlling costmodel_idβ you can mix a cheap model for simple tasks with a more powerful one for complex reasoning
Write a system prompt for an agent that only answers questions about a specific topic of your choice, and politely declines any other question.
Give your agent tools
@tool decorator and use prebuilt tools from the strands_tools package.An agent without tools can only "talk." With tools, it can act: query an API, do a calculation, read a file. In Strands, any Python function becomes a tool with the @tool decorator β the type hints become the schema, and the docstring becomes the description the model uses to decide when to call it.
The agent decides on its own, without you telling it explicitly, that it needs to call current_weather for the first part and calculator (a prebuilt tool from strands_tools) for the second β and combines both results into a single answer.
Create a lookup_product(name: str) tool that returns price/stock from an in-memory dictionary, and verify the agent uses it correctly across several follow-up questions in a conversation.
Conversational memory and sessions
An Agent object already keeps its conversation history as long as it lives in memory β every new call gets appended to the same thread. For long conversations, Strands offers conversation managers that decide how to truncate or summarize history so you don't exceed the model's context window.
The SlidingWindowConversationManager keeps the last N messages and automatically drops the oldest ones β useful for support or sales bots that run indefinitely without accumulating unbounded context (and unbounded cost).
Simulate a 5-turn conversation and check what happens when you reduce window_size to a very small number (e.g. 2) β you'll notice the agent "forgets" the start of the chat.
Typed responses with Pydantic
When you're connecting the agent to another system (a database, a CRM, a frontend), you don't want to parse free text β you want validated JSON. Strands supports this natively using Pydantic models as the output schema.
This is the foundation for automating ticket classification, extracting data from documents, or any flow where the agent's output feeds code, not a human reading text.
Define a Pydantic model to extract data from a product review (1-5 rating, sentiment, and whether it mentions a specific problem) and test it with 3 different example reviews.
Real-time responses
For a production API or chat, you don't want to wait for the agent to finish "thinking" before showing something β you want to display tokens as they arrive. Strands exposes invoke_async() and a callback-handler system for this.
If you're building an API (FastAPI, for example) and don't need to see streaming in the terminal but only need to process events internally, you can disable live output with callback_handler=None when creating the agent, and handle the events yourself.
Wrap the agent in a FastAPI endpoint that returns the response as a StreamingResponse, reusing the async generator above.
Agents-as-Tools: your first team of agents
When a single agent starts taking on too many responsibilities (researching, writing, validating), it's worth splitting it into specialized agents. Strands' simplest pattern for this is Agents-as-Tools: you wrap an entire agent inside a @tool function, and another agent can "call" it just like any other tool.
The writer agent decides on its own when to delegate to the researcher β you don't orchestrate the flow step by step, the model does. This pattern uses few extra tokens because the coordination itself is deterministic (a regular function call).
Add a third "reviewer" agent that receives the writer's text and returns a corrected version, chaining all three roles together.
Graph and Swarm: orchestration patterns
Strands ships three ways to coordinate multiple agents, each suited to a different case:
- Agents-as-Tools (previous level) β simple, deterministic delegation, ideal when you already know which agent does what
- Graph β a deterministic directed graph: agents are nodes, connections define the data flow between them. Ideal for predictable pipelines (e.g. research β write β review, always in that order)
- Swarm β the agents dynamically decide among themselves who to hand the task to. More flexible, but uses more tokens because the model "reasons" about who to delegate to
This is the heart of a production agent architecture: an orchestrator (router) that never resolves the domain itself, it just decides who to delegate to β just like a human dispatcher in a call center.
Add logging inside each ask_* tool to record how many times each specialist gets routed to β it's the first step toward real observability.
Observability, errors, and guardrails
Before putting this into production, three things stop being optional: knowing what the agent did (traces), what happens when something fails (errors/retries), and how much it can end up costing (limits).
Observability with OpenTelemetry
Strands emits traces using the OpenTelemetry standard natively β every model call, every tool use, and every step of the event loop gets recorded, compatible with Jaeger, Grafana Tempo, AWS X-Ray, or Datadog.
Error handling and retries
Basic guardrails
max_tokenslimit per response to avoid uncontrollably long answers- Require explicit confirmation for critical tools (e.g. ones that write to a database)
- A maximum "steps" limit on the event loop, to prevent an agent from entering an infinite tool-calling cycle
Add a counter for tokens used per session, and cut off the conversation (with a clear message to the user) if a budget you define is exceeded.
Orchestrator + load balancer in production
At this point you have an orchestrator that delegates to specialist agents β but with everything running in a single Python process, a traffic spike takes the whole thing down. The last step is splitting each agent into its own service, and spreading the load across multiple instances.
1. Each agent as its own service
You wrap each specialist agent in a FastAPI microservice, independently deployable (Docker, Lambda, Fargate, or EKS β Strands supports all four out of the box):
2. Multiple workers behind a load balancer
You run several replicas of each service (e.g. 3 instances of support_service) and put a load balancer (nginx, or a managed one like AWS ALB) in front, spreading traffic across them β so no specialist agent is a single point of failure:
3. Job queue to decouple the orchestrator
For traffic spikes or long-running tasks, the orchestrator doesn't call the specialists directly β it queues the job (Redis, SQS) and workers consume it at their own pace. This keeps one slow agent from blocking everyone else:
With this, you have the full path: from a one-line agent("hello") in Level 1, to a real production architecture with intelligent routing, horizontal scaling, and end-to-end observability.
Take the orchestrator from Level 8, split each specialist into its own FastAPI service, and set up 2 instances of one of them behind nginx with least_conn. That's your first multi-agent system in production.