# Function calling met de Gemini API [[TOC]] ## Wat is function calling Function calling (ook wel "tool use") is het mechanisme waarmee een taalmodel externe functies kan aanroepen om informatie op te halen of acties uit te voeren die buiten zijn training vallen. Het model voert die functies niet zelf uit: het geeft aan welke functie met welke argumenten aangeroepen moet worden. Jouw code voert de functie uit en stuurt het resultaat terug. Dit maakt Gemini geschikt voor live data opvragen (weer, beurskoersen, databases), acties uitvoeren (e-mail versturen, agenda-items aanmaken), externe APIs aanroepen en bedrijfslogica integreren. :::info title="Welke SDK gebruik je?" De codevoorbeelden hieronder gebruiken de actuele **google-genai** SDK (`from google import genai`). De oudere `google.generativeai`-bibliotheek wordt niet meer aanbevolen voor nieuwe projecten. Installeren doe je met `pip install google-genai`. Als modelnaam gebruiken we `gemini-3.5-flash` (de aanbevolen Flash-variant in juni 2026); `gemini-2.5-flash` werkt ook nog en is goedkoper. ::: ## De function calling cyclus De cyclus bestaat uit zes stappen: 1. Definieer je tools als JSON Schema of als Python-functie. 2. Stuur de prompt plus tools naar Gemini. 3. Gemini geeft een `functionCall`-response terug. 4. Jouw code voert de bijbehorende functie uit. 5. Stuur het function-resultaat terug naar Gemini. 6. Gemini formuleert het eindantwoord voor de gebruiker. ## Client en functie definiëren Je maakt eerst een client aan. Die leest de API-sleutel standaard uit de omgevingsvariabele `GEMINI_API_KEY`. Een functie declareer je als JSON Schema met een duidelijke naam, beschrijving en parameters. ```python import os from google import genai from google.genai import types client = genai.Client(api_key=os.environ["GEMINI_API_KEY"]) get_weather = { "name": "get_weather", "description": "Haalt de huidige weersomstandigheden op voor een opgegeven stad.", "parameters": { "type": "object", "properties": { "city": { "type": "string", "description": "De naam van de stad, bijvoorbeeld Amsterdam", }, "unit": { "type": "string", "enum": ["celsius", "fahrenheit"], "description": "De temperatuureenheid", }, }, "required": ["city"], }, } tools = types.Tool(function_declarations=[get_weather]) config = types.GenerateContentConfig(tools=[tools]) ``` ## De cyclus handmatig uitvoeren Hieronder zie je de volledige heen-en-weer-cyclus. Je leest de `function_call` uit het antwoord, voert je eigen functie uit en stuurt het resultaat terug met `types.Part.from_function_response`. ```python contents = [ types.Content(role="user", parts=[types.Part(text="Wat is het weer in Amsterdam?")]) ] response = client.models.generate_content( model="gemini-3.5-flash", contents=contents, config=config, ) part = response.candidates[0].content.parts[0] if part.function_call: fc = part.function_call print(f"Functie: {fc.name}") print(f"Argumenten: {dict(fc.args)}") weather_data = {"temperature": 15, "condition": "bewolkt", "humidity": 75} function_response_part = types.Part.from_function_response( name=fc.name, response={"result": weather_data}, ) contents.append(response.candidates[0].content) contents.append(types.Content(role="user", parts=[function_response_part])) final_response = client.models.generate_content( model="gemini-3.5-flash", contents=contents, config=config, ) print(final_response.text) ``` :::warn title="Bewaar de volledige modelbeurt" Voeg altijd `response.candidates[0].content` (de beurt met de `functionCall`) terug toe aan `contents` voordat je het `function_response`-deel toevoegt. Bij Gemini 3-modellen bevat die beurt een interne thought-signature die nodig is om de aanroep correct te koppelen. Laat je hem weg, dan kan het model de functie-uitkomst niet goed verwerken. ::: ## Meerdere tools definiëren Je kunt meerdere functies in één tool-lijst aanbieden. Gemini kiest zelf welke (en hoeveel) het aanroept. ```python def get_product_price(product_id: str) -> dict: prices = {"P001": 29.99, "P002": 49.99, "P003": 19.99} return {"product_id": product_id, "price": prices.get(product_id, 0)} def check_stock(product_id: str) -> dict: stock = {"P001": 5, "P002": 0, "P003": 23} return {"product_id": product_id, "in_stock": stock.get(product_id, 0) > 0} product_tools = types.Tool(function_declarations=[ { "name": "get_product_price", "description": "Geeft de prijs van een product op basis van het product-ID.", "parameters": { "type": "object", "properties": { "product_id": {"type": "string", "description": "Het product-ID"} }, "required": ["product_id"], }, }, { "name": "check_stock", "description": "Controleert of een product op voorraad is.", "parameters": { "type": "object", "properties": { "product_id": {"type": "string", "description": "Het product-ID"} }, "required": ["product_id"], }, }, ]) ``` :::tip title="Schrijf scherpe beschrijvingen" Gemini gebruikt het `description`-veld van elke functie en parameter om te beslissen wanneer en hoe een functie aangeroepen wordt. Vage beschrijvingen leiden tot verkeerde of overbodige aanroepen. Beschrijf concreet wat de functie doet en geef bij elke parameter een voorbeeld, bijvoorbeeld een datumnotatie als `2026-07-29`. ::: ## Automatische functie-uitvoering Geef je gewone Python-functies door als tools (in plaats van JSON Schema), dan voert de SDK de aanroepen automatisch voor je uit en handelt de hele cyclus zelf af. De SDK leidt het schema af uit de type-hints en de docstring, dus schrijf die zorgvuldig. ```python def get_weather_impl(city: str, unit: str = "celsius") -> dict: """Haalt het huidige weer op voor een stad. Args: city: De naam van de stad, bijvoorbeeld Rotterdam. unit: De temperatuureenheid, celsius of fahrenheit. Returns: Een dict met temperatuur en conditie. """ return {"temperature": 15, "condition": "bewolkt", "city": city} config = types.GenerateContentConfig(tools=[get_weather_impl]) response = client.models.generate_content( model="gemini-3.5-flash", contents="Wat is het weer in Rotterdam en Utrecht?", config=config, ) print(response.text) ``` Wil je de automatische modus uitzetten en de cyclus zelf beheren, geef dan `automatic_function_calling=types.AutomaticFunctionCallingConfig(disable=True)` mee in de config. ## Tool-keuze afdwingen Met een `ToolConfig` stuur je af of het model wel of geen tool mag kiezen. Dit gebeurt via `function_calling_config`. ```python config = types.GenerateContentConfig( tools=[tools], tool_config=types.ToolConfig( function_calling_config=types.FunctionCallingConfig( mode="ANY", allowed_function_names=["get_weather"], ) ), ) ``` De beschikbare modi: - `AUTO`: het model beslist zelf of het een tool aanroept (standaard). - `ANY`: het model roept altijd een tool aan; met `allowed_function_names` beperk je de keuze. - `VALIDATED`: het model kiest tussen een geldige functie-aanroep of tekst (standaard bij sommige tool-combinaties). - `NONE`: het model roept nooit een tool aan. ## Praktijkvoorbeeld: orderstatus opvragen Een veelvoorkomend patroon is een supportbot die een orderstatus uit je eigen database haalt. Je definieert één functie, laat de SDK die automatisch uitvoeren, en valideert het ID voordat je de database raadpleegt. ```python def get_order_status(order_id: str) -> dict: """Geeft de status van een bestelling op basis van het order-ID. Args: order_id: Het order-ID in de vorm ORD-12345. """ if not order_id.startswith("ORD-"): return {"error": "Ongeldig order-ID. Verwacht formaat: ORD-12345."} fake_db = {"ORD-12345": "verzonden", "ORD-67890": "in behandeling"} return {"order_id": order_id, "status": fake_db.get(order_id, "niet gevonden")} config = types.GenerateContentConfig(tools=[get_order_status]) response = client.models.generate_content( model="gemini-3.5-flash", contents="Kun je de status van bestelling ORD-12345 opzoeken?", config=config, ) print(response.text) ``` Doordat de functie zelf het ID valideert en bij twijfel een nette foutmelding teruggeeft, blijft de bot voorspelbaar, ook als de gebruiker een onzinnig ID noemt. :::faq ### Kan Gemini meerdere functies tegelijk aanroepen? Ja. Gemini kan in één antwoord meerdere `functionCall`-parts teruggeven (parallel function calling). Voer alle aanroepen uit en stuur alle bijbehorende `function_response`-parts samen terug in de volgende beurt. ### Hoe voorkom ik dat Gemini een functie met onjuiste argumenten aanroept? Definieer parameter-types en beschrijvingen nauwkeurig en markeer verplichte velden met `required`. Valideer de argumenten daarnaast altijd in je eigen implementatie voordat je iets uitvoert, want het model kan ondanks het schema af en toe afwijken. ### Kan ik ook functies met bijwerkingen laten aanroepen, zoals schrijven of verwijderen? Ja, maar bouw een bevestigingsstap in voor destructieve acties. Laat Gemini de actie voorstellen, toon de gebruiker exact wat er gaat gebeuren, en voer pas uit na expliciete bevestiging. Gebruik desnoods de mode `NONE` zodra je in de bevestigingsfase zit. ### Wat als mijn functie een fout geeft? Stuur de fout terug als `function_response` met een `error`-veld in plaats van een resultaat. Gemini kan die fout dan verwerken, de gebruiker informeren of een alternatieve aanpak voorstellen. ### Werkt de oude google.generativeai code nog? Die oudere bibliotheek wordt niet meer aanbevolen voor nieuwe projecten. Stap over op de google-genai SDK (`from google import genai`). De belangrijkste verschillen: je werkt met een `client`, roept `client.models.generate_content` aan en geeft tools mee via `types.GenerateContentConfig`. ### Welk model kan ik het beste gebruiken voor function calling? Voor agentische taken en function calling is `gemini-3.5-flash` in juni 2026 een sterke en snelle keuze. Heb je minder zware taken of wil je kosten besparen, dan voldoet `gemini-2.5-flash` of `gemini-2.5-flash-lite` ook. De API-aanroepen zelf blijven identiek; alleen de modelnaam verschilt. :::