+200 XP

Function calling und structured outputs

# Function calling und structured outputs

Wenn Sie Gemini eine Funktion geben, die es aufrufen kann, wird aus dem Textgenerator etwas, das Ihren Kalender lesen, Ihre Pricing-API ansprechen oder Ihre Datenbank abfragen kann. Und wenn sauberes JSON zurückkommt, kann Ihr Code das Ergebnis ohne Regex-Bastelei tatsächlich verwenden. Diese beiden Fähigkeiten sind das Rückgrat jeder ernsthaften Gemini-Integration, und sie funktionieren unter der Haube sehr unterschiedlich. Schauen wir uns beide genau an.

Function calling ist eine Verhandlung, keine Ausführung

Der wichtigste Denkwechsel: Gemini führt Ihre Funktion nie aus. Es entscheidet nur, *dass* eine Funktion aufgerufen werden soll und *mit welchen Argumenten*. Sie führen den Code aus. Sie senden das Ergebnis zurück. Gemini macht weiter.

Dieser Round Trip ist der Tool-Calling-Loop:

1. Sie senden einen Prompt plus eine Liste von Funktions-*Deklarationen* (Name, Beschreibung, Parameter).

2. Gemini antwortet entweder mit normalem Text oder mit einem functionCall-Part, der die gewählte Funktion und die Argumente enthält.

3. Ihr Code führt diese Funktion wirklich aus.

4. Sie senden das Ergebnis als functionResponse zurück.

5. Gemini nutzt das Ergebnis für die endgültige Antwort (oder ruft eine weitere Funktion auf).

Das Modell betreibt strukturierte Intent-Erkennung. Ihre Aufgabe ist es, die eigentliche Ausführung zu verdrahten und den State immer wieder in die Konversation zurückzugeben.

Eine Funktion deklarieren

Eine Funktionsdeklaration ist ein Schema. Gemini liest die description-Felder, um zu entscheiden, wann und wie es die Funktion aufruft. Behandeln Sie diese Felder also als Prompt Engineering, nicht als Dokumentation. Vage Beschreibungen führen zu falschen Aufrufen.

python
from google import genai
from google.genai import types

client = genai.Client()

get_weather = types.FunctionDeclaration(
    name="get_weather",
    description="Get the current temperature for a city. Use only when the user asks about weather.",
    parameters={
        "type": "object",
        "properties": {
            "city": {"type": "string", "description": "City name, e.g. 'Lisbon'"},
            "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
        },
        "required": ["city"],
    },
)

weather_tool = types.Tool(function_declarations=[get_weather])

Das nutzt das vereinheitlichte Google Gen AI SDK, die aktuell empfohlene Python-Bibliothek. Dasselbe SDK spricht sowohl die Gemini API (über AI-Studio-Keys) als auch Vertex AI an, man ändert nur die Client-Konfiguration. Sie schreiben den Loop also einmal.

Den Loop ausführen

Hier der komplette Round Trip mit einem Flash-Modell. Beachten Sie: Das *Funktionsergebnis* geht als neuer Content-Part zurück in die Konversation, nicht als reiner Text.

python
def get_weather_impl(city, unit="celsius"):
    return {"city": city, "temp": 19, "unit": unit}  # echter API-Aufruf gehört hierher

config = types.GenerateContentConfig(tools=[weather_tool])
contents = ["What's the weather in Lisbon right now?"]

resp = client.models.generate_content(
    model="gemini-2.5-flash", contents=contents, config=config
)

part = resp.candidates[0].content.parts[0]
if part.function_call:
    call = part.function_call
    result = get_weather_impl(**call.args)

    contents.append(resp.candidates[0].content)  # der Aufruf des Modells
    contents.append(types.Content(role="user", parts=[
        types.Part.from_function_response(name=call.name, response=result)
    ]))

    final = client.models.generate_content(
        model="gemini-2.5-flash", contents=contents, config=config
    )
    print(final.text)  # "It's 19°C in Lisbon right now."

Entscheidend sind die beiden contents.append-Aufrufe. Sie spielen den Function Call des Modells zurück in die History und hängen dann das Ergebnis an. Lassen Sie das erste Append weg, verliert Gemini den Bezug zu dem, was es angefragt hat.

Gemini mehrere Funktionen aufrufen lassen

Geben Sie ihm mehr als eine Deklaration, und Gemini wählt die passende aus oder fragt mehrere an. Parallel function calling heißt, dass eine einzelne Antwort mehrere functionCall-Parts enthält (z. B. „vergleiche das Wetter in Lissabon und Madrid“ ergibt zwei Aufrufe gleichzeitig). Iterieren Sie über resp.candidates[0].content.parts, führen Sie jeden aus und hängen Sie alle Antworten gemeinsam an, bevor der nächste Turn beginnt.

Sie können das Verhalten auch mit tool_config einschränken. Setzen Sie den Function-Calling-Modus auf ANY, muss Gemini eine Funktion aufrufen statt in Prosa zu antworten. Das ist nützlich, wenn ein Tool-Aufruf das einzig akzeptable Ergebnis ist:

