cloro

How to Add Web Search to an AI Agent or RAG Pipeline

Ricardo Batista
Founder, cloro
•6 min read•
On this page

A language model answers from training data that stops at a cutoff date. Ask it about last week and it guesses, or says it does not know. A live web search API fixes that: the model reads today’s results and answers with sources a user can open and check.

This guide shows both ways to wire search into a model in Python, and the search tool again for a TypeScript agent. Then it gives the numbers we measured when we ran the same questions through six web search APIs: accuracy, latency and cost per search. The code uses cloro’s Google Search endpoint. The patterns work with any web search API that returns JSON.

Should you search first or let the model decide?

There are two patterns, and the choice decides your cost and your latency more than the API does.

PatternHow it worksSearches per questionUse it when
RAG groundingYour code runs one search with the user’s question, then puts the top results into the promptExactly 1Most questions need current facts: news, prices, product support, research assistants
Tool callingThe model sees a web_search tool and calls it zero, one or several times0 to manySome questions need no search, and some need several (multi-step research, comparisons)

Grounding is predictable, because every question costs one search and waits for one search. With tool calling, the model can search again when the first results miss the answer, and it can also run five searches on one question. Start with grounding unless you know your questions need more than one search.

Our benchmark used the grounding pattern: one search per question, with the question text as the query, and the top 10 results in the context. That is enough to answer 96.9% of SimpleQA Verified questions with cloro, and 97.8% with Parallel.

Is there a Google search API built for RAG pipelines?

Yes. A Google search API such as cloro returns Google’s live results page as JSON, which is the shape a RAG pipeline needs: the AI Overview as text, the organic results with title, link and snippet, and People Also Ask questions with answers. Your code puts those into the prompt, and the model answers from them with citations.

Install the cloro Python SDK and set your keys. The Python integration page covers the other endpoints:

pip install cloro openai
export CLORO_API_KEY="your-cloro-key"
export OPENAI_API_KEY="your-openai-key"

Then search, build the context and ask the model:

from cloro import Cloro
from openai import OpenAI

cloro = Cloro()  # reads CLORO_API_KEY
llm = OpenAI()   # reads OPENAI_API_KEY


def web_context(question: str, top_n: int = 10) -> str:
    """Run one Google search and return the results as numbered text blocks."""
    response = cloro.monitor.google(
        query=question,
        country="US",
        include={"aioverview": {"markdown": True}},
    )
    result = response["result"]
    blocks = []

    aio = (result.get("aioverview") or {}).get("markdown")
    if aio:
        blocks.append(f"[AI Overview]\n{aio}")

    for r in (result.get("organicResults") or [])[:top_n]:
        blocks.append(f"[{r['position']}] {r['title']}\n{r['link']}\n{r['snippet']}")

    return "\n\n".join(blocks)


def answer(question: str) -> str:
    prompt = f"""Answer the question using only the web results below.
Cite each fact with the result number in brackets.
If the results do not contain the answer, say so.

Web results:
{web_context(question)}

Question: {question}"""
    reply = llm.responses.create(model="gpt-5.6-luna", input=prompt)
    return reply.output_text


print(answer("When does the EU AI Act start to apply to general-purpose AI models?"))

The prompt tells the model to say when the results do not contain the answer. Without that line, a model fills gaps from training data, and the citation then points at a page that does not support the claim.

Each result block has a number and its URL, so the model can cite [2] and your interface can turn that into a link to the page.

The AI Overview goes first because it is Google’s own summary of the top pages. In our SimpleQA run it held the answer to every question cloro missed without it.

For a nightly job that refreshes a RAG index, do not call the synchronous endpoint in a loop. Submit the queries to POST /v1/async/task with taskType: "GOOGLE" and a webhook URL, as the API docs describe. Async requests skip the 2-credit sync surcharge, and the results arrive at your webhook as each search completes.

How do you give an AI agent a web search tool?

With tool calling, you describe a search function to the model, and the model decides when to call it and with what query.

With LangChain

The langchain-cloro package wraps cloro’s Google Search endpoint as a LangChain tool, so an agent built with LangChain’s create_agent needs only a few lines:

pip install langchain langchain-openai langchain-cloro
from langchain.agents import create_agent
from langchain_cloro import CloroGoogleSearch

