Adding Web Search to Your AI Agent
Give your AI real-time context.
Our AI was generating replies based on stale context.
It knew about our blog posts from a static index. It knew our company voice from a prompt file. But it couldn’t look anything up. When someone tweeted about a breaking news story or referenced something current, our AI was clueless.
The fix: give it web search.
The Tools
We added two capabilities:
web_search - Query Brave Search API, get back titles, URLs, and snippets. Good for “what’s the current context around this topic?”
web_fetch - Fetch a URL and extract the text content. Good for “let me read that article before responding.”
Together, they let the AI research before it responds. See a tweet about a new AI model? Search for context. Want to reference our own blog post? Fetch it and quote accurately.
Brave Search API
We picked Brave for a few reasons:
- 2,000 free queries/month (plenty for our volume)
- Simple REST API, no SDK needed
- Returns clean structured data
The integration is ~50 lines:
class BraveSearch:
def search(self, query: str, count: int = 5) -> list[dict]:
response = requests.get(
"https://api.search.brave.com/res/v1/web/search",
headers={"X-Subscription-Token": self.api_key},
params={"q": query, "count": count},
)
results = []
for item in response.json().get("web", {}).get("results", []):
results.append({
"title": item.get("title"),
"url": item.get("url"),
"description": item.get("description"),
})
return results
URL Fetching
Web pages are messy. We need the content, not the chrome.
class WebFetcher:
def fetch(self, url: str) -> dict:
response = requests.get(url, timeout=15)
html = response.text
# Extract text content (simplified)
text = self._html_to_text(html)
text = text[:self.max_length] # Truncate for context window
return {"url": url, "content": text}
The HTML-to-text conversion strips tags, collapses whitespace, extracts the readable content. Not perfect, but good enough for giving the AI context.
Tool Definitions for Claude
Claude’s tool use requires JSON schemas. For AWS Bedrock’s Converse API:
WEB_SEARCH_TOOL = {
"name": "web_search",
"description": "Search the web for current information.",
"inputSchema": {
"json": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "The search query.",
},
},
"required": ["query"],
}
},
}
Note the nested structure: inputSchema.json. Bedrock’s Converse API is picky about this format. The Anthropic API uses a slightly different structure. Get this wrong and you’ll get validation errors.
The Gotcha: Extended Thinking + Tools
Here’s something that cost us an hour of debugging.
When using Claude’s extended thinking with tool use, there’s a constraint: if thinking is enabled, assistant messages in the conversation must start with thinking blocks.
Our tool loop looked like:
- Claude responds with thinking + tool_use
- We execute the tool
- We send tool results back
- Claude continues…
Step 3 broke. We were building the assistant message without the thinking block:
# WRONG
assistant_content = [
{"text": response_text},
{"toolUse": {...}},
]
Bedrock rejected it. The fix: either include the thinking block, or disable thinking for continuation calls. We went with the simpler option:
# For tool continuations, disable thinking
response = client.invoke(
messages=messages,
thinking_budget=0, # No thinking for tool loop
)
The first call does the deep thinking. Continuations just process tool results and respond. Works fine.
When the AI Uses Tools
We don’t force tool use. The AI decides when it needs more context:
Tweet: "The new Claude 4.5 benchmarks are insane"
AI thinking: "This references something current. Let me search
for context before responding..."
[Calls web_search: "Claude 4.5 benchmarks January 2026"]
AI: "The reasoning improvements are real - we're seeing it
in our own pipelines. The extended thinking on complex
tasks is noticeably better."
Sometimes it searches. Sometimes it fetches our blog to quote accurately. Sometimes it just responds from context. The AI makes the call.
Prompt Integration
We tell the AI about its tools in the system prompt:
## Available Tools
You have access to these tools if you need more context:
- web_search: Search for current news, context, or background
- web_fetch: Fetch a URL to read full content
Use tools sparingly - only if you need specific information
to craft a better reply.
The “use sparingly” guidance matters. Without it, the AI might search for everything, burning API calls and adding latency.
Results
Before: Replies were generic or referenced outdated info.
After: Replies reference current context, quote our blog accurately, engage with breaking topics.
The quality improvement was immediate. The AI went from “responding to the text” to “responding to the situation.”
Try It
If your AI agent would benefit from current information:
- Brave Search - Free tier, simple API, 5 minutes to integrate
- URL fetcher - Basic HTTP + HTML parsing, handles most pages
- Tool definitions - Match your LLM provider’s schema format
- Prompt guidance - Tell the AI when to use tools, when not to
The web isn’t static. Your AI shouldn’t be either.