+200 XP

Gemini · Function calling und structured outputs

Wenn Sie Gemini eine Funktion zum Aufrufen geben, wird aus einem Textgenerator etwas, das Ihren Kalender lesen, Ihre Pricing-API ansprechen oder Ihre Datenbank abfragen kann. Wenn Sie sauberes JSON zurückbekommen, kann Ihr Code das Ergebnis ohne Regex-Hacks verwenden. Diese beiden Fähigkeiten bilden das Rückgrat jeder ernsthaften Gemini-Integration, und technisch funktionieren sie sehr unterschiedlich.

Function calling ist eine Verhandlung, keine Ausführung

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

Dieser Hin und Rückweg 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 tatsächlich aus.
  4. Sie senden das Ergebnis als functionResponse zurück.
  5. Gemini nutzt das Ergebnis, um die finale Antwort zu erzeugen (oder eine weitere Funktion aufzurufen).

Das Modell betreibt strukturierte Intent-Erkennung. Ihre Aufgabe ist es, die tatsächliche Ausführung anzubinden und den Zustand fortlaufend in die Konversation zurückzuspielen.

Eine Funktion deklarieren

Eine Funktionsdeklaration ist ein Schema. Gemini liest die description-Felder, um zu entscheiden, wann und wie die Funktion aufgerufen wird. 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])

Hier wird das einheitliche Google Gen AI SDK verwendet, die aktuell empfohlene Python-Bibliothek. Dasselbe SDK spricht sowohl die Gemini API (über AI-Studio-Keys) als auch Vertex AI an, indem Sie nur die Client-Konfiguration ändern. Den Loop schreiben Sie also einmal.

Den Loop ausführen

Hier der komplette Hin und Rückweg mit einem Flash-Modell. Modell-IDs ändern sich alle paar Monate. Halten Sie den Namen deshalb in einer Konstante und prüfen Sie auf der Modellseite die aktuelle Flash-ID.

python
MODEL = "gemini-3-flash-preview"  # durch die aktuelle Flash-Modell-ID ersetzen

def get_weather_impl(city, unit="celsius"):
    return {"city": city, "temp": 19, "unit": unit}  # hier kommt der echte API-Aufruf hin

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

resp = client.models.generate_content(model=MODEL, contents=contents, config=config)

if resp.function_calls:
    call = resp.function_calls[0]
    result = get_weather_impl(**call.args)

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

    final = client.models.generate_content(model=MODEL, 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 eigenen Turn des Modells in die History zurück und hängen dann das Ergebnis an. Lassen Sie das erste Append weg, verliert Gemini den Überblick darüber, was es angefordert hat.

Hängen Sie diesen Turn unverändert an. Gemini-3-Modelle versehen Function-Call-Parts mit einer thought signature, einem verschlüsselten Protokoll der Überlegungen des Modells, und die API erwartet sie beim nächsten Request zurück. Wenn Sie resp.candidates[0].content unverändert anhängen, ist das erledigt. Bauen Sie den Call-Part dagegen von Hand aus Name und Argumenten nach, geht die Signatur verloren und der Request kann an der Validierung scheitern.

Gemini mehrere Funktionen aufrufen lassen

Geben Sie Gemini mehr als eine Deklaration, wählt es die passende aus oder fordert mehrere an. Parallel function calling bedeutet, dass eine einzelne Antwort mehrere functionCall-Parts enthält („compare weather in Lisbon and Madrid“ ergibt zwei Aufrufe auf einmal). Iterieren Sie über resp.function_calls, führen Sie jeden Aufruf aus und hängen Sie alle Antworten gemeinsam an, bevor der nächste Turn folgt.

Sie können das Verhalten auch mit tool_config einschränken. Setzen Sie den function calling mode auf ANY, muss Gemini eine Funktion aufrufen, statt in Fließtext zu antworten. Das ist sinnvoll, 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, das Modell entscheidet), ANY (muss etwas aufrufen) und NONE (ruft nie auf). Kombinieren Sie ANY mit einer allowed_function_names-Liste, um das Modell auf eine bestimmte Teilmenge festzulegen.

Structured outputs: wenn Sie Daten wollen, kein Tool

Function calling dient dem *Handeln*. Structured output dient dem *Extrahieren*. Wenn Gemini nur sauberes, parsebares JSON liefern soll, simulieren Sie das nicht mit einem Tool. Nutzen Sie die Response-Schema-Funktion, die das Decoding des Modells so einschränkt, dass der Output Ihrem Schema entspricht.

Das ist constrained decoding: Gemini darf bei der Generierung nur Tokens erzeugen, die den Output gegenüber Ihrem Schema gültig 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=MODEL,
    contents="Extract the invoice details from this email: ...",
    config=types.GenerateContentConfig(
        response_mime_type="application/json",
        response_json_schema=Invoice.model_json_schema(),
    ),
)

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

Die Gemini API akzeptiert über response_json_schema standardkonformes JSON Schema. Das model_json_schema() eines Pydantic-Modells lässt sich also direkt einsetzen, und Sie validieren das Ergebnis zurück in typisierte Objekte. Kein Prompt, der um „return only JSON“ bettelt. Keine verirrten Markdown-Fences, die Sie entfernen müssen. Die Output-Keys kommen in der Reihenfolge zurück, die Ihr Schema festlegt. In älterem Code sehen Sie noch response_schema und propertyOrdering: Das funktioniert, aber für neue Projekte ist der JSON-Schema-Weg der richtige.

Wenn das Schema dynamisch ist

Wird die Struktur erst zur Laufzeit festgelegt, übergeben Sie ein einfaches Schema-Dict:

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

Für Klassifikation erzwingt ein Enum auf einem einzelnen Feld wie sentiment, dass die Antwort exakt eines Ihrer Labels ist und nichts anderes. Das ist der sauberste Weg zur Single-Label-Klassifikation.