search = CloroGoogleSearch()  # reads CLORO_API_KEY

agent = create_agent(
    model="openai:gpt-5.6-luna",
    tools=[search],
    system_prompt=(
        "You answer questions about current events and facts. "
        "Search the web when the answer may have changed since your training data. "
        "Search at most 3 times per question. "
        "Cite the URL of every result you use."
    ),
)

result = agent.invoke(
    {"messages": [{"role": "user", "content": "Which web search APIs have a free tier?"}]}
)
print(result["messages"][-1].content)

The tool takes the same options as the API: country, device, pages, and include_aioverview to add the AI Overview.

With a function-calling schema

Without LangChain, the same tool is a JSON schema in any function-calling API:

{
  "type": "function",
  "name": "web_search",
  "description": "Search Google and return the AI Overview and the top results with title, link and snippet. Use for facts that may have changed recently.",
  "parameters": {
    "type": "object",
    "properties": {
      "query": { "type": "string", "description": "The search query" }
    },
    "required": ["query"]
  }
}

When the model calls web_search, your code runs web_context(query) from the grounding example and returns the text as the tool result.

What should the system prompt say?

In a tool-calling agent, the system prompt decides most of the behaviour. The LangChain example has three rules:

  • When to search. Without a rule, the model decides alone, and it can answer from memory after the facts have changed.
  • What to cite. The URL of every result the answer uses lets a user check it.
  • A search limit. A cap of 3 searches per question stops an agent that keeps rewording the same query, and it caps your cost per task.

How do you add web search to a TypeScript agent?

The Vercel AI SDK defines a tool as a description, an input schema and an execute function. In the example below, execute calls cloro through the JavaScript SDK and returns the AI Overview and the top 10 results:

npm install ai @ai-sdk/openai @cloro-dev/cloro zod
import { generateText, isStepCount, tool } from "ai";
import { openai } from "@ai-sdk/openai";
import { Cloro } from "@cloro-dev/cloro";
import { z } from "zod";

const cloro = new Cloro(); // reads CLORO_API_KEY

const webSearch = tool({
  description:
    "Search Google and return the AI Overview and the top results with title, link and snippet. Use for facts that may have changed recently.",
  inputSchema: z.object({
    query: z.string().describe("The search query"),
  }),
  execute: async ({ query }) => {
    const { result } = await cloro.monitor.google({
      query,
      country: "US",
      include: { aioverview: { markdown: true } },
    });
    return {
      aiOverview: result.aioverview?.markdown ?? null,
      results: (result.organicResults ?? []).slice(0, 10).map((r: any) => ({
        position: r.position,
        title: r.title,
        link: r.link,
        snippet: r.snippet,
      })),
    };
  },
});

const { text } = await generateText({
  model: openai("gpt-5.6-luna"),
  system:
    "You answer questions about current events and facts. " +
    "Search the web when the answer may have changed since your training data. " +
    "Search at most 3 times per question. " +
    "Cite the URL of every result you use.",
  prompt: "Which web search APIs have a free tier?",
  tools: { web_search: webSearch },
  stopWhen: isStepCount(5),
});

console.log(text);

The system prompt asks for at most 3 searches, and stopWhen: isStepCount(5) stops the loop after five model steps in case the model ignores that rule. The tool returns an object, which the SDK sends to the model as JSON. The same results are in the steps array of the response, so your interface can show the sources next to the answer. We ran this example with ai 7.0 and @cloro-dev/cloro 0.3.0.

What makes search results good context for a model?

We ran 1,000 SimpleQA Verified questions and 358 FreshQA questions through six web search APIs, one search per question, with the same model reading each set of results. Four findings apply to how you build the context:

  • Accuracy is close at the top. On SimpleQA Verified, Parallel (97.8%), Exa (97.3%) and cloro (96.9%) were within the margin of error of each other. SerpApi scored 94.7%, Brave 93.1% and Tavily 91.8%.
  • Questions about recent events favour Google. On FreshQA, whose answers change over time, SerpApi (88.5%) and cloro (88.3%) led, and the independent indexes scored 81.8% to 84.9%.
  • The AI Overview is most of Google’s accuracy. In a 100-question run, cloro scored 99% with the AI Overview in the context and 89% without it. All 11 questions it missed without the AI Overview were correct with it.
  • Google results are short. In the same 100-question run (report), the model read about 800 tokens per question from cloro or SerpApi, against about 3,000 from Exa, Tavily, Brave and Parallel, which return longer page extracts. Fewer tokens in the context make each model call cheaper.

