ANTIGRAVITY LABJP
Articles/App Development
App Development/2026-04-20Intermediate

Mastering Gemini API Function Calling with Python in Antigravity IDE

A practical guide to implementing Gemini API Function Calling with Python in Antigravity IDE. Includes working code examples for multi-tool setups, error handling, and debugging tips.

python26gemini-api7function-calling5antigravity434google-ai

If you've gotten the Gemini API quickstart running and are now wondering "what do I actually build with this?", Function Calling is probably the next concept that will unlock real-world use cases.

Text generation is great. Streaming works. But practical applications almost always need AI to interact with the outside world — look up current data, perform calculations, or call a third-party API. That's where Function Calling comes in.

What Is Function Calling and Why Does It Matter

LLMs are powerful at language tasks, but they can't tell you the current time accurately or retrieve live stock prices. Ask Gemini "What's the weather in Tokyo right now?" and it will generate a plausible-sounding answer — not a real one.

Function Calling bridges that gap. When the model decides it needs to call a specific function, instead of hallucinating the answer, it returns a structured JSON object with the function name and arguments. Your app executes the function, returns the result to the model, and the model generates a final answer grounded in real data.

The division of responsibility:

  • Your app: defines the functions and actually runs them
  • The model: decides when and which function to call, and generates the arguments

This separation is what makes Function Calling so useful and composable.

Setting Up in Antigravity

Open Antigravity and create the project from the integrated terminal:

# Create project folder
mkdir gemini-function-calling
cd gemini-function-calling
 
# Set up virtual environment
python -m venv .venv
source .venv/bin/activate  # Windows: .venv\Scripts\activate
 
# Install dependencies
pip install google-generativeai python-dotenv

Antigravity's Python extension should auto-detect the virtual environment interpreter. If it doesn't, press Ctrl+Shift+PPython: Select Interpreter → choose .venv/bin/python.

Add your API key to a .env file:

GEMINI_API_KEY=YOUR_GEMINI_API_KEY

A Minimal Function Calling Example

The fastest way to understand the mechanics is a simple "get current time" function:

# basic_function_calling.py
import os
import json
import datetime
import google.generativeai as genai
from dotenv import load_dotenv
 
load_dotenv()
genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
 
# ① Define the actual function
def get_current_time(timezone: str = "Asia/Tokyo") -> dict:
    """Returns the current date and time."""
    now = datetime.datetime.now()
    return {
        "time": now.strftime("%Y-%m-%d %H:%M:%S"),
        "timezone": timezone
    }
 
# ② Define the tool schema for Gemini (JSON Schema format)
tools = [
    {
        "function_declarations": [
            {
                "name": "get_current_time",
                "description": "Get the current date and time",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "timezone": {
                            "type": "string",
                            "description": "Timezone string (e.g., Asia/Tokyo, UTC)"
                        }
                    },
                    "required": []
                }
            }
        ]
    }
]
 
# ③ Initialize model and start chat
model = genai.GenerativeModel("gemini-2.0-flash", tools=tools)
chat = model.start_chat()
 
# ④ Send user message
response = chat.send_message("What time is it right now?")
 
# ⑤ Check if the model wants to call a function
for part in response.parts:
    if hasattr(part, "function_call"):
        func_call = part.function_call
        print(f"Model requested function: {func_call.name}")
        print(f"Arguments: {dict(func_call.args)}")
        
        # ⑥ Execute the function
        result = get_current_time(**dict(func_call.args))
        
        # ⑦ Return the result to the model
        final_response = chat.send_message(
            genai.protos.Part(
                function_response=genai.protos.FunctionResponse(
                    name=func_call.name,
                    response={"result": result}
                )
            )
        )
        print(f"\nAI response: {final_response.text}")

Expected output:

Model requested function: get_current_time
Arguments: {}

AI response: The current time is 2026-04-20 09:00:00 (Asia/Tokyo).

Step ⑤ is the key insight: the model is not executing anything. It's telling your app "please run this function with these arguments." Your app runs the function and reports back. The model then uses that real data to formulate its answer.

Real-World Example: Multiple Tools

Most real applications define several functions. Here's a multi-tool setup with a calculator and unit converter:

# multi_tool_example.py
import os
import google.generativeai as genai
from dotenv import load_dotenv
 
load_dotenv()
genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
 
# Tool implementations
def calculate(expression: str) -> dict:
    """Evaluate a math expression (safe characters only)."""
    allowed_chars = set("0123456789+-*/()., ")
    if not all(c in allowed_chars for c in expression):
        return {"error": "Expression contains invalid characters", "result": None}
    try:
        result = eval(expression)  # Use a safer eval in production
        return {"result": result, "expression": expression}
    except Exception as e:
        return {"error": str(e), "result": None}
 