Die Wahl zwischen beiden

Die beiden überschneiden sich, entscheiden Sie also bewusst:

  • Structured output, wenn Sie die gesamte Interaktion steuern und aus einem einzigen 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 häufiges Muster kombiniert beides: Function calls holen echte Daten, und die finale Antwort kommt über ein Response-Schema zurück, damit Ihr nachgelagerter Code typisiert bleibt. Gemini-3-Modelle akzeptieren Tools und ein Response-Schema im selben Request, ein separater Extraktionsaufruf ist also nicht mehr nötig.

Bauen Sie nicht selbst, was die Plattform mitliefert

Manche „Funktionen“ gibt es bereits als eingebaute Tools. Grounding mit Google Search, Code Execution und URL Context sind native Tools, die Sie in der Konfiguration aktivieren, statt sie selbst zu implementieren. Brauchen Sie aktuelle Fakten, schalten Sie Search Grounding ein, statt eine eigene Suchfunktion zu schreiben:

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

Bei Gemini-3-Modellen können Sie eingebaute Tools wie oben mit Ihren eigenen Funktionsdeklarationen kombinieren. Ältere Modelle und manche Vertex-AI-Konfigurationen schränken das noch ein. Prüfen Sie daher die Tools-Dokumentation für das Modell, das Sie deployen.

Function Calling with the Gemini API

Watch on YouTube

Wissenscheck

1. Was ist die wichtigste konzeptionelle Unterscheidung bei der Art, wie Gemini function calling handhabt?

2. Warum sollen die `description`-Felder einer Funktion laut der Lektion als Prompt Engineering statt als Dokumentation behandelt werden?

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

MEHRFACHAUSWAHL

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

Wählen Sie alle richtigen Antworten aus.

MEHRFACHAUSWAHL

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

Wählen Sie alle richtigen Antworten aus.

Prototyp in AI Studio, dann richtig skalieren

Bevor Sie einen Loop schreiben, bauen Sie die Funktionsdeklaration visuell in Google AI Studio. Dort können Sie Tools definieren, beobachten, wie Gemini functionCall-Parts ausgibt, und funktionierenden Code in Ihrer Sprache kopieren. Das ist der schnellste Weg, um die description-Strings zu optimieren.

Beim Schritt in die Produktion lautet 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 benötigen: 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 Planung, Memory und vielen Tools wird. ADK liefert Ihnen Loop, State und Tool-Orchestrierung als Framework, sodass Sie die Append-the-Response-Verdrahtung nicht mehr von Hand schreiben. Siehe die ADK-Dokumentation.

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

Hart erarbeitete Details, die Ihnen Stunden sparen

Beschreibungen sind Prompts. Wie treffsicher Gemini Funktionen auswählt und befüllt, hängt eng an der Qualität Ihrer description-Felder und Parameterdokumentation. Schreiben Sie ausdrücklich hin, *wann* eine Funktion verwendet werden soll und *wann nicht*.

Validieren Sie jedes Argument. Gemini befüllt Argumente anhand eines Schemas, kann aber trotzdem einen plausiblen, aber falschen Wert halluzinieren, besonders bei IDs oder Enums, an die es sich nur halb erinnert. Behandeln Sie Funktionsargumente wie nicht vertrauenswürdige Nutzereingaben. Validieren Sie, bevor Sie irgendetwas mit Side Effects ausführen.

Setzen Sie `required` und `enum` konsequent ein. Jede Einschränkung im Schema ist eine Einschränkung, die das Modell erfüllen muss. Enums schließen ganze Klassen unbrauchbarer Werte aus. Pflichtfelder verhindern halb befüllte Aufrufe.

Wählen Sie die Modellstufe pro Aufgabe. Flash erledigt das meiste Tool-Routing und die meisten Extraktionen mit niedriger Latenz und geringen Kosten. Greifen Sie zu Pro, wenn die Entscheidung, *welches* Tool aufgerufen wird, echtes Reasoning über einen langen Kontext erfordert oder wenn die Extraktion von subtiler Logik über mehrere Dokumente abhängt.

Spielen Sie Funktionsergebnisse immer zurück. Der häufigste Bug: Sie vergessen, den eigenen Function Call des Modells vor der Antwort anzuhängen. Ohne ihn ist die Konversations-History inkonsistent, die finale Antwort driftet ab, und bei Gemini 3 kann die fehlende thought signature den Request scheitern lassen.

Key Takeaways

  • Sie führen aus, Gemini entscheidet. Der Loop lautet: Funktionen deklarieren, einen functionCall empfangen, selbst ausführen, sowohl den unveränderten Turn des Modells als auch Ihre functionResponse anhängen, dann die finale Antwort generieren.
  • Nutzen Sie response_json_schema (das model_json_schema() eines Pydantic-Modells funktioniert), um per constrained decoding schemakonformes JSON zu erhalten. Hören Sie auf, per Prompt um JSON zu bitten und Markdown-Fences zu entfernen.
  • Function calling greift für Live-Daten und Side Effects über das Modell hinaus; structured output parst Daten aus einem einzigen Aufruf. Bei Gemini 3 können Sie beides plus eingebaute Tools wie Search in einem Request nutzen.
  • Die Treffsicherheit von Tools ist vor allem eine Frage der Schemaqualität. Investieren Sie also in description-Felder, Enums und required.
  • Erstellen Sie den Prototyp in AI Studio und wechseln Sie dann je nach Skalierung, Enterprise-Kontrollen oder Agent-Orchestrierung zur Gemini API, zu Vertex AI oder zu ADK. Halten Sie Modell-IDs an einer Stelle und validieren Sie Funktionsargumente immer, bevor Sie danach handeln.