The harness, the settings and every graded answer are public in the web search API benchmark repo.

Latency is cloro’s weak point, and the AI Overview causes it: cloro waits for Google’s AI Overview before it returns the results. These are the three ways to call cloro, with prices on the Starter plan ($250 a month for 650,000 credits):

RequestCreditsPer 1,000 searchesp50 latency (100-question run)Use it for
Sync, no AI Overview5$1.923.6 sInteractive agents that need speed
Sync, with AI Overview7$2.6911.8 sInteractive agents that need accuracy
Async, with AI Overview5$1.92Delivered by webhookBatch jobs and RAG index refreshes

The two latencies in the table come from the same 100-question run, with and without the AI Overview. In the 1,000-question benchmark, the p50 search latency was 10.96 s for cloro with the AI Overview, 0.74 s for Exa, 1.21 s for Brave, 2.00 s for Tavily, 2.99 s for Parallel and 8.20 s for SerpApi. If your agent must answer in under 3 seconds, an independent index is the better choice today. If the answer must match what Google shows, or must be correct on recent events, Google results are worth the extra seconds.

At $2.69 per 1,000 searches, an agent that searches 3 times per task costs about $0.008 per task in search.

Can you add web search to Claude or Cursor without code?

Yes, with an MCP server. Claude, Claude Code and Cursor can call a web search tool through the Model Context Protocol, so you add a server URL instead of writing the tool yourself. Our web search MCP guide compares the free and paid servers and sets up cloro’s server, and the MCP integration page has the connection details.

Which web search API should your agent use?

The API matters less than the pattern, and the top three on accuracy are close. Choose on the second thing your agent needs: speed (Exa), Google’s page and the lowest price per search (cloro), or a ready-made answer (Tavily). Our web search API comparison has the accuracy results, prices, free tiers and how close each API gets to Google’s results.

Ricardo Batista

About the author

Founder, cloro

Ricardo is one of the founders and engineers behind its SERP and AI-search scraping infrastructure. Before cloro he scaled a financial comparison site to $7M ARR and ran the full-country operations of a unicorn to $65M ARR, then went back to building. He writes about search engine scraping, generative-engine optimization, and turning live search and AI-answer data into something teams can act on.

Frequently asked questions

How do I add web search to an AI agent?

Give it a web search API in one of two ways. For RAG grounding, your code runs one search per question and puts the top results into the prompt. For tool calling, you register a `web_search` tool and the model decides when to call it. Both take under 30 lines of Python with an API that returns results as JSON, such as cloro's Google Search endpoint or the `langchain-cloro` package.

Is there a Google search API built for RAG pipelines?

Yes. cloro's Google Search endpoint returns Google's live results page as JSON: the AI Overview, the organic results with title, link and snippet, and People Also Ask. That is the shape a RAG pipeline puts into a prompt. In our SimpleQA Verified run, with one search per question and the same model reading the results, cloro scored 96.9%.

Which search API works best as a tool inside an AI agent?

In our benchmark of six APIs, Parallel (97.8%), Exa (97.3%) and cloro (96.9%) were the most accurate on SimpleQA Verified, with no significant difference between them. Exa was the fastest at 0.74 s p50, and cloro the cheapest at $1.92 per 1,000 async searches with the AI Overview. The web search API comparison has the full results, prices and free tiers.

How much does web search cost per agent run?

With cloro on the Starter plan ($250 a month for 650,000 credits), a synchronous Google search costs 5 credits, $1.92 per 1,000, and 7 credits with the AI Overview, $2.69 per 1,000. An agent that searches three times per task pays about $0.008 per task with the AI Overview. Async requests skip the 2-credit sync surcharge.

Does the AI Overview make an agent more accurate?

On factual questions, yes. In a 100-question SimpleQA run, cloro answered 99 questions correctly with the AI Overview in the context and 89 without it. The cost is time: the p50 latency was 11.8 s with the AI Overview and 3.6 s without it.