def convert_units(value: float, from_unit: str, to_unit: str) -> dict:
    """Simple unit conversion (km↔miles, kg↔lbs)."""
    conversions = {
        ("km", "miles"): lambda v: v * 0.621371,
        ("miles", "km"): lambda v: v * 1.60934,
        ("kg", "lbs"): lambda v: v * 2.20462,
        ("lbs", "kg"): lambda v: v / 2.20462,
    }
    key = (from_unit.lower(), to_unit.lower())
    if key in conversions:
        result = conversions[key](value)
        return {"result": round(result, 4), "from": f"{value} {from_unit}", "to": f"{result:.4f} {to_unit}"}
    return {"error": f"Conversion from {from_unit} to {to_unit} is not supported"}
 
# Map tool names to functions
TOOL_FUNCTIONS = {
    "calculate": calculate,
    "convert_units": convert_units,
}
 
tools = [
    {
        "function_declarations": [
            {
                "name": "calculate",
                "description": "Evaluate a mathematical expression",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "expression": {"type": "string", "description": "Math expression to evaluate (e.g., 2 + 3 * 4)"}
                    },
                    "required": ["expression"]
                }
            },
            {
                "name": "convert_units",
                "description": "Convert between units (km↔miles, kg↔lbs)",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "value": {"type": "number", "description": "The value to convert"},
                        "from_unit": {"type": "string", "description": "Source unit"},
                        "to_unit": {"type": "string", "description": "Target unit"}
                    },
                    "required": ["value", "from_unit", "to_unit"]
                }
            }
        ]
    }
]
 
def chat_with_tools(user_message: str) -> str:
    """General-purpose chat with tools — handles multi-step function calls."""
    model = genai.GenerativeModel("gemini-2.0-flash", tools=tools)
    chat = model.start_chat()
    
    response = chat.send_message(user_message)
    
    # Loop to handle multiple rounds of function calls
    max_iterations = 5
    for _ in range(max_iterations):
        func_calls = [p for p in response.parts if hasattr(p, "function_call")]
        if not func_calls:
            break  # No more function calls — we have the final answer
        
        # Execute all requested functions and return results
        function_responses = []
        for part in func_calls:
            fc = part.function_call
            func = TOOL_FUNCTIONS.get(fc.name)
            if func:
                result = func(**dict(fc.args))
            else:
                result = {"error": f"Unknown function: {fc.name}"}
            
            function_responses.append(
                genai.protos.Part(
                    function_response=genai.protos.FunctionResponse(
                        name=fc.name,
                        response={"result": result}
                    )
                )
            )
        
        response = chat.send_message(function_responses)
    
    return response.text
 
# Test it
print(chat_with_tools("Calculate 42 * 1.08, then convert that result from km to miles"))
# Expected: calculates 45.36, then converts to ~28.18 miles

The max_iterations loop is critical. Gemini may request multiple function calls in sequence — calculate first, then convert. Without a loop and a cap, you risk running indefinitely if something goes wrong. In production, always set a reasonable upper bound.

Debugging Function Calling in Antigravity

The most common frustration is "why isn't the function being called?" Antigravity's debug panel helps, but first add this inspection utility to your code:

def debug_response(response):
    """Print the internal structure of a Gemini response for debugging."""
    print("--- Response structure ---")
    print(f"Number of candidates: {len(response.candidates)}")
    for i, candidate in enumerate(response.candidates):
        print(f"Candidate {i}: finish_reason={candidate.finish_reason}")
        for j, part in enumerate(candidate.content.parts):
            if hasattr(part, "text"):
                print(f"  Part {j}: text = {part.text[:100]}")
            elif hasattr(part, "function_call"):
                print(f"  Part {j}: function_call = {part.function_call.name}({dict(part.function_call.args)})")

A finish_reason of STOP means normal completion. MAX_TOKENS means you've hit the token limit. If functions aren't being called when you expect them to be, the most likely culprit is a vague description in your tool schema. The more specific you are about when and why the function should be used, the more reliably the model will call it.

Where to Go From Here

Function Calling opens up a whole category of "AI + live data" applications that aren't possible with text generation alone. Take the code from this guide and connect it to an API you already use — a weather service, your own database, or a company REST API.

The Google GenAI SDK for Python documentation has additional examples, including tool_config for forcing the model to always call a specific tool — useful for keeping chatbot behavior consistent and predictable.

Share

Thank You for Reading

Antigravity 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

App Dev2026-05-03
Why `uv add transformers` Fails Inside Antigravity, and How to Actually Fix It
If `uv add transformers` errors out, or it succeeds but Antigravity's agent still throws ModuleNotFoundError, there are five distinct causes. Here is how to diagnose them in order.
App Dev2026-04-23
Keeping the Antigravity Python API Stable in Production — Retries, Timeouts, and Circuit Breakers That Actually Work
A deeply practical guide to keeping Python services built on the Google Gen AI SDK alive under real traffic. We cover retry, timeout, circuit breaker, rate limit, and cost budgeting patterns with runnable code from an Antigravity workflow.
Agents & Manager2026-04-19
Antigravity AI Agent Design: Multimodal Production Implementation Patterns
A complete guide to building multimodal AI agents with Google Antigravity (Gemma 4). Covers image+text integration, Function Calling, async batch processing, state management, error handling, and cost estimation — with production-ready code.
📚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 →