python
config = types.GenerateContentConfig(
    tools=[weather_tool],
    tool_config=types.ToolConfig(
        function_calling_config=types.FunctionCallingConfig(mode="ANY")
    ),
)

Die Modi sind AUTO (Standard, Modell entscheidet), ANY (muss etwas aufrufen) und NONE (nie aufrufen). Nutzen Sie ANY mit einer allowed_function_names-Liste, um das Modell auf eine bestimmte Teilmenge zu begrenzen.

Structured outputs: wenn Sie Daten wollen, kein Tool

Function calling ist zum *Handeln*. Structured output ist zum *Extrahieren*. Wenn Sie nur wollen, dass Gemini sauberes JSON zurückgibt, das Sie parsen können, täuschen Sie das nicht mit einem Tool vor. Nutzen Sie das Response-Schema-Feature, das das Decoding des Modells so einschränkt, dass der Output garantiert zu Ihrem Schema passt.

Das ist constrained decoding: Gemini darf zur Generierungszeit nur Tokens produzieren, die den Output gegenüber Ihrem Schema valide halten. Sie hoffen nicht auf JSON. Sie bekommen es.

python
from pydantic import BaseModel

class Invoice(BaseModel):
    vendor: str
    total: float
    currency: str
    line_items: list[str]

resp = client.models.generate_content(
    model="gemini-2.5-flash",
    contents="Extract the invoice details from this email: ...",
    config=types.GenerateContentConfig(
        response_mime_type="application/json",
        response_schema=Invoice,
    ),
)

invoice = Invoice.model_validate_json(resp.text)
print(invoice.total, invoice.currency)

Ein Pydantic-Modell als response_schema zu übergeben, ist der idiomatische Weg: Das SDK wandelt es in ein Schema um, Gemini hält sich daran, und Sie validieren direkt zurück in typisierte Objekte. Kein Prompt, der um „gib nur JSON zurück“ bittet. Keine überflüssigen Markdown-Fences, die man entfernen muss.

Wenn das Schema dynamisch ist

Wird Ihre Struktur erst zur Laufzeit festgelegt, übergeben Sie ein rohes Schema-Dict statt einer Pydantic-Klasse. Nutzen Sie propertyOrdering, um die Feldreihenfolge festzulegen, denn die Reihenfolge kann bei komplexen Extraktionen die Qualität beeinflussen:

python
schema = {
    "type": "object",
    "properties": {
        "sentiment": {"type": "string", "enum": ["positive", "neutral", "negative"]},
        "topics": {"type": "array", "items": {"type": "string"}},
    },
    "required": ["sentiment", "topics"],
    "propertyOrdering": ["sentiment", "topics"],
}

Speziell für Klassifikation gibt es außerdem response_mime_type="text/x.enum" mit einem Enum-Schema, das die Antwort auf genau eines Ihrer Labels und sonst nichts festnagelt. Das ist der saubersten Weg für Single-Label-Klassifikation.

Die Wahl zwischen beiden

Sie überlappen sich, entscheiden Sie also bewusst:

  • Structured output, wenn Sie die gesamte Interaktion kontrollieren und aus einem Aufruf nur geparste Daten zurückbrauchen. Schneller, einfacher, garantierte Struktur.
  • Function calling, wenn Gemini *über sich hinaus* greifen muss: Live-Daten, Ihre APIs, Side Effects, mehrstufiges Reasoning, bei dem jeder Schritt von echten Ergebnissen abhängt.

Ein verbreitetes Muster kombiniert beides: Ein Function Call holt echte Daten, und ein abschließender Generierungsschritt gibt sie über ein Response Schema zurück, damit Ihr nachgelagerter Code typisiert bleibt.

Bauen Sie nicht selbst, was die Plattform liefert

Manche „Funktionen“ existieren schon als Built-in-Tools. Grounding mit Google Search, Code Execution und URL Context sind native Tools, die Sie in der Config aktivieren statt selbst zu implementieren. Wenn Sie aktuelle Fakten brauchen, schalten Sie Search Grounding ein, anstatt eine eigene Suchfunktion zu schreiben:

python
config = types.GenerateContentConfig(
    tools=[types.Tool(google_search=types.GoogleSearch())]
)

Einige Built-in-Tools lassen sich in einem einzigen Aufruf nicht frei mit eigenen Funktionsdeklarationen mischen, und die Regeln unterscheiden sich zwischen Gemini API und Vertex AI. Prüfen Sie also das benötigte Tool, bevor Sie kombinieren.

Function Calling with the Gemini API

Watch on YouTube

Wissenscheck

1. Was ist die wichtigste konzeptionelle Unterscheidung dabei, wie Gemini function calling handhabt?

2. Warum sollten die `description`-Felder einer Funktion laut Lektion als Prompt Engineering und nicht als Dokumentation behandelt werden?

3. Was sendet Ihr Code im Tool-Calling-Loop an Gemini zurück, nachdem die gewählte Funktion tatsächlich ausgeführt wurde?

