BetsyFromR's picture
Update tools/web_search.py
13e61d2 verified
from typing import Any, Optional
from smolagents.tools import Tool
import duckduckgo_search
import random
import time
class DuckDuckGoSearchTool(Tool):
name = "web_search"
description = "Performs a duckduckgo web search based on your query (think a Google search) then returns the top search results."
inputs = {'query': {'type': 'string', 'description': 'The search query to perform.'}}
output_type = "string"
def __init__(
self,
max_results=10,
backends=None,
retries=2,
min_delay=0.2,
max_delay=0.8,
**kwargs,
):
super().__init__()
self.max_results = max_results
self.backends = backends or ["auto", "lite", "html", "api"]
self.retries = retries
self.min_delay = min_delay
self.max_delay = max_delay
try:
from duckduckgo_search import DDGS
except ImportError as e:
raise ImportError(
"You must install package `duckduckgo_search` to run this tool: for instance run `pip install duckduckgo-search`."
) from e
self.ddgs = DDGS(**kwargs)
def _format_results(self, results) -> str:
postprocessed_results = []
for result in results:
title = result.get("title") or "Untitled"
href = result.get("href") or result.get("url") or ""
body = result.get("body") or result.get("snippet") or ""
postprocessed_results.append(f"[{title}]({href})\n{body}".strip())
return "## Search Results\n\n" + "\n\n".join(postprocessed_results)
def forward(self, query: str) -> str:
last_error = None
for backend in self.backends:
for attempt in range(self.retries + 1):
try:
results = list(
self.ddgs.text(query, max_results=self.max_results, backend=backend)
)
except Exception as e:
last_error = e
# Jittered backoff to reduce rate-limit issues.
sleep_for = min(
self.max_delay,
self.min_delay * (2 ** attempt) + random.random() * 0.1,
)
time.sleep(sleep_for)
continue
if results:
return self._format_results(results)
# Empty results can happen; try next backend.
break
if last_error is not None:
return (
"Web search failed. This can happen if outbound network access is blocked or the "
f"DuckDuckGo API is rate-limiting requests. Error: {last_error}"
)
return (
"No results found. This may indicate network restrictions or a temporary "
"DuckDuckGo issue. Try a shorter query or retry later."
)