From Zero to Agent (Part-I)

Published: (March 13, 2026 at 12:20 AM EDT)
5 min read
Source: Dev.to

Source: Dev.to

Step 1: Your First Strands Agent on Cloud

In just a few lines of Python you can stand up an agent backed by Claude Sonnet 4 on Amazon Bedrock:

from strands import Agent

agent = Agent(
    system_prompt="You are a helpful assistant that provides concise responses."
)

agent("Tell me a joke.")

No infrastructure to provision. No API gateway to configure.

The default model provider is Amazon Bedrock, and the default model is Claude Sonnet 4 in your current AWS region. From there you can add tools – both built‑in ones from the strands‑agents‑tools package (e.g., calculator) and custom ones decorated with @tool. You can also invoke tools directly (agent.tool.calculator(...)), configure logging, and swap model providers or adjust inference parameters via BedrockModel.

Below is an example that builds a RecipeBot, a cooking assistant that uses DuckDuckGo web search as a tool, all wired up in under 50 lines of code.

RecipeBot demo

import warnings
warnings.filterwarnings(action="ignore", message=r"datetime.datetime.utcnow")

from strands import Agent

# Initialise your agent
agent = Agent(
    model="us.anthropic.claude-sonnet-4-5-20250929-v1:0",  # optional: specify the model ID
    system_prompt="You are a helpful assistant that provides concise responses."
)

# Send a message to the agent
response = agent("Hello! Tell me a joke.")

Key Takeaway – The Strands Agent abstracts away the entire request‑response‑tool loop. You think in terms of what the agent should do, not how to wire API calls. Three lines are all Strands needs for a working agent on Bedrock.

Step 2: Personal Agent Assistant on a Local Machine

Not every use case should hit a cloud endpoint. This step shows how to swap Amazon Bedrock for Ollama, the local LLM runtime, using Strands’ OllamaModel provider. The agent runs entirely on your machine, keeping all data local.

Local Ollama demo

from strands import Agent
from strands.models.ollama import OllamaModel

ollama_model = OllamaModel(
    model_id="llama3.2:3b",
    host="http://localhost:11434",
    temperature=0.7,
)

# Example tools (you would define these elsewhere)
tools = [file_read, file_write, list_directory]

agent = Agent(model=ollama_model, tools=tools)

The use case is a local file‑operations assistant: read files (including PDFs), write files, list directory contents. The agent can summarise a shareholder letter, scaffold a README, or create files on your behalf, all powered by a 3 B‑parameter model running locally.

Key Takeaway – The Strands model‑provider abstraction is genuinely portable. Switching from Claude on Bedrock to Llama on Ollama is a one‑line change, which matters for offline scenarios, privacy‑sensitive workloads, and cost‑optimised development.

Step 3: Connecting Agents to AWS Services

This is where things become practically useful. The example builds a Restaurant Assistant that connects to two AWS managed services:

  • Amazon Bedrock Knowledge Base – RAG over restaurant menus.
  • Amazon DynamoDB – Reservation management.

The step demonstrates three ways to define tools:

  1. Inline with @tool decorator – define the function next to your agent code.
  2. Standalone file with @tool decorator – import it as a module.
  3. TOOL_SPEC dictionary – Bedrock Converse‑API‑style schema, useful for fine‑grained control over parameters and return shapes.
from strands import Agent
from strands_tools import current_time, retrieve   # built‑in tools

# Custom tools (could be defined inline, imported, or via TOOL_SPEC)
# Example: get_booking_details, create_booking, delete_booking

agent = Agent(
    model=model,
    system_prompt=system_prompt,
    tools=[
        retrieve,
        current_time,
        get_booking_details,
        create_booking,
        delete_booking,
    ],
)

The built‑in retrieve tool reads from your Bedrock Knowledge Base automatically when the KNOWLEDGE_BASE_ID environment variable is set—no custom RAG plumbing required.

Key Takeaway – Strands agents can be connected to any AWS service through custom tools and boto3 calls. The retrieve built‑in tool gives you RAG in one line, and the TOOL_SPEC pattern lets you define sophisticated tool contracts when needed.

Step 4: MCP Tools and Multiple Servers

The Model Context Protocol (MCP) is the emerging standard for connecting AI agents to external tool servers. Here we show how Strands natively integrates with MCP servers, both via stdio for local CLI‑style servers and Streamable HTTP for networked, stateless servers.

from strands.tools.mcp import MCPClient
from mcp import StdioServerParameters, stdio_client

mcp_client = MCPClient(
    lambda: stdio_client(
        StdioServerParameters(
            command="uvx",
            args=["awslabs.aws-documentation-mcp-server@latest"]
        )
    )
)

with mcp_client:
    tools = mcp_client.list_tools_sync()
    agent = Agent(tools=tools)
    agent("What is Amazon Bedrock's pricing model?")

This step also covers:

  • Creating your own MCP server with FastMCP
  • Direct tool invocation via call_tool_sync
  • Timeout configuration with read_timeout_seconds
  • Connecting multiple MCP servers to a single agent simultaneously

MCP diagram

Key Takeaway – MCP turns the tool ecosystem into a plug‑and‑play marketplace. Any MCP‑compatible server—whether AWS documentation, CDK best practices, databases, or APIs—becomes a tool your agent can use without any glue code. You can combine multiple servers in a single agent call.

Step 5: Advanced Response Processing, Streaming and Callbacks

Real applications don’t just call an agent and wait. They stream tokens, render partial results, pipe events to dashboards, and serve responses over HTTP. This step demonstrates two patterns for achieving that.

Method 1 — Async Iterators (stream_async)

Ideal for async frameworks like FastAPI. Iterate over agent events as they arrive:

async for event in agent.stream_async("Calculate 2+2"):
    if "data" in event:
        print(event["data"])
    if "current_tool_use" in event:
        print(f"Tool: {event['current_tool_use']['name']}")

Events carry structured lifecycle signals: init_event_loop, start_event_loop, message, current_tool_use, data, force_stop, and result. This gives you fine‑grained control to build streaming UIs, progress indicators, or custom logging.

Async streaming diagram

Method 2 — Callback Handlers

For synchronous contexts, pass a callback_handler function to the agent. It fires on every event, letting you intercept model output and tool calls in real time without restructuring your code around async.

Callback handler diagram

Key Takeaway

  • stream_async paired with FastAPI is the production pattern for streaming agent APIs.
  • Callback handlers are the lightweight alternative for scripts, CLIs, or any synchronous environment.

Both approaches give you visibility into every step of the agent’s reasoning and tool usage.

To be continued…

0 views
Back to Blog

Related posts

Read more »

Travigo

Travel as fast as you speak with Gemini! Where live agents meet immersive storytelling & 3D navigation. This project was created for entering the Gemini Live Ag...

Micro games

Hey Gamers! 👾 As part of the Rapid Games Prototyping module, we are tasked with reviewing a peer's game. The challenge is to analyse a prototype built in just...