MEHRFACHAUSWAHL

4. Wählen Sie ALLE korrekten Aussagen zum Tool-Calling-Loop und zu Funktionsdeklarationen.

Wählen Sie alle richtigen Antworten aus.

MEHRFACHAUSWAHL

5. Wählen Sie ALLE korrekten Aussagen zu Nutzen und Design von function calling und structured outputs, wie in der Lektion beschrieben.

Wählen Sie alle richtigen Antworten aus.

Im AI Studio prototypen, dann richtig skalieren

Bevor Sie irgendeinen Loop schreiben, bauen Sie die Funktionsdeklaration visuell im Google AI Studio. Sie können Tools definieren, zusehen, wie Gemini functionCall-Parts ausgibt, und funktionierenden Code in Ihrer Sprache kopieren. Das ist der schnellste Weg, diese so wichtigen description-Strings zu justieren.

Beim Schritt in die Produktion geht es um die Frage, *wo* der Loop läuft:

  • Gemini API (ai.google.dev) für App-Backends und schnelle Services. Der SDK-Code oben ist alles, was Sie brauchen.
  • Vertex AI, wenn Sie Enterprise-Kontrollen brauchen: IAM, VPC, Data Residency und managed Deployment. Gleiches SDK, andere Client-Initialisierung.
  • Agent Development Kit (ADK), wenn aus einem Modell mit einer Handvoll Tools ein echter Agent mit Planning, Memory und vielen Tools wird. ADK gibt Ihnen Loop, State und Tool-Orchestrierung als Framework, sodass Sie die Append-the-Response-Plumbing nicht mehr von Hand schreiben. Siehe die ADK-Docs für den Agent-first-Ansatz.

Für interne Workspace-Automatisierung brauchen Sie davon nicht immer etwas. Apps Script kann Gemini aufrufen und direkt auf Docs, Sheets oder Gmail wirken, was oft der kürzeste Weg zu einem funktionierenden Tool innerhalb von Google Workspace ist.

Hart erkaufte Details, die Ihnen Stunden sparen

Beschreibungen sind Prompts. Geminis Trefferquote beim Auswählen und Füllen von Funktionen hängt fast vollständig an der Qualität Ihrer description-Felder und Parameter-Dokumentation. Schreiben Sie aus, *wann* eine Funktion zu nutzen ist und *wann nicht*.

Validieren Sie jedes Argument. Gemini füllt Argumente aus einem Schema, kann aber trotzdem einen plausibel-aber-falschen Wert halluzinieren, besonders bei IDs oder Enums, an die es sich nur halb erinnert. Behandeln Sie Funktionsargumente wie nicht vertrauenswürdigen User-Input. Validieren Sie, bevor Sie etwas mit Side Effects ausführen.

Nutzen Sie `required` und `enum` konsequent. Jede Einschränkung, die Sie ins Schema legen, ist eine Einschränkung, die das Modell erfüllen muss. Enums beseitigen ganze Klassen von Müllwerten. Required-Felder verhindern halb gefüllte Aufrufe.

Wählen Sie die Stufe pro Aufgabe. Flash bewältigt den Großteil von Tool-Routing und Extraktion mit niedriger Latenz und niedrigen Kosten. Greifen Sie zu Pro, wenn die Entscheidung, *welches* Tool aufzurufen ist, echtes Reasoning über einen langen Kontext erfordert, oder wenn die Extraktion von subtiler Logik über mehrere Dokumente abhängt.

Geben Sie Funktionsergebnisse immer zurück. Der häufigste Bug ist, den Function Call des Modells vor der Antwort nicht anzuhängen. Ohne das ist die Konversationshistorie inkonsistent, und die endgültige Antwort driftet.

Zentrale Erkenntnisse

  • Sie führen aus, Gemini entscheidet. Der Tool-Calling-Loop lautet: Funktionen deklarieren, functionCall empfangen, selbst ausführen, sowohl den Aufruf als auch die functionResponse anhängen, dann die endgültige Antwort generieren.
  • Nutzen Sie `response_schema` mit einem Pydantic-Modell, um über constrained decoding garantiert valides JSON zu bekommen. Hören Sie auf, nach JSON zu prompten, und hören Sie auf, Markdown-Fences zu entfernen.
  • Handeln vs. extrahieren: Function calling greift für Live-Daten und Side Effects über das Modell hinaus; structured output parst Daten aus einem einzigen Aufruf. Kombinieren Sie beides, wenn Sie echte Daten holen und sie dann typisiert zurückgeben.
  • Investieren Sie in `description`-Felder, Enums und `required`. Tool-Genauigkeit ist überwiegend Schema-Qualität, und jede Einschränkung muss das Modell erfüllen.
  • Prototypen im AI Studio, dann weiterziehen zur Gemini API, zu Vertex AI oder zu ADK, je nachdem, ob Sie Skalierung, Enterprise-Kontrollen oder volle Agent-Orchestrierung brauchen. Und validieren Sie Funktionsargumente immer, bevor Sie darauf handeln.