GEMINI LABJP
NANOLITE — Nano Banana 2 Lite is here: Google's fastest and most cost-efficient Gemini Image model, made for running lightweight image generation cheaplyOMNIFLASH — Gemini Omni Flash is in public preview, a natively multimodal model that lets enterprises and developers build custom, dynamic video workflowsAGENTS — Managed Agents expand with background: true for async server-side runs and polling, remote MCP server integration, and refreshing credentials across interactionsMEMORY — The Memory Bank IngestEvents API is generally available, decoupling event ingestion from memory generation so you can stream content continuouslyTHROUGHPUT — Provisioned Throughput now lets you submit up to seven pending orders for the same model and regionDEPRECATE — Image generation models shut down on August 17, and the Grok 4.1 family on the Gemini Enterprise Agent Platform on August 20NANOLITE — Nano Banana 2 Lite is here: Google's fastest and most cost-efficient Gemini Image model, made for running lightweight image generation cheaplyOMNIFLASH — Gemini Omni Flash is in public preview, a natively multimodal model that lets enterprises and developers build custom, dynamic video workflowsAGENTS — Managed Agents expand with background: true for async server-side runs and polling, remote MCP server integration, and refreshing credentials across interactionsMEMORY — The Memory Bank IngestEvents API is generally available, decoupling event ingestion from memory generation so you can stream content continuouslyTHROUGHPUT — Provisioned Throughput now lets you submit up to seven pending orders for the same model and regionDEPRECATE — Image generation models shut down on August 17, and the Grok 4.1 family on the Gemini Enterprise Agent Platform on August 20
Articles/Dev Tools
Dev Tools/2026-03-11Intermediate

Gemini External Tool Integration — Grounding and Function Calling in Practice

How to connect Gemini to external services and your own data, covering both the in-app integrations and the API tools parameter: Google Search grounding, the full Function Calling round-trip, and the latency and cost trade-offs to plan for.

Gemini75Function Calling16IntegrationGrounding4Tools

I asked for the latest, and got a confident, stale answer

While drafting an app announcement with Gemini, I asked it to "account for the recent release status," but it answered based on how things stood months earlier. That makes sense: a model answers from what it learned up to its training cutoff.

The way past that wall — "doesn't know the latest" and "can't see my data" — is external tool integration. Gemini offers two paths: the integrations you toggle in the app, and the tools parameter you call from the API. Knowing both lets you pick the right one for the job.

In-app integrations

In the Gemini app (web and mobile), you can toggle connections to Google services from the settings screen. They are designed to fire automatically only when a question calls for them.

Google Search

Activates for news, current events, and real-time figures, folding search results into the answer.

  • "What's the weather in Tokyo today?"
  • "Summarize recent AI news in three lines"
  • "When was company X's latest earnings report?"

Google Maps

Searches places, directions, and store or hotel details.

  • "How do I get from Shibuya Station to Tokyo Tower?"
  • "Highly-rated Italian restaurants nearby"

YouTube

Searches videos and suggests related content.

  • "Find Python machine learning tutorial videos"

Google Flights & Hotels

Searches and compares flights and accommodations.

  • "Cheapest flights from Tokyo to Paris next month"

Each integration toggles independently. Turning off the ones you don't need avoids unintended external calls.

From the API: search grounding

To do the same thing from code, you use the tools parameter. Start with search grounding: the model runs a Google Search only when it judges one is needed, then builds the answer on top of those results.

from google import genai
from google.genai import types
 
client = genai.Client(api_key="YOUR_API_KEY")
 
response = client.models.generate_content(
    model="gemini-3.5-flash",
    contents="What's the current weather in Tokyo? Cite your sources.",
    config=types.GenerateContentConfig(
        tools=[types.Tool(google_search=types.GoogleSearch())],
    ),
)
 
print(response.text)
 
# Pull out the grounding sources
meta = response.candidates[0].grounding_metadata
if meta and meta.grounding_chunks:
    for chunk in meta.grounding_chunks:
        print("Source:", chunk.web.uri)
else:
    print("(No search was used for this request)")

The model searches only when it decides outside information is required. A weather question returns grounding_chunks; a question answerable from general knowledge skips search and leaves grounding_metadata empty. Always branch for the no-grounding case — that is the trick to keeping this stable in production. Code that never assumes grounding exists won't crash on the quieter requests.

From the API: the Function Calling round-trip

Search grounding is executed for you on Google's side. To reach your own database or internal API, you use Function Calling. Here is the step most introductions skip: once the model says it wants to call a function, who actually runs it? Your code does.

The flow has five stages: (1) declare the function, (2) the model requests a call, (3) you execute the function, (4) you return the result to the model, (5) the model produces the final answer.

from google import genai
from google.genai import types
 
client = genai.Client(api_key="YOUR_API_KEY")
 
