Building AI Agents with AWS Strands in October 2025
Learn how to build production-ready AI agents using AWS Strands Agents SDK with local models via Docker Model Runner and OpenAI-compatible APIs.
AWS Strands Agents SDK has emerged as a powerful, model-driven framework for building production-ready AI agents with minimal code. Released in May 2025 and reaching version 1.0 in July 2025, Strands has already achieved over 1 million downloads and is actively used in production by AWS teams powering Amazon Q Developer, AWS Glue, VPC Reachability Analyzer, and Kiro. Unlike traditional workflow-based frameworks, Strands embraces the reasoning capabilities of modern large language models, allowing the LLM itself to plan, execute tools, and iterate—freeing developers from hardcoding complex task flows.
Why Choose AWS Strands Agents?
- Model-driven simplicity: Define a model, prompt, and tools—the LLM handles planning and execution autonomously
- Production-proven: Used by multiple AWS teams for mission-critical agent applications
- Model flexibility: Works with Amazon Bedrock, Anthropic, OpenAI, Ollama, LiteLLM, and any OpenAI-compatible API
- Native MCP support: Seamless integration with Model Context Protocol servers for standardized tool access
- Multi-agent orchestration: Built-in patterns for Graph, Swarm, Agents-as-Tools, and human handoffs
- Enterprise-ready: Comprehensive observability, tracing, metrics, and async streaming support
Building a Simple Agent with Local Models
Here’s a practical example demonstrating Strands with a local model via Docker Model Runner using the OpenAI standard. The beauty of Strands is that the agent logic remains identical whether you use OpenAI cloud, Ollama, LM Studio, or Docker Model Runner—true portability with zero vendor lock-in.
Unified Experience with OpenAI Standard
Strands’ architecture stays consistent across all model providers supporting the OpenAI API standard. This means:
- Zero proprietary lock-in—your agent code is completely portable
- Identical agent loops, tool integration, and workflow definitions
- Full feature compatibility (streaming, tool calls, multi-agent patterns)
- Seamless switching between cloud and local models
Requirements
There is an assumption that you understand how to find and install whatever technology is needed for this.
| Technology | Purpose |
|---|---|
docker | Docker Model Runner for local inference |
uv | Package and project management |
strands-agents | Core Strands Agents SDK |
strands-agents[openai] | OpenAI provider integration |
strands-agents-tools | Community-driven tool collection |
ddgs | DuckDuckGo Search |
Installation
uv init my-strands-project
cd my-strands-project
uv sync
source .venv/bin/activate
# Install Strands with OpenAI support
uv add 'strands-agents[openai]' strands-agents-tools ddgs
Basic Agent with Local Model
from strands import Agent, tool
from strands.models.openai import OpenAIModel
from ddgs import DDGS
@tool(name="duckduckgo_search", description="Search the web using DuckDuckGo")
def duckduckgo_search(query: str, max_results: int = 3):
with DDGS() as ddgs:
results = [r for r in ddgs.text(query, max_results=max_results)]
return [
{"title": r["title"], "url": r["href"], "snippet": r["body"]}
for r in results
]
Lets test the tool by calling it with a query:
duckduckgo_search("who is the current president of the united states? today is 2025-10-25")
Output:
[{'title': 'List of presidents of the United States | U.S. Presidents ...',
'url': 'https://www.britannica.com/topic/Presidents-of-the-United-States-1846696',
'snippet': 'Click on a president below to learn more about each presidency through an interactive timeline. The table below the graphic provides a list of presidents of the United States , their birthplaces, political parties, and terms of office.'},
{'title': 'President Donald Trump [R, 2025-2029], President of the ...',
'url': 'https://www.govtrack.us/congress/other-people/donald_trump/412733',
'snippet': 'Trump is President of the United States and is a Republican. He has served since Jan. 20, 2025 . Trump’s current term ends on Jan. 20, 2029. He is 79 years old. He was previously President of the United States as a Republican from 2017 to Jan. 20, 2021.'},
{'title': 'President in 2025',
'url': 'https://whowaspresident.com/2025',
'snippet': 'He took office on January 20, 2021 and left office on January 20, 2025 . He was then followed by Donald J. Trump, who is the 47th President , taking office on January 20, 2025 .'}]
Now that we know the tool works, we can create an agent that uses it.
# Configure Docker Model Runner endpoint
docker_model_config = {
"base_url": "http://localhost:12434/v1", # Docker Model Runner endpoint
"api_key": "docker", # Dummy key for local models
}
# Initialize OpenAI-compatible model
model = OpenAIModel(
client_args=docker_model_config,
model_id="hf.co/unsloth/qwen3-coder-30b-a3b-instruct-gguf",
params={
"temperature": 0 # no creativity
}
)
# Create agent with tools
agent = Agent(
name="Web Research Assistant",
model=model,
tools=[duckduckgo_search],
system_prompt=(
"""
You are a helpful research assistant.\n
Use the DDGS tool to search for real-time web information\n
and present concise answers with relevant URLs.
"""
)
)
# Run the agent
response = agent("who is the current president of the united states? today is 2025-10-25")
print(response.message['content'][0]['text'])
Output Example
As of today, October 25, 2025, the current president of the United States is Donald J. Trump. He took office on January 20, 2025.
Sources:
- [Current President of the United States - Wikipedia](https://en.wikipedia.org/wiki/Current_President_of_the_United_States)
- [The White House](https://www.whitehouse.gov/)
Multi-Agent Patterns
Strands 1.0 introduced powerful multi-agent orchestration primitives:
Agents-as-Tools: Hierarchical Delegation
In this example, I’ll use two different local models. Majority of the configuration is the same as above.
- Docker Model Runner
- LM Studio
docker_model_config = {
"base_url": "http://localhost:12434/engines/v1",
"api_key": "docker",
}
lm_studio_config = {
"base_url": "http://127.0.0.1:1234/v1",
"api_key": "lmstudio",
}
docker_model = OpenAIModel(
client_args=docker_model_config,
model_id="hf.co/unsloth/qwen3-coder-30b-a3b-instruct-gguf",
params={
"temperature": 0
}
)
lm_studio_model = OpenAIModel(
client_args=lm_studio_config,
model_id="google/gemma-3-27b",
params={
"temperature": .7
}
)
research_agent = Agent(
name="Web Research Assistant",
model=docker_model,
tools=[duckduckgo_search],
system_prompt=(
"""
You are a research specialist who gathers detailed information. \n
Use the DDGS tool to search for real-time web information \n
and present concise answers with relevant URLs.
"""
)
)
summary_agent = Agent(
name="Summary Writer",
model=lm_studio_model,
tools=[],
system_prompt=(
"""
You are a summary writer who summarizes the information gathered by the research assistant.
"""
)
)
@tool(name="call_research_agent", description="Research the web for information")
def call_research_agent(query: str):
return research_agent(f"Search and collect data for: {query}")
@tool(name="call_summary_agent", description="Summarize the information gathered by the research assistant")
def call_summary_agent(query: str):
return summary_agent(f"Summarize the information gathered by the research assistant: {query}")
orchestrator = Agent(
model=docker_model,
tools=[call_research_agent, call_summary_agent],
system_prompt=(
"You are the orchestrator responsible for completing user tasks. "
"Determine whether to call the call_research_agent for new information, then have the call_summary_agent clean it up. "
"After summarizing, return in the perspective of the pirate."
)
)
# Mileage will vary. This is a simple example.
orchestrator("who is the current president of the united states? today is 2025-10-25")
## Manual - Custom Workflow Logic (Finer Grained Control)
# Optional - Custom Workflow Logic (Manual Control)
def manual_orchestrate(query: str):
# Step 1: Research
research_result = research_agent(f"Search and collect data for: {query}")
# Step 2: Summarize
summary = summary_agent(f"Summarize this: {research_result}")
# Step 3: Evaluate and return
decision = orchestrator(
f"User asked: '{query}'. Here’s the summary: {summary}. "
)
return decision
result = manual_orchestrate("who is the current president of the united states? today is 2025-10-25")
Output of the Manual - Custom Workflow Logic:
Tool #2: duckduckgo_search
Based on the information available, the current president of the United States as of October 25, 2025, is Donald J. Trump. He has been serving as the 47th president since January 20, 2025.
Relevant sources:
- [Current President of the United States - Wikipedia](https://en.wikipedia.org/wiki/Current_President_of_the_United_States)
- [The White House](https://www.whitehouse.gov/)As of October 25, 2025, the current president of the United States is Donald J. Trump, who is serving as the 47th president since January 20, 2025. This information is supported by sources including Wikipedia's page on the Current President of the United States and The White House official website.Ahoy there, ye scurvy dog!
As of today, October 25, 2025, the current president of the United States be none other than Donald J. Trump, who's been in charge since January 20, 2025, as the 47th president. Aye, and he's been sailing the seas of politics with the same vigor as a pirate on the high seas!
So, there ye have it, matey. The president be Trump, and he's been steering the ship of state since the new year. Now, if ye'll excuse me, I've got to go find me some treasure and avoid any landlubbers who might be after me rum.
Ah, the life of a pirate be much more exciting than that of a president, wouldn't ye say? 🏴☠️
Formatted Output:
result.message['content'][0]['text']
"Ahoy there, ye scurvy dog! \n\nAs of today, October 25, 2025, the current president of the United States be none other than Donald J. Trump, who's been in charge since January 20, 2025, as the 47th president. Aye, and he's been sailing the seas of politics with the same vigor as a pirate on the high seas!\n\nSo, there ye have it, matey. The president be Trump, and he's been steering the ship of state since the new year. Now, if ye'll excuse me, I've got to go find me some treasure and avoid any landlubbers who might be after me rum. \n\nAh, the life of a pirate be much more exciting than that of a president, wouldn't ye say? 🏴\u200d☠️"
Swarm: Self-Organizing Agent Teams
Great way to have inter agent communication and collaboration to research and refine the answer before returning to the user.
from strands.multiagent import Swarm
# Create specialized agents
researcher = Agent(
model=docker_model,
system_prompt="Research and gather information",
tools=[search_web]
)
writer = Agent(
model=docker_model,
system_prompt="Write clear, concise summaries",
tools=[]
)
reviewer = Agent(
model=lm_studio_model,
system_prompt="Review and refine content for accuracy",
tools=[]
)
# Create swarm for collaborative work
swarm = Swarm(
[researcher, writer, reviewer],
entry_point=researcher, # the agent to start the swarm
max_handoffs=20, # max number of handoffs between agents
max_iterations=20 # max number of iterations of the swarm
)
result = swarm("Write a comprehensive report on quantum computing trends in 2025")
Graph: Conditional Workflow Orchestration
Very similar to LangGraph and how they build their agents.
NOTE: Eats up A LOT of the context window from agents bouncing their context back and forth.
from strands.multiagent import GraphBuilder
builder = GraphBuilder()
builder.add_node(researcher, "researcher")
builder.add_node(writer, "writer")
builder.add_node(reviewer, "reviewer")
builder.add_edge("researcher", "writer")
builder.add_edge("writer", "reviewer")
builder.set_entry_point("researcher")
builder.set_execution_timeout(600)
graph = builder.build()
result = graph("Research the impact of AI on the stock market and create a comprehensive report")
Production Deployment Best Practices
Security Considerations
- Input validation: Always validate and sanitize user inputs before passing to agents
- Tool permissions: Implement least-privilege access for each tool
- Output sanitization: Use Amazon Bedrock Guardrails to filter sensitive information
- Secrets management: Never hardcode API keys—use AWS Secrets Manager or environment variables
Performance Optimization
- Context window management: Strands automatically prunes conversation history to stay within token limits
- Parallel tool execution: Async tools execute concurrently for faster responses
- Caching: Implement LRU caching for frequently accessed data
- Timeout configuration: Set appropriate timeouts to prevent runaway agents
Deployment Patterns
# FastAPI integration for production
from fastapi import FastAPI
from strands import Agent
app = FastAPI()
# Initialize agent once at startup
agent = Agent(
model=lm_studio_model,
tools=[search_web, calculator]
)
@app.post("/query")
async def query_agent(query: str):
result = await agent.invoke_async(query)
return {
"response": result.message['content'][0]['text'],
"tokens": result.metrics.accumulated_usage['totalTokens']
}
Real-World Application Patterns (2025)
- Customer support agents: Multi-step troubleshooting with tool use, conditional routing, and human escalation
- Research assistants: Web search, data analysis, report generation with iterative refinement
- DevOps automation: AWS service integration for infrastructure management and monitoring
- Document processing: Multi-agent workflows combining extraction, analysis, and generation
- Financial analysis: Market research, calculation, and reporting with specialized agent teams
Strands vs LangGraph
While both frameworks enable AI agent development, they have different philosophies:
Strands Agents: Model-driven approach where the LLM orchestrates the workflow. Developers provide model + prompt + tools, and the agent autonomously decides execution flow. Ideal for applications where the LLM’s reasoning should drive the process.
LangGraph: Graph-based approach with explicit developer-defined workflows. Better for scenarios requiring deterministic, visualized execution paths with fine-grained control over each step.
Best practice: Use LangGraph for macro-level orchestration and Strands for micro-level agent reasoning—they complement each other effectively in complex systems.
Conclusion
AWS Strands Agents SDK empowers developers to build production-ready, intelligent AI agents with minimal code. By embracing a model-driven approach and supporting any OpenAI-compatible API, Strands provides the flexibility to run locally with Docker Model Runner or deploy to cloud infrastructure seamlessly. With built-in multi-agent patterns, comprehensive observability, native MCP support, and battle-tested production usage at AWS, Strands represents a powerful framework for building the next generation of autonomous AI applications.
Whether you’re prototyping a simple chatbot or orchestrating complex multi-agent systems for enterprise use cases, Strands provides the foundation to reason, act, and scale with confidence.
Image from AWS Strands Agents by Servifyspheresolutions
Further Resources: