+200 XP

Claude · Tool use und structured outputs

Ein Modell, das nur Text ausgeben kann, ist eine Sackgasse, sobald es eine Live-Datenbank abfragen, eine API aufrufen oder sauberes JSON an den nächsten Service in Ihrer pipeline übergeben soll. Tool use und structured outputs schließen diese Lücke bei Claude. Sie beschreiben Fähigkeiten, Claude entscheidet, wann sie aufgerufen werden, und Sie erhalten Daten zurück, die Ihr Code verarbeiten kann.

Diese Lektion behandelt beide Mechaniken anhand der Anthropic Messages API. Sie sehen, wie die Requests und Responses aufgebaut sind, die Sie senden und parsen, und wie die beiden Techniken zusammenhängen.

Was „tool use“ tatsächlich bedeutet

Tool use (manchmal auch function calling genannt) ist ein Protokoll. Claude führt Ihren Code nie aus. Sie übergeben eine Liste von Tool-Definitionen. Jede hat einen Namen, eine Beschreibung und ein JSON Schema für ihre Inputs.

Wenn Claude entscheidet, dass ein Tool hilft, hört es auf, Fließtext zu schreiben, und gibt einen strukturierten Request aus, zum Beispiel: „rufe get_weather mit {"location": "Paris"} auf.“ Ihre Anwendung führt diese Funktion aus und schickt das Ergebnis zurück. Dann macht Claude weiter.

Dieses Hin und Her ist der Tool-use-Loop. Wenn Sie ihn verstanden haben, ergibt sich der Rest dieser Lektion.

Die vier Schritte des Loops

  1. Sie senden eine User-Nachricht plus Ihr tools-Array.
  2. Claude antwortet mit stop_reason: "tool_use" und einem tool_use-Content-Block.
  3. Sie führen das Tool aus und senden die Antwort als tool_result zurück.
  4. Claude liest das Ergebnis und erzeugt seine finale Textantwort.

Ein konkreter get_weather-Loop

Hier ist der komplette Loop in Python mit dem offiziellen SDK. Lesen Sie ihn einmal durch, danach gehen wir die einzelnen Strukturen durch.

python
import anthropic

client = anthropic.Anthropic()

tools = [{
    "name": "get_weather",
    "description": "Get current temperature for a given city.",
    "input_schema": {
        "type": "object",
        "properties": {
            "location": {"type": "string", "description": "City name, e.g. 'Paris'"}
        },
        "required": ["location"],
    },
}]

def get_weather(location):
    # In der Praxis rufen Sie hier eine Wetter-API auf.
    return {"location": location, "temp_c": 14, "conditions": "cloudy"}

messages = [{"role": "user", "content": "What's the weather in Paris right now?"}]

response = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=1024,
    tools=tools,
    messages=messages,
)

# Schritt 2: Claude hat ein Tool angefordert.
if response.stop_reason == "tool_use":
    tool_call = next(b for b in response.content if b.type == "tool_use")
    result = get_weather(**tool_call.input)

    # Schritt 3: Claudes Request UND Ihr Ergebnis anhängen.
    messages.append({"role": "assistant", "content": response.content})
    messages.append({
        "role": "user",
        "content": [{
            "type": "tool_result",
            "tool_use_id": tool_call.id,
            "content": str(result),
        }],
    })

    # Schritt 4: Claude liest das Ergebnis und schreibt die Antwort.
    final = client.messages.create(
        model="claude-sonnet-4-5",
        max_tokens=1024,
        tools=tools,
        messages=messages,
    )
    print(final.content[0].text)

Die Beispiele verwenden claude-sonnet-4-5. Jede aktuelle Claude-Modell-ID aus der Modellübersicht funktioniert genauso.

Die Response-Struktur lesen

Wenn Claude ein Tool will, ist response.content eine Liste von Blöcken. Der relevante sieht so aus:

json
{
  "type": "tool_use",
  "id": "toolu_01A09q90qw90lq917835lq9",
  "name": "get_weather",
  "input": {"location": "Paris"}
}

Drei Felder sind wichtig:

  • name sagt Ihnen, welche Funktion Sie ausführen sollen.
  • input ist bereits ein geparstes Objekt, das Ihrem Schema entspricht, Sie müssen also keine Strings parsen.
  • `id` ist die Referenz, die Sie zurückgeben müssen.

Das Ergebnis zurücksenden

Das Detail, das viele übersehen: Sie müssen zwei Nachrichten anhängen, in dieser Reihenfolge.

  1. Claudes eigenen Assistant-Turn: den vollständigen response.content, einschließlich des tool_use-Blocks.
  2. Einen User-Turn mit dem tool_result.

Die tool_use_id in Ihrem Ergebnis muss exakt mit der id übereinstimmen, die Claude gesendet hat, sonst bricht der Loop.

Wenn Ihr Tool fehlschlägt, setzen Sie "is_error": true im Result-Block. Claude sieht dann den Fehler. Es kann sich entschuldigen, es mit anderen Inputs erneut versuchen oder ein anderes Tool wählen.

Mehrere Tools und parallele Aufrufe

Selten liefern Sie nur ein Tool aus. Übergeben Sie mehrere im tools-Array, und Claude wählt anhand der Beschreibungen das passende.

Schreiben Sie diese Beschreibungen wie Dokumentation, denn sie sind das Einzige, worauf Claude seine Entscheidung stützt. „Get current temperature for a given city“ schlägt „weather tool“ jedes Mal.

Claude kann auch mehrere Tools in einem einzigen Turn anfordern (parallel tool use). Dann enthält response.content mehrere tool_use-Blöcke. Führen Sie alle aus. Geben Sie dann alle tool_result-Blöcke gemeinsam in einer User-Nachricht zurück, bevor Sie die API erneut aufrufen.

Claude kann mehrere Tools hintereinander aufrufen, bevor es fertig ist. Um das abzudecken, packen Sie den Aufruf in eine while response.stop_reason == "tool_use"-Schleife statt in ein einzelnes if.

Structured outputs: sauberes JSON zurückbekommen

Tool use löst „tu etwas“. Structured outputs lösen „gib mir Daten in exakt dieser Form“. Angenommen, Sie extrahieren Felder aus einer Support-E-Mail. Sie brauchen jedes Mal {"category": ..., "urgency": ..., "summary": ...}, ohne Fließtext und ohne Markdown-Fences.

Seit November 2025 bietet die Messages API native structured outputs. Es gibt sie in zwei Formen:

  • JSON outputs. Sie übergeben ein JSON Schema als Response-Format, und Claudes Textantwort lässt sich garantiert parsen und entspricht dem Schema.
  • Strict tool use. Sie ergänzen eine Tool-Definition um "strict": true, und jeder tool_use-Input entspricht garantiert dem input_schema dieses Tools.

Beide nutzen constrained decoding. Das Modell kann keine Tokens ausgeben, die Ihr Schema verletzen würden, Sie brauchen also keine Retry-Logik für fehlerhaftes JSON mehr.

python
import json
import anthropic

client = anthropic.Anthropic()

ticket_schema = {
    "type": "object",
    "properties": {
        "category": {"type": "string", "enum": ["billing", "bug", "feature", "other"]},
        "urgency": {"type": "string", "enum": ["low", "medium", "high"]},
        "summary": {"type": "string", "description": "One sentence."},
    },
    "required": ["category", "urgency", "summary"],
    "additionalProperties": False,
}

email = "I was charged twice this month and need this fixed before Friday!"

response = client.beta.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=1024,
    betas=["structured-outputs-2025-11-13"],
    output_format={"type": "json_schema", "schema": ticket_schema},
    messages=[{"role": "user", "content": email}],
)

ticket = json.loads(response.content[0].text)
print(ticket)
# {'category': 'billing', 'urgency': 'high', 'summary': 'Customer charged twice and wants a fix by Friday.'}

Das Feature startete als Beta mit dem oben gezeigten Header. Prüfen Sie in der Dokumentation die aktuellen Parameternamen und welche Modelle es unterstützen, denn Beta-APIs können sich ändern, wenn sie allgemein verfügbar werden.

Die Python- und TypeScript-SDKs können auch ein Pydantic- oder Zod-Modell entgegennehmen und es für Sie in ein Schema umwandeln.

Die enum-Constraints leisten hier echte Arbeit. Mit constrained decoding kann Claude keine vierte Dringlichkeitsstufe erfinden. Je enger Ihr Schema, desto enger Ihre Outputs.

Einige Schema-Features werden nicht unterstützt, etwa bestimmte numerische Grenzen und komplexe rekursive Definitionen. Der erste Request mit einem neuen Schema hat außerdem etwas zusätzliche Latenz, während die Grammatik kompiliert wird. Danach wird die kompilierte Grammatik gecacht.

Das Forced-Tool-Pattern

Bevor es native structured outputs gab, bestand der übliche Trick darin, ein Tool zu definieren, das Ihren Output repräsentiert, und Claude zu zwingen, es aufzurufen. Sie finden das in viel bestehendem Code. Es funktioniert weiterhin, und mit "strict": true wird es garantiert.

python
extract_tool = {
    "name": "record_ticket",
    "description": "Record the structured fields of a support ticket.",
    "strict": True,
    "input_schema": ticket_schema,
}

response = client.beta.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=1024,
    betas=["structured-outputs-2025-11-13"],
    tools=[extract_tool],
    tool_choice={"type": "tool", "name": "record_ticket"},
    messages=[{"role": "user", "content": email}],
)

ticket = next(b.input for b in response.content if b.type == "tool_use")

Der Parameter tool_choice ist der Hebel. Mit {"type": "tool", "name": "record_ticket"} erzwingen Sie genau diesen Aufruf. Sie führen hier nie eine Funktion aus. Sie lesen nur b.input.

Weitere Werte für tool_choice:

  • {"type": "auto"} (Standard): Claude entscheidet, ob es ein Tool nutzt.
  • {"type": "any"}: Claude muss *irgendein* Tool nutzen, wählt aber selbst, welches.
  • {"type": "tool", "name": "..."}: ein bestimmtes Tool erzwingen, wie oben.
  • {"type": "none"}: in diesem Turn keine Tool-Aufrufe.

Als Faustregel: Nutzen Sie JSON outputs, wenn Claudes Antwort selbst eine feste Form haben soll. Nutzen Sie strict tools, wenn Claude in einem Agent echte Funktionen aufruft und ein fehlerhaftes Argument etwas kaputt machen würde.

Der Tool-use-Guide ist die maßgebliche Referenz für Schema-Sonderfälle und Streaming.

Claude Tool Use Explained

Watch on YouTube

Wissenscheck

1. Was passiert im beschriebenen Tool-use-Protokoll tatsächlich, wenn Claude ein Tool „nutzt“?

2. Warum sind tool use und structured outputs wertvoll, wenn Sie Claude in eine Software-pipeline integrieren?

3. Was passiert im letzten Schritt des Tool-use-Loops, nachdem Sie ein tool_result an Claude zurückgesendet haben?

MEHRFACHAUSWAHL

4. Wählen Sie ALLE Elemente, die eine einzelne Tool-Definition enthalten muss, wenn Sie Ihr tools-Array an Claude senden.

Wählen Sie alle richtigen Antworten aus.

MEHRFACHAUSWAHL

5. Wählen Sie ALLE Aussagen, die das Verhalten des Tool-use-Loops korrekt beschreiben.

Wählen Sie alle richtigen Antworten aus.

Wie das mit MCP und dem Agent SDK zusammenhängt

Alles oben ist die rohe API. Sie definieren Tools inline und führen sie selbst aus. Das passt perfekt für eine Handvoll maßgeschneiderter Tools innerhalb eines Service.

Schnell werden Sie wiederverwendbare Tools wollen, die jede Claude-Oberfläche aufrufen kann, etwa die Desktop-App, Claude Code oder Ihr eigener Agent. MCP (Model Context Protocol) standardisiert das.

Ein MCP-Server stellt Tools (plus Ressourcen und prompts) über ein definiertes Protokoll bereit. Sie schreiben ein Tool einmal und binden es in viele Clients ein. Die Claude-Apps zeigen diese als Connectors an, und es gibt ein Connector-Verzeichnis für gängige wie Google Drive oder GitHub.

MCP-Tools und API-Tools sind dieselbe Idee in unterschiedlichem Umfang. Die Tool-Liste eines MCP-Servers wird letztlich zu Einträgen in einem tools-Array, und der Call/Result-Handshake entspricht dem Loop, den Sie gerade gelernt haben. Das Protokoll lernen Sie unter modelcontextprotocol.io.

Das Claude Agent SDK setzt eine Ebene höher an. Es führt den Tool-use-Loop für Sie aus, verwaltet den Kontext und übernimmt mehrstufiges Agent-Verhalten. Sie beschreiben Tools und Ziele, statt die while stop_reason == "tool_use"-Mechanik von Hand zu programmieren.

Wenn Sie einen echten Agent bauen, greifen Sie zum SDK. Wenn Sie präzise Kontrolle über einen einzelnen Austausch brauchen, gehen Sie wie oben gezeigt auf die Messages API zurück. Beide nutzen dasselbe Tool-use-Protokoll, deshalb lohnt es sich, den rohen Loop zu lernen.

Praktische Stolperfallen

Ein paar Dinge, die Sie in Produktion erwischen werden:

  • Token-Budget. Tool-Definitionen liegen im Kontextfenster, zwanzig ausführliche Tools kosten also bei jedem Aufruf spürbar Tokens. Halten Sie Schemas schlank und Beschreibungen präzise.
  • Validieren Sie die Werte trotzdem. Strict mode garantiert die Form, nicht die Bedeutung. Ein schema-konformes {"user_id": "1 OR 1=1"} bleibt gefährlich. Behandeln Sie input wie nicht vertrauenswürdigen User-Input: Wertebereiche prüfen, bereinigen und autorisieren, bevor Sie eine Datenbank ansprechen.
  • Erzwungene Tools überspringen das Reasoning. Wenn Sie tool_choice auf ein bestimmtes Tool festlegen, springt Claude direkt zum Aufruf, und erzwungene Tool-Auswahl ist nicht mit extended thinking kompatibel. Wenn Sie vorher Reasoning brauchen, lassen Sie es auf auto, nutzen Sie JSON outputs oder teilen Sie die Arbeit auf zwei Aufrufe auf.
  • Fehler sind Signal, kein Scheitern. Ein is_error: true mit einer hilfreichen Meldung lässt Claude sich im nächsten Turn oft selbst korrigieren. Das ist besser, als den Loop abstürzen zu lassen.

Key Takeaways

  • Tool use ist ein Loop in vier Schritten. Tools senden, einen tool_use-Block empfangen, die Funktion ausführen und ein tool_result mit der passenden tool_use_id zurückgeben. Geben Sie Claudes Assistant-Turn vor dem Ergebnis zurück, sonst bricht der Loop.
  • Für garantiertes JSON nutzen Sie native structured outputs. Verwenden Sie ein json_schema-Output-Format für die Antwort selbst oder "strict": true bei Tools. Constrained decoding bedeutet, dass das Schema immer eingehalten wird. Das ältere Forced-Tool-Pattern funktioniert weiterhin.
  • Schreiben Sie Tool-Beschreibungen wie Dokumentation. Claude nutzt sie zur Auswahl, formulieren Sie sie also konkret.
  • Validieren Sie Tool-Inputs in Ihrem Code. Eine gültige Form heißt nicht, dass der Wert sicher ist. Claude schlägt vor, Ihre Anwendung führt aus.
  • Skalieren Sie bewusst. Nutzen Sie die rohe Messages API für einen einzelnen maßgeschneiderten Austausch, MCP für wiederverwendbare App-übergreifende Tools und das Agent SDK, wenn der Loop für Sie verwaltet werden soll. Alle drei nutzen dasselbe Protokoll.

Was Sie aus dieser Lektion umsetzen

Diese Maßnahmen sind im Playbook der Rolle zusammengefasst.

  • Erzwingen Sie ein Tool-Schema, wenn Sie garantiert geparstes JSON brauchen
Vollständiges Action Playbook ansehen →