---
title: "Verify Agent Answers with Live Search: A Grounding Pattern"
description: "Check a model's claim against Google Search and Google News JSON with two calls (2 credits), and handle stale or conflicting sources honestly."
url: https://perceptlayer.com/blog/ground-agent-answers-live-search
---

[Blog](https://perceptlayer.com/blog) / [AI agents](https://perceptlayer.com/blog/category/ai-agents)

# Verify Agent Answers with Live Search: A Grounding Pattern

3 Jul 2026 Perceptlayer 8 min read

Grounding an LLM with search results means checking each factual claim in a draft answer against live sources before it reaches the user. Extract the claim, run one web search and one news search, hand the model only those results, and make it return a verdict with URLs and dates. Two calls cost 2 credits per claim, and the hard part is not the retrieval but deciding what to do when the sources are old or disagree.

## Key takeaways

-   Treat grounding as a verification step after the draft, not only as context before it: one `/v1/google-search/search` call plus one `/v1/google-news/news` call per claim.
-   Keep the date with every result. News results carry `iso_date`; web snippets sometimes start with a date, and some don't.
-   Return one of five verdicts: supported, contradicted, outdated, conflicting or unverified. "Unverified" is a valid answer.
-   Checking a claim costs 2 credits (2 calls × 1 credit). Failed calls cost nothing.
-   Search results are evidence, not truth. A snippet can be truncated, old or wrong, and the pattern has to say so.

## What does grounding an LLM with search results mean?

Grounding means the model's answer is tied to retrieved sources that a reader can open, instead of resting on training data alone. Retrieval-augmented generation, introduced in [Lewis et al.'s 2020 paper](https://arxiv.org/abs/2005.11401), supplies documents to the model at generation time. Hallucination, where fluent output is not supported by any source, is surveyed in [Ji et al.'s 2022 review](https://arxiv.org/abs/2202.03629).

Most grounding guides retrieve first and generate second. That works for questions you know in advance. This article covers the other direction: the agent has already drafted an answer, and a second pass checks the claims in it. It's cheaper to reason about, because each check is small, bounded and has an explicit pass or fail.

If you want the retrieve-first version, read [RAG with live web data](https://perceptlayer.com/blog/rag-with-live-web-data). The two combine well: retrieve to write, verify before you send.

## Why check claims after the draft instead of before?

A draft shows you which claims the model actually made, so you only spend calls on those. Pre-retrieval fetches pages for the topic and hopes the right fact is in them. Post-draft verification queries the exact statement, and a miss is visible: no supporting result means the claim stays unverified.

It also separates two jobs. The first pass writes. The second pass acts as a reviewer that sees only the claim and the evidence, not the conversation, so it can't be talked into agreeing with the draft.

The cost is latency. You make a second round trip, and you'll want to run the two searches concurrently. If you hit the request rate, [concurrent requests under rate limits](https://perceptlayer.com/blog/concurrent-api-requests-python-rate-limit) covers the loop. Rates are counted per minute, and every response carries `RateLimit-Remaining` and `RateLimit-Reset`; the [rate limits](https://docs.perceptlayer.com/rate-limits) docs cover the rest.

## How does the pattern work step by step?

Five steps: pull checkable claims out of the draft, turn each into a search query, fetch web and news results, compact them to the fields the judge needs, and ask the model for a verdict that cites the evidence. The model never sees raw JSON, only a short list of titles, URLs, snippets, sources and dates.

1.  **Extract claims.** Ask the model for atomic, checkable statements: names, numbers, dates, "latest" and "first" claims. Skip opinions.
2.  **Write a query per claim.** Short and specific beats a pasted sentence.
3.  **Fetch two views.** The [Search endpoint](https://perceptlayer.com/apis/google-search/search) returns web results; the [News endpoint](https://perceptlayer.com/apis/google-news/news) returns articles with a publication timestamp.
4.  **Compact.** Keep title, link, snippet, source and date. Drop thumbnails, tokens and pagination. [Trimming API responses for LLM context](https://perceptlayer.com/blog/trim-api-responses-llm-context) shows how much that saves.
5.  **Judge.** Force a verdict from a fixed list and require a URL for every verdict except "unverified".

### The evidence fetcher

This Python collects both result sets for one query. It uses only parameters from the endpoint tables: `query` and `hl` for search, `q` and `hl` for news.

```python
import os
import requests

BASE = "https://api.perceptlayer.com"
HEADERS = {"X-API-Key": os.environ["API_KEY"]}

def get(path, **params):
    r = requests.get(BASE + path, headers=HEADERS, params=params, timeout=30)
    if r.status_code in (429, 503):
        wait = r.headers.get("Retry-After")
        raise RuntimeError(f"retry after {wait}s")
    r.raise_for_status()
    return r.json()

def evidence(query):
    web = get("/v1/google-search/search", query=query, hl="en")
    news = get("/v1/google-news/news", q=query, hl="en")
    return {
        "web": [
            {
                "title": x.get("title"),
                "url": x.get("link"),
                "snippet": x.get("snippet"),
                "source": x.get("source"),
            }
            for x in web.get("organic_results", [])
        ],
        "news": [
            {
                "title": x.get("title"),
                "url": x.get("link"),
                "snippet": x.get("snippet"),
                "source": (x.get("source") or {}).get("name"),
                "date": x.get("iso_date"),
            }
            for x in news.get("news_results", [])
        ],
    }
```

Authentication is the `X-API-Key` header ( [authentication](https://docs.perceptlayer.com/authentication)). A rate-limited (429) or temporarily unavailable (503) response carries `Retry-After` with the seconds to wait, and failed calls aren't billed. Production code should retry; [handling errors in Python](https://perceptlayer.com/blog/handle-web-data-api-errors-python) has the full version.

### The judge prompt

The prompt is where most grounding fails, so keep it strict:

```text
Claim: {claim}
Today's date: {today}

Evidence (web results and news results, each with source and date when known):
{evidence}

Using ONLY the evidence, return JSON:
{"verdict": "supported|contradicted|outdated|conflicting|unverified",
 "reason": "one sentence",
 "urls": ["the result URLs your verdict rests on"]}

Rules:
- If sources disagree, use "conflicting" and list both sides.
- If the evidence is newer than the claim implies, use "outdated".
- If no result addresses the claim, use "unverified". Do not guess.
- A snippet that ends in "..." may be cut off; do not infer what follows.
```

Pass today's date explicitly. Models don't reliably know it, and "outdated" is meaningless without it.

## What does a worked check look like?

Two checks, using excerpts of real recorded responses. In both, the claim is what a model might plausibly say; the evidence is what the API returned.

### Example 1: a stale "latest" claim

Suppose the draft says: "Gartner's most recent strategic technology trends report covers 2025." The recorded sample comes from a broader query, `q=technology`, which is enough to show the mechanics; in your agent you'd search for the claim's own wording. The news call:

```bash
curl "https://api.perceptlayer.com/v1/google-news/news?q=technology" \
  -H "X-API-Key: $API_KEY"
```

The recorded response for that request includes this first result:

```json
{
  "news_results": [
    {
      "position": 1,
      "title": "Top Strategic Technology Trends for 2027",
      "link": "https://www.gartner.com/en/articles/top-technology-trends-2027",
      "snippet": "Explore Gartner's Top Strategic Technology Trends for 2027 — 10 trends that will shape autonomy, resilience and governance in the years...",
      "iso_date": "2026-10-20T15:59:45+00:00",
      …
      "source": {
        "name": "Gartner",
        …
      }
    }
  ],
  …
}
```

A Gartner page titled for 2027 and dated 2026-10-20 strongly suggests the draft's "most recent" claim is out of date as of 2026-10-24, since a 2027 report implies a newer one than 2025. The verdict is **outdated**, with the Gartner URL as the citation. It's an inference, not proof: the snippet is truncated and the title alone doesn't rule out something newer still, so a stricter pipeline would fetch the page before committing. The source is the publisher itself and the timestamp is machine-readable, which keeps the judge's guessing to a minimum.

### Example 2: a number that a snippet disputes

Now suppose the draft says: "Tim Raue, the Berlin restaurant, holds three Michelin stars." The search call is the one from the recorded sample:

```bash
curl "https://api.perceptlayer.com/v1/google-search/search?query=best+restaurants+in+Berlin&hl=en&safe=off" \
  -H "X-API-Key: $API_KEY"
```

Two organic results from the recorded response:

```json
{
  "organic_results": [
    {
      "position": 1,
      "title": "The Best Restaurants in Berlin - Food Guide & Map",
      "link": "https://andershusa.com/best-restaurants-berlin-germany-guide/",
      "snippet": "Dec 3, 2025 — Tim Raue is the most internationally renowned restaurant in Berlin. It holds two Michelin stars, has been frequently ranked on The World's 50 ...",
      "source": "Anders & Kaitlin",
      …
    },
    {
      "position": 2,
      "title": "Restaurants - Berlin",
      "link": "https://guide.michelin.com/us/en/berlin-region/berlin/restaurants",
      "snippet": "Berlin and surroundings: 1-48 of 79 restaurants · POTS · Rutz · GOLVET · Bandol sur mer · Nobelhart & Schmutzig · Oukan · 136 · FACIL.",
      "source": "MICHELIN Guide",
      …
    }
  ],
  …
}
```

Result 1 says two stars, which differs from the draft's three. This article doesn't vouch for either number; the point is what the evidence says. That result is a travel blog, the snippet is dated Dec 3, 2025, and it's a secondary source. Result 2 is the Michelin Guide's own listing page, the kind of primary source you'd want, and its snippet doesn't mention stars at all.

An honest verdict here is **conflicting, leaning contradicted**: one dated secondary source disagrees with the draft, and the primary source's snippet neither confirms nor denies. Nobody has checked the Michelin page itself. A good pipeline doesn't quietly rewrite "three" to "two". It flags the claim, links both results, and, if the stakes justify it, fetches the Michelin page itself.

## Where does this pattern fail?

It fails in four predictable ways, and each one needs a decision in your code rather than a better prompt. Stale sources look authoritative, sources disagree, snippets are cut off, and ranking is not truth. Stating these in the output is part of the pattern; a verifier that always sounds certain is a hallucination generator with citations.

| Failure | What you see | What to do |
| --- | --- | --- |
| Stale source | A well-ranked result is months old; the web snippet has no date | Prefer news results with `iso_date` for time-sensitive claims. Return "outdated" or "unverified", never "supported", when the only match is undated |
| Conflicting sources | Two results give different numbers | Return "conflicting" with both URLs. Don't average, and don't pick the higher-ranked one |
| Truncated snippet | The text ends in `...` | Treat it as a lead, not a quote. Fetch the page if the claim hinges on the missing words |
| Rank is not truth | The top result is a blog; the primary source is third | Tell the judge to prefer primary sources (the company, the registry, the publisher) and to say which kind it relied on |
| No match | Neither call returns anything on the claim | "Unverified". Absence of results is not a contradiction |

Two limits are specific to the tools. News coverage depends on what Google News indexes, so a niche claim may have no news result at all. And data is returned as found at the time of the call: a result that's correct today can change tomorrow, so store the retrieval date next to each verdict.

## What does it cost per answer?

Each claim costs 2 credits: one Search call and one News call, 1 credit each. An answer with 5 checkable claims costs 5 × 2 = 10 credits, and an agent that verifies 1,000 such answers a month spends 10,000 credits. Failed calls cost nothing and return `X-Credits-Used: 0`.

The free tier gives 1,000 credits every month after you verify an email, which covers 500 claim checks. Beyond that, credits come in prepaid packs starting at 10,000 credits; [pricing](https://perceptlayer.com/pricing) has what they cost, and the [credits](https://docs.perceptlayer.com/credits) docs cover how credits work.

To keep spend predictable, verify only claims that matter: numbers, dates, "latest", "first", names. Skip claims the user supplied and anything with no external referent. For caps and budgets across a whole agent, see [AI agent API cost control](https://perceptlayer.com/blog/ai-agent-web-data-costs), and [caching responses](https://perceptlayer.com/blog/cache-web-data-api-responses) helps when the same claim recurs.

## How do you give an agent this as a tool?

Expose the two calls as tools and let the agent choose, or wrap `evidence()` in one `verify_claim` tool of your own. The MCP server at `https://api.perceptlayer.com/mcp` offers `search_endpoints`, `get_endpoint` and `call_endpoint`. The first two only read the catalogue and cost nothing; `call_endpoint` runs an endpoint and spends its credits on success only.

For Claude Code, add the server with the command from the [AI agents docs](https://docs.perceptlayer.com/ai-agents):

```bash
claude mcp add --transport http perceptlayer https://api.perceptlayer.com/mcp --header "Authorization: Bearer $API_KEY"
```

A single wrapped tool is usually the better design for verification, because it fixes the query shape, the compaction and the two-call budget. Open-ended tool access makes sense when the agent must choose among many sources. The trade-offs are covered in [MCP vs function calling](https://perceptlayer.com/blog/mcp-vs-function-calling-web-data) and [tool schema design](https://perceptlayer.com/blog/agent-tool-schema-design-web-apis). For a full MCP walkthrough, see [Claude MCP web search](https://perceptlayer.com/blog/claude-agent-live-search-mcp).

Your next step: [get a free API key](https://perceptlayer.com/signup), run the News call from example 1 in the playground on the [Google News API](https://perceptlayer.com/apis/google-news) page, then try one claim from your own agent's last answer.

## APIs in this post

-   [Google Search **1 credit per call** · 7 endpoints](https://perceptlayer.com/apis/google-search)
-   [Google News **1 credit per call** · 1 endpoint](https://perceptlayer.com/apis/google-news)

## Frequently asked questions

### Does grounding with search results stop hallucinations?

It reduces unsupported claims but doesn't remove them. The model can still misread a snippet, cite a result that doesn't say what it claims, or accept a wrong source. Requiring a URL per verdict, a fixed verdict list and an explicit "unverified" option makes errors visible and checkable instead of hidden.

### Should I use Google Search or Google News for verification?

Use both. News results include `iso_date`, so they suit time-sensitive claims such as latest releases and recent events. Web results cover reference pages, primary sources and older facts, but snippets may carry no date. One call to each costs 2 credits. See the [Google Search API](https://perceptlayer.com/apis/google-search) and [Google News API](https://perceptlayer.com/apis/google-news).

### What happens if a verification call fails?

A failed call is not billed and returns `X-Credits-Used: 0`. For 429 and 503, wait the seconds in `Retry-After` and retry. Other failures return a JSON error with a code and `request_id`; see [errors](https://docs.perceptlayer.com/errors). If a lookup still fails, mark the claim unverified rather than passing it unchecked.

### Can I fetch the full page behind a result?

The Search and News endpoints return titles, links, snippets and dates, not page bodies. If a claim depends on text past a truncated snippet, fetch the linked page with your own HTTP client, or use another endpoint from the [catalogue](https://perceptlayer.com/apis) that fits that website. Keep the retrieval date with whatever you store.

### How many claims should I verify per answer?

Only the ones a wrong answer would hurt: figures, dates, names, and anything phrased as "latest" or "first". Each verified claim costs 2 credits, so 5 claims cost 10 credits. Verifying every sentence adds cost and latency without adding much, because most sentences aren't checkable facts.

grounding ai agents verification google search google news

## More from the blog

1.  [AI agents](https://perceptlayer.com/blog/category/ai-agents) 17 Sept 2026 Perceptlayer 7 min read
    
    ## [RAG with Live Web Data: When to Skip the Vector Store](https://perceptlayer.com/blog/rag-with-live-web-data)
    
    Which RAG questions need a stored index and which need a fresh call. A per-query Google Search lookup costs 1 credit, with the latency trade-off.
    
2.  [AI agents](https://perceptlayer.com/blog/category/ai-agents) 30 Jul 2026 Perceptlayer 7 min read
    
    ## [Scheduled AI Agent Runs: Budgeting Credits per Run](https://perceptlayer.com/blog/scheduled-agent-credit-budget)
    
    Cap an agent at N calls per run with a Python ledger that reads X-Credits-Used, plus the math for hourly and daily runs on 1,000 free credits.
    
3.  [AI agents](https://perceptlayer.com/blog/category/ai-agents) 22 Jul 2026 Perceptlayer 11 min read
    
    ## [LangChain Custom Tool for Live Web Data: Python Tutorial](https://perceptlayer.com/blog/langchain-custom-tool-web-data)
    
    Build a LangChain tool in Python for Google Search and News: typed arguments, retries on 429, 502 and 503 only, and a per-run credit cap.
