I have an issue with a SerperDev search tool

With the same code I was working with weeks ago.
Updated the API key and added credits.
Does any one have an idea?
Here is the error. See the bottom line (Error code 403)

Agent: Senior Research Assistant

Thought: To conduct a comprehensive analysis of AI agents as of October 2024, I need to gather the latest information on key trends, breakthrough technologies, and potential industry impacts. I will start by searching for recent articles and reports on AI agents.

Using tool: Search the internet

Tool Input:

“{"search_query": "AI agents October 2024 trends breakthroughs industry impact"}”

Tool Output:

{‘message’: ‘Unauthorized.’, ‘statusCode’: 403}

1 Like

Yesterday, the same happened with me with one crew(403) but for another old crewai no problem. I do not know the reason.

@Pazalka @aiTravenup Did you guys upgrade the CrewAI SDK in the meantime? Maybe it’s an SDK issue?


Different results for the same specification. Now I think something related to venv issues. Tks!!!

The same happened to me, and it seems like serper wants us to send the request via URL. So I wrote my own version of the tool that goes to google custom search instead of serper. Hope this helps. I’ve left the print statements in to check that it works. Its only compatible with the very latest package.

This how you import it.
my_serper_dev_tool_path = ‘D:/Code/agents/crewai/code/misc’

sys.path.insert(0, my_serper_dev_tool_path)

from my_serper_dev_tool import SerperDevTool

search_tool = SerperDevTool()

This is my class:
import os
import sys
import requests
from pydantic import BaseModel, Field
from typing import Any, Optional, Type
from crewai_tools import BaseTool
import datetime

def save_results_to_file(content: str) → None:
“”“Saves the search results to a file.”“”
filename = f"search_results
{datetime.datetime.now().strftime(‘%Y-%m-%d_%H-%M-%S’)}.txt"
with open(filename, “w”) as file:
file.write(content)
print(f"Results saved to {filename}")

def _get_google_key() → str:
script_dir = os.path.dirname(os.path.abspath(file))
filename = os.path.join(script_dir, “google_key.txt”)
print(f’google_key filename={filename}')
try:
with open(filename, “r”) as file:
line = file.readline().strip()
key_name, API_KEY = line.split(“=”, 1)
except FileNotFoundError:
print(f"Error: {filename} file not found or could not be read")
exit()
return API_KEY

class SerperDevToolSchema(BaseModel):
search_query: str = Field(
…, description=“Mandatory search query you want to use to search the internet”
)

class SerperDevTool(BaseTool):
name: str = “Search the internet”
description: str = “A tool that can be used to search the internet with a search_query.”
args_schema = SerperDevToolSchema # Direct assignment, no Type hint here
search_url: str = “https://google.serper.dev/search
country: Optional[str] = “”
location: Optional[str] = “”
locale: Optional[str] = “”
n_results: int = 10
save_file: bool = False

def _run(self, **kwargs: Any) -> Any:
    search_query = kwargs.get("search_query") or kwargs.get("query")
    save_file = kwargs.get("save_file", self.save_file)
    n_results = kwargs.get("n_results", self.n_results)
    api_key = _get_google_key()
    cx = 'create your own site on google'
    print(f'\n\nkwargs:\n{kwargs}')
    if kwargs:
        url = f"https://www.googleapis.com/customsearch/v1?q={search_query}&key={api_key}&cx={cx}&num={n_results}"
        response = requests.get(url)
    else:
        response = "No search query provided and therefore no results returned." 

    data = response.json()


    # Extract and format the output
    formatted_results = []
    for item in data.get("items", []):
        result = {
            "Title": item.get("title"),
            "Link": item.get("link"),
            "Snippet": item.get("snippet")
        }
        formatted_results.append(result)

    # Print or save the formatted output in a readable way
    for result in formatted_results:
        print(f"Title: {result['Title']}")
        print(f"Link: {result['Link']}")
        print(f"Snippet: {result['Snippet']}")
        print("---")  # Separator for readability

    if save_file:
        _save_results_to_file(formatted_results)


    return f"\nSearch results: {formatted_results}\n"

“”"
if “organic” in data:
results = data[“organic”][:self.n_results]
string =
for result in results:
try:
string.append(
“\n”.join(
[
f"Title: {result[‘title’]}“,
f"Link: {result[‘link’]}”,
f"Snippet: {result[‘snippet’]}",
“—”,
]
)
)
except KeyError:
continue

        content = "\n".join(string)
        if save_file:
            _save_results_to_file(content)
        return f"\nSearch results: {content}\n"
    else:
        return data

“”"