# (1) Declare the function
get_weather = types.FunctionDeclaration(
    name="get_weather",
    description="Return the current weather for a given city",
    parameters={
        "type": "object",
        "properties": {
            "city": {"type": "string", "description": "City name"},
        },
        "required": ["city"],
    },
)
tools = [types.Tool(function_declarations=[get_weather])]
 
# The local implementation that actually runs (normally it hits an API)
def run_get_weather(city: str) -> dict:
    fake_db = {"Tokyo": "Clear, 24C", "Osaka": "Cloudy, 22C"}
    return {"city": city, "weather": fake_db.get(city, "no data")}
 
contents = [
    types.Content(role="user", parts=[types.Part(text="What's the weather in Tokyo?")]),
]
 
# (2) First call to the model
resp = client.models.generate_content(
    model="gemini-3.5-flash",
    contents=contents,
    config=types.GenerateContentConfig(tools=tools),
)
 
part = resp.candidates[0].content.parts[0]
if part.function_call:
    call = part.function_call
    # (3) Run the function on our side
    result = run_get_weather(**dict(call.args))
 
    # (4) Append both the model's call and our result to the history
    contents.append(resp.candidates[0].content)
    contents.append(
        types.Content(
            role="tool",
            parts=[types.Part(
                function_response=types.FunctionResponse(
                    name=call.name, response=result,
                )
            )],
        )
    )
 
    # (5) Get the final answer grounded in the result
    final = client.models.generate_content(
        model="gemini-3.5-flash",
        contents=contents,
        config=types.GenerateContentConfig(tools=tools),
    )
    print(final.text)

The key is step (4): append both the model's call (function_call) and your execution result (function_response) to the history before asking for the final answer. Return only the result, and the model loses track of what was asked and what came back, producing an off-target reply. I once spent half a day on a bug caused by appending just one of the two.

Four things I watch in production

Inserting an external tool adds concerns that plain text generation never had. Here is what I check every time while running these in my own indie projects.

  • Latency: tool calls involve a network round-trip, so responses slow down. On user-facing screens, an interim "searching…" indicator changes the perceived speed dramatically.
  • Cost: grounding searches and multiple round-trips each add charges. Estimating on the free tier before designing your production rate limits keeps things safe.
  • Citations: the source URLs in grounding_chunks are your material for showing readers that an answer is trustworthy. If you display them, account for dead links.
  • Preventing stray calls: pass only the tools you actually need. Declaring too many raises the odds the model picks an unintended function.

Choosing between them in indie development

For drafts where factual freshness matters — app announcements, release notes — I reach for search grounding. When the answer depends on data that lives only on my side, such as internal metrics or inventory, I use Function Calling. Feeding in app revenue figures (an AdMob report, say) for summarization is another job for the latter.

The in-app integrations are best for getting a feel for the behavior by hand. The API tools come into their own once you fold that behavior into automation.

Which model should call the tools

When you build tool integration, the model you pick shapes the outcome too. In my own setup, I lean on gemini-3.5-flash for the lighter round-trips — search grounding or a single Function Calling hop — where speed matters, and only reach for a higher-tier model when I want to chain several tools and have it reason step by step.

Flash models respond quickly and stay cheaper, which suits features that run in sync with a user's action. For work that keeps no one waiting — a nightly batch, say — where you want precision in picking the right tool and assembling its arguments, switching up is worth it. Build on Flash first; if you see wrong-function picks or dropped arguments, move up. That order wastes the least effort.

One more thing: calling the API without naming a model uses the default, and that default can shift with updates. In automation, pin model explicitly so behavior doesn't change out from under you one day.

Your next step

With your own Gemini API key, run the search-grounding snippet above as-is, and try one question that returns grounding_chunks and one that doesn't. Experiencing the empty case first makes the design decisions far easier when you wire up the Function Calling round-trip.

Thank you for reading. I hope it gives you a solid foothold as you start building.

Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Dev Tools2026-06-24
Folding a Local Gemma 4 into Daily Work — Practical Notes on the Ollama API and Response Speed
Taking a local Gemma 4 you can now run interactively and folding it into real work: how to hit Ollama's local API from a script, tricks to improve perceived response speed, and a two-tier fallback that automatically routes to the cloud Gemini API — code included.
Dev Tools2026-06-24
Running Gemma 4 Locally on Windows — A Hands-On LLM in Two Commands with Ollama
How to run Google's lightweight open model Gemma 4 locally on a Windows laptop. With Ollama, you go from install to running in effectively two commands. Plus how to split work between the cloud Gemini API and a local Gemma.
Dev Tools2026-06-21
Finding Every Reference to the Image Preview Models Before They Stop on June 25
gemini-3.1-flash-image-preview and gemini-3-pro-image-preview stop on June 25. Here is a dependency audit for surfacing references buried in rarely-run branches and batches before the cutoff.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →