Large Language Models are powerful, but they have one major limitation:
They only know what they were trained on.
What if you want your AI agent to access the latest information from the web?
That's where custom tools become incredibly useful.
In this lab, you'll build a custom web search tool using DuckDuckGo Search (DDGS) and connect it to a Strands Agent. This allows the agent to retrieve up-to-date information and provide responses based on real-time search results.
By the end of this lab, you'll have a Recipe Assistant that can search the web for recipes and cooking information.
🚀 What You'll Learn
In this lab, you'll learn:
- How to create a custom web search tool
- How to integrate third-party Python libraries into Strands tools
- How agents use tools to access live information
- How to handle API errors gracefully
- How to build a specialized AI assistant
🤖 Why Web Search Matters
LLMs have knowledge cutoffs.
For example, an LLM may know:
✅ How recipes work
✅ Common cooking techniques
✅ Popular dishes
But it may not know:
❌ Latest recipes
❌ Current food trends
❌ Newly published cooking content
❌ Real-time information
A web search tool solves this problem.
User Question
↓
Agent Analysis
↓
Web Search Tool
↓
Search Results
↓
Agent Response
Instead of relying only on training data, the agent can retrieve fresh information from the web.
🛠️ Prerequisites
Before starting, make sure you have:
- Python 3.10+
- AWS Account
- Amazon Bedrock access
- AWS credentials configured
- uv installed
- DDGS package installed
Install DDGS:
pip install ddgs
📜 The Script
Let's start by looking at the complete example.
from strands import Agent, tool
from ddgs import DDGS
from ddgs.exceptions import RatelimitException
import logging
from strands.models.bedrock import BedrockModel
# Configure logging
logging.getLogger("strands").setLevel(logging.INFO)
# Define a websearch tool
@tool
def websearch(
keywords: str,
region: str = "us-en",
max_results: int | None = None
) -> str:
"""Search the web to get updated information."""
try:
results = DDGS().text(
keywords,
region=region,
max_results=max_results
)
return results if results else "No results found."
except RatelimitException:
return "RatelimitException: Please try again after a short delay."
except Exception as e:
return f"Exception: {e}"
# Bedrock
bedrock_model = BedrockModel(
model_id="<YOUR_MODEL_ID>",
region_name="eu-west-2",
temperature=0.3,
)
# Create a recipe assistant agent
recipe_agent = Agent(
model=bedrock_model,
system_prompt="""
You are RecipeBot, a helpful cooking assistant.
Help users find recipes based on ingredients and answer cooking questions.
Use the websearch tool to find recipes when users mention ingredients or to look up cooking information.
""",
tools=[websearch],
)
response = recipe_agent(
"Suggest a recipe with chicken and capsicum."
)
print(f"Metrics : {response.metrics}")
Now let's break it down step by step.
⚙️ Step 1: Import Dependencies
from strands import Agent, tool
from ddgs import DDGS
from ddgs.exceptions import RatelimitException
import logging
from strands.models.bedrock import BedrockModel
We're importing:
| Import | Purpose |
|---|---|
| Agent | Creates the AI agent |
| tool | Converts a Python function into a Strands tool |
| DDGS | Performs DuckDuckGo searches |
| RatelimitException | Handles search rate limits |
| logging | Displays runtime information |
| BedrockModel | Connects to Amazon Bedrock |
⚙️ Step 2: Configure Logging
logging.getLogger("strands").setLevel(logging.INFO)
Logging helps us understand what the agent is doing during execution.
Example output:
INFO | strands.agent | Processing user request
INFO | strands.tools | Executing websearch tool
During development, logs provide valuable visibility into agent behavior.
⚙️ Step 3: Create the Web Search Tool
@tool
def websearch(
keywords: str,
region: str = "us-en",
max_results: int | None = None
) -> str:
This function becomes a Strands tool through the @tool decorator.
The agent can now call this function whenever it needs information from the web.
Parameters
| Parameter | Description |
|---|---|
| keywords | Search query |
| region | Search region |
| max_results | Maximum number of results |
Example:
websearch(
"chicken capsicum recipe"
)
⚙️ Step 4: Search Using DDGS
results = DDGS().text(
keywords,
region=region,
max_results=max_results
)
DDGS performs a DuckDuckGo search and returns matching results.
These results are then sent back to the agent.
The agent uses them to generate an informed response.
⚙️ Step 5: Handle Errors Gracefully
Production-ready tools should always handle failures.
Rate Limit Handling
except RatelimitException:
If too many requests are made, DDGS may temporarily block searches.
Instead of crashing, the tool returns a helpful message.
General Error Handling
except Exception as e:
Unexpected failures are captured and returned safely.
This improves reliability and user experience.
🧠 Why the Docstring Matters
"""Search the web to get updated information."""
The docstring helps the LLM understand:
- What the tool does
- When it should use it
- What kind of information it can retrieve
Think of the docstring as instructions for the AI.
A clear description leads to better tool selection.
⚙️ Step 6: Configure Amazon Bedrock
bedrock_model = BedrockModel(
model_id="<YOUR_MODEL_ID>",
region_name="eu-west-2",
temperature=0.3,
)
This model powers the reasoning and decision-making process.
The agent determines:
- Whether web search is needed
- What search query to generate
- How to interpret results
- How to respond to users
⚙️ Step 7: Create a Specialized Recipe Agent
recipe_agent = Agent(
model=bedrock_model,
system_prompt="""
You are RecipeBot...
""",
tools=[websearch],
)
This agent has a clear responsibility:
Find recipes
Answer cooking questions
Search the web when necessary
The system prompt defines the agent's personality and capabilities.
⚙️ Step 8: Ask the Agent a Question
response = recipe_agent(
"Suggest a recipe with chicken and capsicum."
)
The agent receives the request and reasons about how to solve it.
Because recipe information may require fresh data, it can choose to invoke the web search tool.
▶️ Run the Agent
Execute the script:
python agent.py
Or:
uv run labs/04b-websearch-tool/agent.py
📊 Example Interaction
User
Suggest a recipe with chicken and capsicum.
Agent Workflow
User Request
↓
Agent Analysis
↓
Web Search Tool
↓
Recipe Search Results
↓
Response Generation
Agent Response
You can make a Chicken Capsicum Stir Fry.
Ingredients:
- Chicken breast
- Capsicum
- Onion
- Garlic
- Soy sauce
Instructions:
1. Sauté garlic and onion.
2. Add chicken and cook thoroughly.
3. Add sliced capsicum.
4. Stir in soy sauce.
5. Serve hot with rice.
Actual responses may vary depending on model and search results.
📈 Understanding Agent Metrics
At the end of the script:
print(f"Metrics : {response.metrics}")
Metrics help monitor agent performance.
You may see information such as:
Input Tokens
Output Tokens
Latency
Tool Calls
These metrics become extremely useful when optimizing production agents.
🔍 How Tool Calling Works
When a user asks a question:
User Prompt
↓
Agent Reasoning
↓
Tool Selection
↓
Web Search
↓
Results Returned
↓
Final Response
The agent automatically decides whether the tool should be used.
You don't need to manually call the function.
This is what makes agentic systems powerful.
💡 Real-World Use Cases
The same approach can be used for:
News Assistant
Search latest headlines
Research Assistant
Search technical documentation
Travel Assistant
Search destinations and hotels
Shopping Assistant
Search products and reviews
Support Assistant
Search knowledge bases
A web search tool unlocks countless possibilities.
🎯 Key Takeaways
- Custom tools allow agents to access live information
- DDGS provides a simple web search capability
- Error handling improves reliability
- Docstrings help the LLM understand tool functionality
- Agents automatically decide when to invoke tools
- Tool-based architectures make AI assistants far more useful
📚 Source Code
GitHub Repository:
https://github.com/d3vjamal/strands-agents-labs
🚀 Previous Lab
Lab 04A: Creating Your First Custom Tool | Strands Agentic AI
Top comments (0)