n4nAI

Gemini 3 agents with Google Search grounding

Learn how to build Gemini 3 agents with Google Search grounding: step-by-step setup, code, and verification for production LLM systems.

n4n Team4 min read793 words

Audio narration

Coming soon — every post will get a voice note here.

Building reliable agents requires fresh data. Gemini 3 search grounding lets you attach Google Search as a tool so the model cites live web results instead of hallucinating. This guide walks through standing up a grounded agent end to end, from API config to verification.

Step 1: Provision credentials and install the SDK

Get a Gemini API key from Google AI Studio (or use a Vertex AI service account). The google-genai SDK unifies both surfaces and is the supported client for Gemini 3. Install it:

pip install google-genai

Initialize the client from an environment variable. Never hardcode keys in source.

from google import genai

client = genai.Client(api_key="AIza...")

The client targets the same REST endpoints that serve gemini-3-pro and gemini-3-flash. Confirm model availability in your region before shipping, because grounding may be restricted in some jurisdictions.

Step 2: Enable Gemini 3 search grounding in a single call

Grounding is a first-class tool. You pass a GoogleSearch tool instance and the model decides when to query the web. The response carries grounding metadata alongside the generated text.

from google.genai import types

response = client.models.generate_content(
    model="gemini-3-pro",
    contents="What are the current PCI-DSS v4.0 requirements for tokenizing PAN data?",
    tools=[types.Tool(google_search=types.GoogleSearch())],
)

print(response.text)
print(response.candidates[0].grounding_metadata)

The grounding_metadata block is the heart of gemini 3 search grounding. It contains web_search_queries (the actual searches issued), grounding_chunks (retrieved URLs with titles), and grounding_supports (which output token ranges are backed by which chunk). A typical structure looks like this:

{
  "web_search_queries": ["PCI-DSS v4.0 tokenization requirements"],
  "grounding_chunks": [
    {"web": {"uri": "https://www.pcisecuritystandards.org/", "title": "PCI DSS"}}
  ],
  "grounding_supports": [
    {"segment": {"start_index": 0, "end_index": 42}, "grounding_chunk_indices": [0]}
  ]
}

A common mistake is assuming the tool always fires. If the prompt is purely arithmetic or the model judges it has sufficient parametric knowledge, it may skip the search. Force coverage by explicitly requesting cited sources, or assert len(grounding_chunks) > 0 in tests.

Step 3: Wrap the call in a minimal agent loop

A single call is not an agent. You need state and iteration. Below is a stripped-down loop that retains history and re-invokes the model with the same grounding tool each turn.

def grounded_agent(query, history=None):
    history = history or []
    resp = client.models.generate_content(
        model="gemini-3-pro",
        contents=history + [query],
        tools=[types.Tool(google_search=types.GoogleSearch())],
    )
    meta = resp.candidates[0].grounding_metadata
    sources = [c.web.uri for c in meta.grounding_chunks if c.web]
    history.append(query)
    history.append(resp.text)
    return resp.text, sources, history

Use it across turns:

text, sources, hist = grounded_agent("Compare AWS Nitro and GCP Confidential VMs.")
text2, sources2, hist = grounded_agent("Which supports SGX enclaves?", hist)

The second turn benefits from prior context and still triggers fresh searches when needed. Gemini 3 search grounding operates per request; the model may issue new queries even if the topic overlaps with a previous turn.

For production, add a max-turn guard and truncate history to the last N tokens. Grounding metadata bloats context if you feed it back blindly—strip it before appending model output to history. Streaming works, but grounding_metadata is only available on the final aggregated response, so don’t expect incremental citations.

Step 4: Parse and persist citations

Engineers often discard grounding_metadata and later get bitten by compliance audits. Extract the chunks and map them to rendered text segments.

meta = resp.candidates[0].grounding_metadata
for support in meta.grounding_supports:
    segment = resp.text[support.segment.start_index:support.segment.end_index]
    linked = [meta.grounding_chunks[i].web.uri for i in support.grounding_chunk_indices]
    print(f"'{segment}' -> {linked}")

This gives you a citation graph: every substring of the answer traces to one or more URLs. Store both the answer and the graph in your database. If you surface answers in a UI, render superscript links using the end_index offsets.

Note that grounding_chunks may include web and retrieved_context types. Only web carries a public URI suitable for display. Internal retrieval chunks appear when you also attach a Vector Store tool; ignore them for external citations.

Step 5: Route through a gateway for resilience

If you front your inference with n4n.ai, its OpenAI-compatible endpoint addresses 240+ models and automatically falls back when a provider is rate-limited or degraded. You keep the same gemini 3 search grounding behavior by passing the provider-native tool via an extension field.

from openai import OpenAI

gw = OpenAI(base_url="https://api.n4n.ai/v1", api_key="n4n_key")
resp = gw.chat.completions.create(
    model="gemini-3-pro",
    messages=[{"role": "user", "content": "Latest CVE in OpenSSL?"}],
    extra_body={"tools": [{"google_search": {}}]},
)

The gateway forwards cache-control hints and honors your routing directives, so you can pin to Gemini 3 or let it shift to an equivalent model during outages. Per-token metering shows up in one bill. This matters when you run hundreds of grounded queries per minute and a single provider hiccup shouldn’t break the agent.

Step 6: Verify the agent end to end

Verification is not optional. Write a smoke test that asserts grounding occurred and the answer is non-empty.

def test_grounding():
    text, sources, _ = grounded_agent("Who won the 2024 Nobel Prize in Physics?")
    assert text.strip(), "Empty response"
    assert sources, "Gemini 3 search grounding returned no sources"
    assert any("hinton" in text.lower() or "hopfield" in text.lower() for _ in [0])

Run it in CI against a staging key with low quota. Beyond unit tests, log web_search_queries to confirm the model actually searched. If you see zero queries on factual prompts, your prompt is too vague or the tool was dropped by a proxy.

For latency, measure p95 of the full round trip including search. Grounding adds a real web fetch; budget 2–5x baseline generation time. Cache repeated queries at the agent layer using the cache_control hint if your gateway supports it.

Operational notes

  • Rate limits: Google caps search-grounded calls per minute separately from pure generation. Backoff on 429 with retry-after.
  • Cost: You pay per token for input, output, and search attribution. Strip grounding metadata from history to avoid replay charges.
  • Safety: Grounded answers can still be wrong. Show the source links; don’t hide them behind a “trust the model” UI.
  • Model drift: Gemini 3 may change search ranking. Pin model version (gemini-3-pro-2025-xx) in production.

Building agents on gemini 3 search grounding is straightforward if you treat the search tool as a normal function call and persist the metadata. The code above is runnable today against the Gemini API; adapt the gateway snippet only if you need multi-provider failover.

Tagsgemini-3google-searchgroundingai-agents

Written by

n4n Team

The team building n4n — a single OpenAI-compatible API in front of 240+ models, with automatic fallback, load balancing and pay-per-token metering.

More from n4n Team →

All gemini 3 multi-modal agents posts →