strands-agents review
Strands Agents is an AWS-led Python SDK that runs a model and tool calling loop around an `Agent` object. Python functions become tools through type hints and docstrings; model adapters connect Bedrock, Anthropic, OpenAI, Gemini, Ollama, and other providers; MCP clients can supply remote tools; hooks observe or stop execution; and Pydantic models validate structured results. Version 1.53.0 adds audio content blocks, agents used directly as tools, MCP OAuth for streamable HTTP, Anthropic prompt caching, and context-manager offloading strategies. The default provider is Amazon Bedrock, so the shortest example still depends on AWS credentials, regional model access, and billable model calls.
Strands 1.53.0 makes sense for Python teams that want Bedrock defaults plus first-party MCP, hooks, structured output, and agent delegation. Do not add its 72 MB environment for simple completions, and never mistake an in-process `@tool` function for a security boundary.
We installed it
| Install | ✓ · 2.2s | 47 packages on disk · 72 MB |
| Import | ✓ | import strands in 2.11s · pure Python · py.typed · requires Python >=3.10 |
| Known vulns | 0 | (pip-audit) |
Answers from our run
Does strands-agents install cleanly?
Yes. In a fresh container with an empty cache, pip install strands-agents finished in 2 seconds, leaving 47 packages and 72 MB on disk. pip-audit reported no known vulnerabilities.
What does strands-agents need to run?
Python >=3.10, and nothing compiled: it is pure Python. In our run import strands succeeded in 2.11s, and the package ships py.typed for type checkers.
strands-agents or langgraph: which should you use?
langgraph: Use it for explicit state graphs, durable execution, and the larger LangChain integration orbit. Strands 1.53.0 makes sense for Python teams that want Bedrock defaults plus first-party MCP, hooks, structured output, and agent delegation.
When should you not use strands-agents?
The task is one model request with no tools or iterative decisions. A provider SDK call avoids a 47-package, 72 MB agent runtime.
Use it if
- Amazon Bedrock is already the model plane and the application should reuse AWS credential resolution, regions, and model access controls.
- Tools should be regular typed Python functions whose docstrings become the descriptions shown to the model.
- An agent needs MCP tools, streamed events, structured Pydantic output, execution hooks, or specialist agents exposed as callable tools.
- The same application may switch among hosted and local model providers behind a shared agent interface.
- The task is one model request with no tools or iterative decisions. A provider SDK call avoids a 47-package, 72 MB agent runtime.
- AWS defaults are unwanted and the team does not need Strands-specific hooks, MCP, or orchestration. Every non-Bedrock model still requires its provider extra, client settings, and credentials.
- Untrusted tool execution cannot be isolated. A Python tool runs with the application's process permissions unless you build an external sandbox and approval boundary.
- Your production policy requires a slow-moving surface. The SDK moved from 1.50.2 to 1.53.0 within weeks, while several context and bidirectional APIs remain experimental.
- A large third-party integration catalog and years of community recipes matter more than the compact core. LangGraph and adjacent LangChain packages have the broader installed ecosystem.
Setup reality
We installed strands-agents 1.53.0 in a fresh Python 3.12 Bookworm container. Installation took 2.2 seconds, left 47 packages, and used 72 MB on disk. Package metadata contains 99 direct requirement entries when provider and feature extras are counted. The core is pure Python, requires Python 3.10 or newer, ships py.typed, and uses Apache-2.0. pip-audit reported zero known vulnerabilities. Importing strands worked in 2.11 seconds.
A bare Agent() selects Amazon Bedrock. The quickstart requires AWS credentials plus access to the documented Claude model in the configured region; missing either produces a provider error on the first invocation. Other providers use their own model classes and optional extras, such as strands-agents[gemini] or [ollama]. Keep keys in provider-supported environment or credential stores, pass an explicit model id, and set cost, token, and execution limits before exposing an agent to requests.
Tools run inside your Python process. Their docstrings and annotations form the schema the model sees, but they do not add authorization, input trust, idempotency, timeouts, or isolation. Directory loading watches ./tools and makes discovered functions callable, which is useful locally and risky on a writable production filesystem. MCP clients have their own lifetime: create the Agent inside the client context, filter the advertised tools, and treat OAuth or server trust as an application security boundary.
Streaming returns event dictionaries for text, tools, lifecycle changes, and the final result. Consumers must handle cancellation and partial output instead of assuming every stream ends cleanly. Structured output can still fail validation and raises StructuredOutputException. Version 1.53.0 adds more agent delegation and audio support, but bidirectional streaming stays under strands.experimental; its extras can pull audio dependencies, and Nova Sonic requires Python 3.12 or newer.
Patterns
Run the default Bedrock agent invoke-bedrock-agent
from strands import Agent
agent = Agent(system_prompt='Answer with sources when available.')
result = agent('Explain the retry policy.')
print(str(result))The default provider needs valid AWS credentials, regional Bedrock access, and an enabled model before this call can succeed.
Expose a typed function define-python-tool
from strands import Agent, tool
@tool
def word_count(text: str) -> int:
"""Count whitespace-separated words in text.
Args:
text: Text to count.
"""
return len(text.split())
agent = Agent(tools=[word_count])The model receives the function schema and docstring. Validate inputs and enforce authorization inside the function before touching external state.
Return a Pydantic model validate-structured-output
from pydantic import BaseModel, Field
from strands import Agent
class Ticket(BaseModel):
title: str
priority: int = Field(ge=1, le=5)
agent = Agent()
result = agent(
'Create a priority 3 ticket titled Renew certificate',
structured_output_model=Ticket,
)
print(result.structured_output)Catch `StructuredOutputException` around this call. The older `agent.structured_output()` method is deprecated.
Consume text and the final result stream-agent-events
from strands import Agent
agent = Agent(callback_handler=None)
async for event in agent.stream_async('Summarize this incident'):
if 'data' in event:
print(event['data'], end='')
elif 'result' in event:
final_result = event['result']Streams include more than text. Handle tool, error, cancellation, and completion events before adapting this to an HTTP response.
Load tools from an MCP session connect-mcp-server
from strands import Agent
from strands.tools.mcp import MCPClient
from mcp import stdio_client, StdioServerParameters
client = MCPClient(lambda: stdio_client(
StdioServerParameters(command='uvx', args=['server-package']),
))
with client:
tools = client.list_tools_sync()
agent = Agent(tools=tools)
result = agent('Use the server to inspect the record')Keep invocation inside the context manager. Pin the server package and review its tools instead of executing an unversioned command from a prompt.
Choose a Bedrock model explicitly configure-bedrock-model
from strands import Agent
from strands.models import BedrockModel
model = BedrockModel(
model_id='us.amazon.nova-pro-v1:0',
temperature=0.2,
streaming=True,
)
agent = Agent(model=model)A cross-region inference id, account model access, and IAM permissions must all match the deployment region and policy.
Use the Gemini provider configure-gemini-model
from strands import Agent
from strands.models.gemini import GeminiModel
model = GeminiModel(
client_args={'api_key': gemini_api_key},
model_id='gemini-2.5-flash',
params={'temperature': 0.3},
)
agent = Agent(model=model)Install the gemini extra and keep the API key out of source. Provider parameters and supported content types differ from Bedrock.
Point an agent at Ollama configure-ollama-model
from strands import Agent
from strands.models.ollama import OllamaModel
model = OllamaModel(
host='http://127.0.0.1:11434',
model_id='llama3',
)
agent = Agent(model=model)Install the ollama extra and test tool-call reliability with the exact local model. Provider compatibility does not guarantee equivalent reasoning.
Expose a specialist agent delegate-to-agent-tool
from strands import Agent
researcher = Agent(
name='researcher',
system_prompt='Answer factual research questions only.',
)
orchestrator = Agent(tools=[
researcher.as_tool(
name='research_assistant',
description='Research a factual question and return sources.',
)
])Agent-tool context resets between calls by default. Set preserve_context only when cross-call memory is required and safe.
Cancel a disallowed tool invocation intercept-tool-call
from strands import Agent
from strands.hooks import BeforeToolCallEvent
def block_delete(event: BeforeToolCallEvent):
if event.tool_use['name'] == 'delete_record':
event.cancel_tool = 'Deletion requires operator approval.'
agent = Agent(tools=[delete_record])
agent.add_hook(block_delete)A hook is application policy code. Keep authorization in the underlying service too, because other callers may bypass this Agent.
Watch a development tools directory load-local-tools
from strands import Agent
agent = Agent(load_tools_from_directory=True)
result = agent('List the tools available for this task')This watches `./tools` and makes discovered code callable. Do not enable it on a production filesystem writable by untrusted users or jobs.
Start an experimental voice session run-bidirectional-audio
import asyncio
from strands.experimental.bidi import BidiAgent
from strands.experimental.bidi.models import BidiNovaSonicModel
from strands.experimental.bidi.io import BidiAudioIO, BidiTextIO
async def main():
agent = BidiAgent(model=BidiNovaSonicModel())
audio = BidiAudioIO()
text = BidiTextIO()
await agent.run(
inputs=[audio.input()],
outputs=[audio.output(), text.output()],
)
asyncio.run(main())Install the bidi and bidi-io extras. Nova Sonic requires Python 3.12+, audio I/O may need system libraries, and the namespace is experimental.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| langgraph | PyPI | Use it for explicit state graphs, durable execution, and the larger LangChain integration orbit. |
| pydantic-ai | PyPI | Use it when typed dependencies and Pydantic-first results matter more than a Bedrock-centered quickstart. |
| crewai | PyPI | Use it for role-based multi-agent crews and its established task and process abstractions. |
| smolagents | PyPI | Use it for a smaller Hugging Face-oriented agent layer with straightforward tool and code-agent patterns. |
More ai / ml guides
openai · mcp · huggingface-hub · @modelcontextprotocol/sdk · scikit-learn · tiktoken · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

