Give a CrewAI Crew Real-Time Web Search

A crew is several agents with the same tools, which means a tool that is slightly too expensive or slightly too chatty gets that flaw multiplied by the number of agents. Here is the search tool written both ways, and the two settings that stop a crew from searching the same thing four times.
TL;DR
- •@tool from crewai.tools is enough for a search tool; subclass BaseTool when you want a Pydantic args_schema and a typed contract.
- •The tool description is the whole spec the delegating agent reads — write it as instructions, not as a label.
- •A crew multiplies tool calls: the same question researched by four agents is four searches unless you cache or centralise.
- •POST https://www.apipick.com/api/search/web with an x-api-key header: 15 credits per call, charged only on HTTP 200.
- •Give the search tool to one researcher agent and let the others read its output, rather than arming every agent with it.
What changes when the caller is a crew?
A single agent calls a tool when it needs it. A crew calls it once per agent that holds it — and then again after delegation, because the agent receiving the delegated task often decides it needs its own look at the evidence.
That turns two properties of a search tool from nice-to-have into load-bearing: how wide the result set is, and what a redundant call costs. Both are decisions you make inside twenty lines of tool code.
What does the tool look like with @tool?
import os, httpx
from crewai.tools import tool
API_KEY = os.environ["APIPICK_KEY"]
@tool("Web Search")
def web_search(query: str) -> str:
"""Search the live web and return ranked results.
Use this when the answer depends on current information — news,
prices, product details, anything published after your training
data. Write the query in plain words, the way a person would
type it into a search box.
Returns up to five results as 'title — url — snippet' lines.
"""
r = httpx.post(
"https://www.apipick.com/api/search/web",
headers={"x-api-key": API_KEY},
json={"query": query, "max_num_results": 5},
timeout=20,
)
r.raise_for_status()
return "\n\n".join(
f"{x['title']} — {x['url']}\n{x['snippet']}"
for x in r.json()["results"]
)When is BaseTool worth the extra code?
The moment the tool takes more than one argument. A Pydantic args_schema is what stops an agent from inventing country when the parameter is country_code.
from typing import Type, Optional
from pydantic import BaseModel, Field
from crewai.tools import BaseTool
class WebSearchInput(BaseModel):
query: str = Field(..., description="Plain-language search query")
country_code: Optional[str] = Field(
None, description="ISO country code to localise results, e.g. US or GB"
)
start_date: Optional[str] = Field(
None, description="Only results published on or after this ISO date (YYYY-MM-DD)"
)
class WebSearchTool(BaseTool):
name: str = "Web Search"
description: str = (
"Search the live web for current information. Use for news, prices, "
"and anything published after your training cutoff. Optionally "
"restrict by country or publication date."
)
args_schema: Type[BaseModel] = WebSearchInput
def _run(self, query: str, country_code=None, start_date=None) -> str:
body = {"query": query, "max_num_results": 5}
if country_code: body["country_code"] = country_code
if start_date: body["start_date"] = start_date
r = httpx.post(
"https://www.apipick.com/api/search/web",
headers={"x-api-key": API_KEY}, json=body, timeout=20,
)
r.raise_for_status()
return "\n\n".join(
f"{x['title']} — {x['url']}\n{x['snippet']}"
for x in r.json()["results"]
)How should the crew be wired?
The instinct is to give every agent the search tool. Resist it. The cheaper and more coherent pattern is one researcher holds the tool, and downstream agents consume what it produced.
from crewai import Agent, Task, Crew
search = WebSearchTool()
researcher = Agent(
role="Researcher",
goal="Find and cite current evidence for the question at hand",
backstory="You never state a fact without a URL to back it.",
tools=[search], # only this agent searches
)
analyst = Agent(
role="Analyst",
goal="Turn the researcher's evidence into a defensible conclusion",
backstory="You work strictly from the evidence handed to you.",
tools=[], # no tools — reads the researcher's output
)
crew = Crew(
agents=[researcher, analyst],
tasks=[
Task(description="Research: {topic}", agent=researcher,
expected_output="5-8 bullet findings, each with a URL"),
Task(description="Conclude, citing only the findings above", agent=analyst,
expected_output="A short memo with inline citations"),
],
)
crew.kickoff(inputs={"topic": "EU AI Act timeline changes this year"})Two agents, one tool, one pass of searches. Arm both and you pay twice for the same evidence — and often get two slightly different versions of it, which is worse than paying twice.
How do you add reading to the crew?
Snippets identify the page; they rarely contain the answer. Give the researcher a second tool so it can open the two or three URLs that matter.
@tool("Read Pages")
def read_pages(urls: list[str]) -> str:
"""Fetch clean readable text for specific URLs.
Call after Web Search when a snippet is not enough. Pass only the
URLs that look genuinely relevant — at most three.
"""
r = httpx.post(
"https://www.apipick.com/api/extract",
headers={"x-api-key": API_KEY},
json={"urls": urls[:3]},
timeout=60,
)
r.raise_for_status()
return "\n\n---\n\n".join(
f"# {x['title']}\n{x['url']}\n\n{x['content'][:6000]}"
for x in r.json()["results"] if x["status"] == "ok"
)Extraction is 2 credits per URL, so reading three pages costs less than half a search. The [:6000] is not about money — it is about not handing a crew forty thousand characters that every downstream agent then re-reads.
What should you check before shipping a crew?
- Only the agents that must search, search. Tool assignment is the main cost lever in a crew.
- Timeouts on every tool. A stalled HTTP call in one agent stalls the whole crew.
- Expected output that demands URLs. If the task description does not ask for citations, delegation quietly loses them.
- Only-on-success billing. Crews produce more malformed tool calls than single agents; with HTTP-200 billing those cost nothing.
The same tool in other frameworks: LangChain, Vercel AI SDK, n8n, and raw OpenAI / Claude. Start with a free key: 100 credits, no card.
Frequently Asked Questions
Does CrewAI have a built-in web search tool?
crewai-tools ships wrappers for several search vendors, and they work. Writing your own is worth it when you want to control the returned shape, cap the result count at the source, or use a provider whose billing suits a multi-agent workload. It is about twenty lines either way.
@tool decorator or BaseTool subclass?
Use @tool from crewai.tools for a single-argument search tool: the function becomes the tool, the docstring becomes the description. Subclass BaseTool when you want an explicit Pydantic args_schema — worth it once the tool takes a country code and a date range as well as a query, because the schema stops the agent inventing parameter names.
Why does my crew cost more than a single agent for the same question?
Because each agent that holds the tool will use it. A four-agent crew researching one topic issues roughly four times the searches a single agent would, and delegation adds more. The fix is architectural: give the search tool to one researcher agent, and let the analyst and writer agents work from that agent's output rather than searching again.
How do I keep search results from blowing up the crew's context?
Return three fields — title, url, snippet — and cap the count at the source with max_num_results (1–5, default 5). In a crew this matters more than in a single agent, because tool output often gets passed along through delegation, so an over-wide result set is re-read by every agent downstream of the one that fetched it.
What does a crew run cost in search calls?
Web Search is 15 credits per call and $1 buys 1,000 credits, so roughly $0.015 per search. A five-search research task is about $0.075. Credits come off only on HTTP 200, so the retries that a crew produces when one agent misformats an argument do not appear on the bill.
APIs used in this article
Sarah Choy is the CEO of API Pick. She writes about building production-ready APIs for AI agents and LLM workflows.