Startseite / Artikel

Claude Tool Use End-to-End: Der agierende Kreislauf in drei Iterationen

Claude Tool-Use von Ende zu Ende: eine einzige Messages-API-Anfrage über den agierenden Loop, inklusive Regeln für Tool-Definitionen, Tool-Choice, parallele Aufrufe und Tool-Resultate.

Verlag: REACTAPP.TOP19 Min. Lesezeit4379 Wörter

Quellen: Part III | ‘tool_use’, End to End: The Agentic Loop in Three Iterations

Warum die Schleife von Ihnen geschrieben werden muss

Durch die direkte Verwendung von tool_use über die Messages API (anthropic.Anthropic() gefolgt von client.messages.create(...)) liegt die Steuerung der Schleife in Ihren Händen. Ihr Code deklariert die Tools, prüft den Abbruchgrund, analysiert Claudes Anfragen, führt sie aus und gibt das Ergebnis zurück. Das Manuell-Schreiben dieser Schleife bildet die Grundlage jedes systems, das Tools verwendet, und ist ein Standardthema im Lehrplan für den Claude Certified Architect.

Zunächst ein Hinweis: Die Messages API ist zustandslos. Zwischen den Aufrufen wird nichts gespeichert, weshalb jede Anfrage den gesamten Dialog enthält. Ein Schritt, bei dem Tools verwendet werden, besteht in der Regel aus mehreren Anfragen statt nur einer, bis Claude alles hat, was es benötigt. Der Rest folgt dann einer einzigen Anfrage durch diesen vollständigen Zyklus.

Das laufende Beispiel ist ein kleiner Terminplanungs-Assistent. Ein Benutzer fragt, ob er für ein Treffen in London morgen einen Regenschirm mitnehmen soll und wann er zu Hause aufbrechen muss, um pünktlich anzukommen. Zur Beantwortung sind drei verschiedene Informationen erforderlich: die Details des Treffens, die Wettervorhersage und die Fahrzeit. Beobachten Sie, wie Claude die Frage in drei Schritte aufteilt und wie viel der Arbeit auf Ihren Code und nicht auf das Modell entfällt.

1. Die Struktur der Schleife

Jeder Austausch unter Verwendung von Tools folgt einem vierphasigen Zyklus:

  1. Deklarieren Sie die Tools in der Anfrage.
  2. Claude fragt nach einem oder mehreren davon, was durch stop_reason: „tool_use“ signalisiert wird.
  3. Ihr Code führt sie aus und sammelt die Ergebnisse ein.
  4. Ihre Anwendung sendet die Ergebnisse zurück und ruft die API erneut auf.

Die Phasen zwei bis vier wiederholen sich, und jeder Durchlauf zählt als eine Iteration. Der Schleifenprozess endet, wenn Claude aufhört, nach Tools zu fragen, und eine normale Abschlussmeldung (end_turn) oder einen anderen Grund für das Beenden zurückgibt. Da die API zustandslos ist, müssen Sie das Gespräch selbst aufbauen und es jedes Mal erneut senden. Nichts geht voran, es sei denn, Ihr Code sorgt dafür.

2. Deklaration der Tools

Claude ist nur auf die von Ihnen angegebenen Tools beschränkt. Diese befinden sich im obersten Ebene-Parameter tools der Anfrage, der ein Array mit Definitionen enthält. Immer wenn tools vorhanden ist, erstellt die API vor der Benutzernachricht einen versteckten Systemprompt daraus. Dieser versteckte Prompt wird berechnet: Jeder Name, jede Beschreibung und jedes Schema verbrauchen bei jeder Anfrage Eingabetoken, selbst wenn Claude das jeweilige Tool nie verwendet.

Jedes Client-Tool benötigt drei Felder:

  • name ist eine eindeutige Identifikationsnummer, die der Regel ^[a-zA-Z0-9_-]{1,64}$ entsprechen muss. Es handelt sich um den String, der im tool_use-Block zurückgegeben wird, und Ihr Code verwendet ihn, um zur richtigen Funktion übergehen zu können.
  • description ist eine in Alltagssprache verfasste Beschreibung zum Zweck des Tools, zum richtigen Zeitpunkt seiner Verwendung sowie zur Bedeutung jedes Parameters. Nichts anderes beeinflusst die korrekte Aufrufweise so stark, daher sollte sie als Spezifikation statt als einfacher Titel verfasst werden.
  • input_schema ist ein JSON Schema für die Argumente: ihre Typen, ob sie required sind, und was jeder Typ bedeutet.

Hier sind die drei Tools für das Beispiel:

"tools": [
  {
    "name": "get_calendar_event",
    "description": "Look up a calendar event by a natural-language query. Returns the event's start time and location.",
    "strict": true,
    "input_schema": {
      "type": "object",
      "properties": {
        "query": { "type": "string", "description": "What to search for, e.g. 'meeting in London tomorrow'" }
      },
      "required": ["query"],
      "additionalProperties": false
    }
  },
  {
    "name": "get_weather",
    "description": "Get the forecast for a city on a given date. Returns condition and temperature in Celsius.",
    "strict": true,
    "input_schema": {
      "type": "object",
      "properties": {
        "city": { "type": "string", "description": "City name, e.g. 'London'" },
        "date": { "type": "string", "description": "ISO date, e.g. '2026-07-14'" }
      },
      "required": ["city", "date"],
      "additionalProperties": false
    }
  },
  {
    "name": "get_travel_time",
    "description": "Estimate door-to-door travel time between two places. Returns minutes.",
    "strict": true,
    "input_schema": {
      "type": "object",
      "properties": {
        "origin": { "type": "string", "description": "Starting location" },
        "destination": { "type": "string", "description": "Ending location" }
      },
      "required": ["origin", "destination"],
      "additionalProperties": false
    }
  }
]

Definieren Sie sie sorgfältig. Anthropics Anleitung zu effektiven Werkzeugen lässt sich auf einige Gewohnheiten reduzieren:

  • Siezen Sie die Werkzeugnamen genau. get_current_weather gibt Claude mehr Informationen als weather.
  • Nennen und beschreiben Sie Parameter eindeutig. Wählen Sie user_id statt user, damit die richtige Art von Wert übergeben wird, und beschreiben Sie jeden Parameter – schließlich zieht auch ein gut benanntes Feld mit einer vagen Beschreibung weiterhin fehlerhafte Eingaben an.
  • Halten Sie die Werkzeugliste klein. Eine übermäßig große Liste verunreinigt den generierten Systemprompt und erschwert die Auswahl des Modells.
  • Überprüfen Sie alles. Ein Schema begrenzt die Struktur, nicht die Absicht, daher prüfen Sie jeden Eingang, den Ihr Code erhält.

Zwei Ergänzungen zu diesen Definitionen verdienen eine genaue Betrachtung.

  1. strict: true ist am wichtigsten. Er befindet sich auf der höchsten Ebene jedes Tools neben name, description und input_schema und aktiviert ein grammatikgesteuertes Stichprobenverfahren für die Argumente des Tools, sodass das Modell physisch nicht in der Lage ist, einen input zu erzeugen, der Ihr Schema bricht. Wenn dieser Wert deaktiviert bleibt, gibt Claude in der Regel gültige Argumente aus, kann aber abweichen – beispielsweise "2" anstelle der erforderlichen Zahl 2, einen Wert außerhalb eines enum oder ein fehlendes Pflichtfeld. Jede Abweichung führt zu einem Laufzeitfehler im Code, der den Aufruf verarbeitet. Wenn strict: true aktiviert ist, passt der input innerhalb jedes tool_use-Blocks sicherlich zu input_schema, und der Name ist garantiert einer Ihrer eigenen Tools.
  2. Eine Schema-Regel garantiert, dass jedes Objekt den Wert additionalProperties: false haben muss, weshalb sie in allen oben genannten Tools enthalten ist. Die strenge Anwendung dieser Regeln ist ein Bestandteil der strukturierten Ausgabe-Funktion von Anthropic. Zum Zeitpunkt der Erstellung war diese Funktion in aktuellen Modellen wie Opus 4.8 allgemein verfügbar, während ältere Modelle wie Sonnet 4.5 den Beta-Header structured-outputs-2025-11-13 erforderten. Kompilierte Schemata werden bis zu 24 Stunden lang im Cache gespeichert, sodass ein vorgefertigter Cache keinerlei Kompilierungskosten verursacht.

Man kann auch cache_control zu Tool-Definitionen hinzufügen, um diese über mehrere Anfragen hinweg zu cachen und so erneute Verarbeitungskosten zu vermeiden – was sich lohnt, wenn die Tool-Liste groß und stabil ist.

Definitionen beschreiben ausschließlich die Eingabedaten

Die Definition einer Tool umfasst ausschließlich die Eingabe, also das, was Claude an Sie sendet. Das überrascht Menschen aus Frameworks, die Rückgabetypen deklarieren. Einfach ausgedrückt:

  • Eine Definition enthält name, description und input_schema als obligate Bestandteile, während strict, input_examples und cache_control optionale Ergänzungen sind. Weder output_schema noch error_schema existieren.
  • Die Rückgabewerte werden zur Laufzeit durch Ihren Code festgelegt und anschließend im tool_result-Block, wie in Abschnitt 6 beschrieben, zurückgegeben. Das content-Feld kann entweder einen String oder eine Liste von Blöcken enthalten, wobei die API diese nicht gegen irgendetwas überprüft, da es kein zu prüfendes Schema gibt. Eine praktische Vorsichtsmaßnahme: Ein Tool könnte ein DTO-Objekt zurückgeben, und der Standardparser flacht dieses durch seine toString-Methode in einen einfachen String ab. Die Verwendung dieser abgeflachten Form funktioniert zwar, ist aber nicht ideal. Konvertieren Sie DTOs lieber in strukturiertes JSON.
  • Auch Fehler sind eine Laufzeitangelegenheit. Melden Sie einen fehlgeschlagenen Aufruf mit is_error: true im tool_result sowie einer aussagekräftigen Nachricht im content; die Definition enthält keinen deklarativen Fehlertyp. Standardmäßig leitet das SDK eine ausgelöste Ausnahme als Fehlerergebnis an Claude weiter, und Claude passt sich an.
  • Die Unebenheit ist beabsichtigt. Definitionen dienen dazu, Claude zu zeigen, wie ein Tool aufgerufen wird. Ein Ergebnis ist lediglich zusätzlicher Kontext, der sich wieder dem Zyklus anschließt; daher ist abgesehen vom tool_use_id, das es mit der Anfrage verbindet, kein Vertrag erforderlich.
  • Möchten Sie ein garantiertes Ausgabeformat? Überprüfen Sie es selbst im Code, bevor Sie etwas zurücksenden, oder wenden Sie strukturierte Ausgaben (output_config.format) auf die abschließende Antwort an, die Claude aus diesen Ergebnissen erstellt. MCP-Tools bringen ihr eigenes outputSchema mit, doch das ist eine Eigenschaft der MCP-Schicht und nicht der nativen Definitionen.

Kontrolle darüber, ob Claude ein Tool aufruft

tool_choice entscheidet darüber, ob in einer Runde Tools aufgerufen werden dürfen und welche.

  • Das Feld befindet sich auf der obersten Ebene der Anfrage neben tools und messages und gehört keinem bestimmten Tool.
  • Was es einschränkt, ist die Ausgabe, die Claude erzeugen darf. Die Logik bleibt unverändert, da Claude den gesamten Prompt in jedem Fall liest.
  • Ihr Geltungsbereich umfasst nur eine einzelne Anfrage, niemals etwas Globales. Die API ist zustandslos, sodass tool_choice nur die mit ihr gesendete Antwort steuert – also eine einzige Iteration. Um sie über mehrere Iterationen hinweg beizubehalten, muss sie jedes Mal erneut gesendet werden. Es ist zulässig, sie pro Iteration zu variieren: Frühzeitig ein Tool zwingend verwenden, später auto und für eine endgültige Textantwort none.

Das Objekt sieht so aus:

{
  "type": "auto" | "any" | "tool" | "none",
  "name": "get_weather",              // required ONLY when type is "tool"
  "disable_parallel_tool_use": false  // optional; default false
}

type ist erforderlich und kann einen von vier Werten annehmen. name ist nur dann notwendig, wenn type den Wert "tool" hat. disable_parallel_tool_use ist optional und begrenzt die Anzahl der Tools, die pro Schritt aufgerufen werden dürfen.

auto. Claude entscheidet selbst: keine Tools, ein Tool, mehrere Tools oder eine textbasierte Antwort. Parallelaufrufe sind erlaubt. Eine reine Textantwort ist zulässig, und Claude kann vor den Aufrufen etwas erläutern. Dies ist standardmäßig der Fall, wenn tools angegeben werden. Durch die Einstellung disable_parallel_tool_use: true wird die Anzahl auf ein einziges Tool begrenzt, wobei auch keine Tools möglich sind. Dies eignet sich für Chat-Assistenten und agierende Schleifen, in denen unterschiedliche Schritte unterschiedliche Aktionen erfordern. Es ist der einzige Modus, der es Claude ermöglicht, vor dem Handeln laut nachzudenken, sowie der einzige Modus neben none, der erweitertes Nachdenken unterstützt.

any. Claude muss ein Tool aufrufen, darf aber selbst wählen, welches. Es wird mindestens ein Aufruf durchgeführt, und da die parallele Verwendung standardmäßig aktiviert ist, können mehrere tool_use-Blöcke zurückkehren, nicht unbedingt nur einer. Genau ein Aufruf findet nur statt, wenn disable_parallel_tool_use: true gesetzt ist. Einfacher Text ist nicht zulässig, es gibt keine einleitende Begründung, und dies ist niemals die Standard-Einstellung. Verwenden Sie diese Option, wenn ein durch ein Tool erzeugtes Ergebnis zwingend erforderlich ist, das Tool sich jedoch unterscheidet – wie beispielsweise bei Routern und Klassifizierern.

tool. Claude muss das von Ihnen benannte Tool aufrufen, daher ist name erforderlich. Es wird mindestens ein Aufruf dieses Tools durchgeführt (es kann ihn mehrmals parallel aufrufen), und genau ein Aufruf muss disable_parallel_tool_use: true enthalten. Es darf keinen reinen Text geben, auch keine einleitenden Erklärungen. Dies eignet sich für einmalige, strukturierte Extraktionen, als obligater erster Schritt oder für das JSON-over-Tool-Muster, beispielsweise {"type": "tool", "name": "get_weather"}. Eine Anfrage, die ein Tool nennt, das nicht in tools enthalten ist, erhält eine 400-Fehlermeldung, und das Erzwingen eines Tools beschränkt den Aufruf nicht auf einen einzigen, es sei denn, die parallele Verwendung ist deaktiviert.

none. Claude darf in diesem Zug keine Tools aufrufen, auch wenn sie definiert sind, und stop_reason kann nicht tool_use sein. Einfacher Text ist erlaubt, genauso wie vorangestellte Begründungen. Dies ist der Standardfall, wenn keine tools angegeben werden. Verwenden Sie ihn, um einen rein textbasierten Zug zu erzwingen, beispielsweise für eine endgültige Synthese, ohne den tools-Array zu verändern. Dadurch werden Tools deaktiviert, ohne dass der Array geändert wird – allerdings werden bei Wechsel darauf weiterhin gespeicherte Nachrichtenblöcke ungültig.

Mehrere allgemeine Details können leicht übersehen werden:

  • Erzwungene Modi entfernen die Einleitung. Unter any oder tool füllt die API den Assistentenzug im Voraus aus, sodass der tool_use-Block ohne Erklärung oder Begründung erscheint, unabhängig von Ihrer Anfrage. Sichtbare Begründungen erfordern auto.
  • Erweitertes Denken erfordert auto oder none. Die erzwungene Verwendung eines Tools kann damit nicht kombiniert werden, und die API lehnt diese Kombination ab.
  • Zählregel für disable_parallel_tool_use. auto bedeutet höchstens ein Tool, any und tool bedeuten genau ein Tool, und der Standardwert false erlaubt parallele Aufrufe bei Claude 4-Modellen.
  • Caching-Kosten. Das Ändern von tool_choice zwischen Anfragen macht die im Cache gespeicherten Nachrichtenblöcke ungültig. Tooldefinitionen und der Systemprompt bleiben im Cache, doch die Konversation wird neu verarbeitet.
  • Kombinieren mit strict. tool_choice sorgt dafür, dass ein Tool ausgeführt wird, und strict stellt sicher, dass seine Argumente dem Schema entsprechen. Gemeinsam liefern sie in jedem Schritt ein typisiertes, strukturiertes Ergebnis.
  • In einer Anfrage:

    response = client.messages.create(
        model="claude-opus-4-8",
        max_tokens=1024,
        tools=tools,
        tool_choice={"type": "any", "disable_parallel_tool_use": True},  # must call exactly one tool
        messages=messages,
    )
    

    Daraus ergeben sich zwei Gestaltungsregeln: Reservieren Sie die Verwendung von Tools für Fälle, in denen tatsächlich ein Tool-Ergebnis erforderlich ist, und bleiben Sie bei auto, wenn eine prosaische Antwort ausreicht. Fügen Sie außerdem, wenn ein Klassifizierungs-Tool zwangsläufig verwendet werden muss, eine "other"-Option zu dessen Enum hinzu, damit Claude eine Kategorie ablehnen kann, anstatt die Eingabe falsch zu klassifizieren.

    3. Erste Iteration: Claude bittet um Tools

    Die Anfrage enthält das Tool-Array, eine von Ihnen gewählte tool_choice-Option sowie die Frage des Benutzers:

    messages = [{"role": "user",
                 "content": "I have a meeting in London tomorrow
                             — should I bring an umbrella, and
                             when should I leave home to be on time?"}]
    
    response = client.messages.create(
        model="claude-opus-4-8",
        max_tokens=1024,
        tools=tools,                    # the three strict definitions from Section 2
        tool_choice={"type": "auto"},   # let Claude decide whether, and what, to call
        messages=messages,
    )
    

    Claude analysiert die Anfrage und stellt fest, dass zwei der drei Anforderungen nicht voneinander abhängen: Die Kalenderabfrage und die Prognose können gleichzeitig ausgeführt werden. Daher bittet er um beide Tools in einer einzigen Antwort. Zusammen zurückgegebene unabhängige Aufrufe werden als parallele Toolnutzung bezeichnet und erscheinen als mehrere tool_use-Blöcke in einem einzigen Schritt.

    {
      "id": "msg_01...",
      "role": "assistant",
      "stop_reason": "tool_use",
      "content": [
        { "type": "text", "text": "Let me check your meeting details and the London forecast." },
        { "type": "tool_use", "id": "toolu_01Cal", "name": "get_calendar_event",
          "input": { "query": "meeting in London tomorrow" } },
        { "type": "tool_use", "id": "toolu_01Wx", "name": "get_weather",
          "input": { "city": "London", "date": "2026-07-14" } }
      ]
    }
    

    Drei Dinge heben sich in dieser Antwort ab.

    1. stop_reason ist tool_use, was bedeutet, dass der Turn noch nicht abgeschlossen ist und Claude auf Sie wartet.
    2. Der content-Array enthält eine Mischung verschiedener Elemente. Ein text-Block mit Erzählung geht häufig den tool_use-Blöcken voraus, sodass die Toolaufrufe nicht an einer festen Stelle liegen.
    3. Jeder tool_use-Block verfügt über eine id (mit dem Präfix toolu_), einen name sowie ein input-Objekt, das bereits Ihrem Schema entspricht.

    Finden Sie die Aufrufe, indem Sie durch den Inhalt iterieren und nach Typ filtern – niemals nach Index:

    tool_calls = [block for block in response.content if block.type == "tool_use"]
    

    Das führt hier zu zwei Aufrufen. Jeder id dient als Identifikator zur Rückgabe des Ergebnisses dieses Aufrufs, und die Verknüpfung von id mit dem Ergebnis ist die Methode, mit der Claude Antworten auf Fragen zuordnet, wenn mehrere offen sind.

    Hinweis für Claude 4-Modelle: Erweitertes Denken kann unterbrochen werden, sodass das Schlussfolgern sowohl zwischen den Tool-Aufrufen als auch davor stattfinden kann. Wenn das Erweiterte Denken aktiviert ist, müssen die Denkblöcke zusammen mit dem Rest des Assistenten-Antwortschritts zurückgesendet werden, sonst vergisst die Fortsetzung dieses Schlussfolgerns.

    4. Ausführung der Tools

    Nun geht die Arbeit an Ihren Code. Claude hat zwei Tools angefordert, hat aber keines ausgeführt. Führen Sie alles aus, was es angefordert hat, sammeln Sie alle Ergebnisse und senden Sie anschließend einen einzigen Nachfolgeaufruf, der sie zusammen enthält. Claude wartet, bis jeder von ihm ausgeführte Aufruf ein entsprechendes Ergebnis hat.

    Ob die Ausführung parallel oder sequenziell erfolgt, liegt bei Ihnen, da Claude dies nicht festlegt. Die Antwort gibt an, was aufgerufen werden soll, nicht wie dies geplant werden muss. Unabhängige Aufrufe, wie die Abfragen des Kalenders und des Wetters, können gleichzeitig ausgeführt werden, um die Latenz zu verringern. Wenn einer von ihnen von dem Ergebnis eines anderen abhängt, sollten sie nacheinander ausgeführt werden. Das Modell deutet auf Abhängigkeiten hin, indem es unabhängige Aufgaben in parallele Blöcke gruppiert und abhängige Aufgaben auf einen späteren Zeitpunkt verschiebt – genau das geschieht in der zweiten Iteration. Threads, Asynchrone Verarbeitung oder eine Job-Queue sind Entscheidungen Ihres Loops, nicht der API.

    Betrachten Sie die Ausführung in der Produktion als unzuverlässige Eingabe/Ausgabe-Operationen, die fehlschlagen können:

    • Legen Sie jedem Tool eine Zeitüberschreitung fest, damit ein einzelner langsamer Aufruf den gesamten Ablauf nicht blockiert.
    • Wählen Sie bei Möglichkeit idempotente Operationen, da Wiederholungen und Neuausführungen bei einem Agent unvermeidlich sind.
  • Fehler nacheinander abfangen. Wenn eines von zwei parallelen Tools einen Fehler auslöst, sollte dennoch ein Ergebnis für dieses Tool zurückgesendet werden (mehr dazu unter is_error weiter unten), anstatt den Ablauf abzubrechen.
  • Die Schleife messen. Latenz pro Tool, Anzahl der Aufrufe, Tokenverbrauch sowie Fehlerraten zeigen an, ob ein Agent funktionsfähig ist oder allmählich schlechter wird.
  • 5. Schritte vor und nach dem Ausführen eines Tools

    Die Verantwortung für die Schleife bedeutet, zwei Phasen zu verwalten: die Zeit zwischen „Claude hat ein Tool angefordert“ und „das Tool wurde ausgeführt“ sowie die Zeit zwischen „das Tool wurde ausgeführt“ und „das Ergebnis wurde zurückgesendet“. Sie verdienen Namen, denn wie gut sie gestaltet sind, macht den größten Unterschied zwischen einem sicheren und einem riskanten Agenten aus.

    Ein Vor-Tool-Nutzungsschritt wird vor der Ausführung durchgeführt. Er prüft den angeforderten Aufruf und entscheidet, ob er unverändert ausgeführt, geändert oder abgelehnt werden soll. Hier findet die Durchsetzung statt, wobei Claude Vorschläge macht und Ihr Code die Entscheidung trifft.

    Ein Nach-Tool-Nutzungsschritt wird nach der Ausführung und vor der Rückgabe des Ergebnisses an Claude ausgeführt. Er verarbeitet die Rohausgabe, indem er sie redigiert, kürzt, umformattet oder protokolliert.

    Innerhalb einer Client-SDK-Schleife sind dies einfach Funktionen, die die Ausführung umschließen:

    for block in tool_calls:
        if not pre_tool_use(block):                       # validate / guard
            results.append(error_result(block.id, "Blocked by policy."))
            continue
        output = execute(block.name, block.input)         # run the tool
        output = post_tool_use(block, output)             # redact / log / reshape
        results.append(tool_result(block.id, output))
    

    Der Schritt vor der Tool-Nutzung ist der Ort, an dem die eigentlichen Schutzmaßnahmen liegen, und es ist die Aufgabe des Implementierers, nicht der des Modells. Häufige Produktionsmuster:

    • Überprüfen Sie die Argumente sowohl nach Ihrer eigenen Richtlinie als auch nach dem Schema.
    • Weigern Sie sich entschieden gegenüber zerstörerischen Operationen: rm -rf für ein Shell-Tool, DROP TABLE für ein Datenbank-Tool.
    • Lassen Sie eine Person alles von hoher Auswirkung genehmigen, wie zum Beispiel das Schreiben in die Produktionsumgebung.
    • Entfernen Sie Geheimnisse aus den Argumenten, bevor sie an einen externen Dienst gesendet werden.
    • Protokollieren Sie jeden versuchten Aufruf, damit Audits und Compliance-Prüfungen einen Überblick haben.

    Im Anschluss kümmert sich der Schritt nach der Tool-Nutzung um das Ergebnis, indem er Zugangsdaten oder personenbezogene Daten entfernt, bevor die Ergebnisse in den Kontext gelangen, übermäßig große Datenmengen kürzt und die Ergebnisse aufzeichnet.

    6. Rückgabe der Ergebnisse

    Antworten Sie auf einen tool_use-Schritt mit einer user-Nachricht, die eine Liste von tool_result-Blöcken enthält – jeweils einen pro tool_use-Block in der Antwort, wobei jeder Block mit seinem tool_use_id verknüpft ist. Fügen Sie zunächst den Schritt des Assistenten der laufenden Nachrichtenliste hinzu und danach die Ergebnisse als neuen Benutzerschritt. Die Iteration eins sieht so aus:

    {
      "role": "user",
      "content": [
        {
            "type": "tool_result",
            "tool_use_id": "toolu_01Cal",
            "content": "{\"start\": \"2026-07-14T15:00\", \"location\": \"Canary Wharf, London\"}"
        },
        {
            "type": "tool_result",
            "tool_use_id": "toolu_01Wx",
            "content": "{\"condition\": \"rain\", \"temp_c\": 12}"
        }
      ]
    }
    

    Zwei Formen des Inhalts. Der content eines Ergebnisses kann ein einfacher String sein, der serialisierte Rückgabewert wie im Beispiel, oder eine Liste von Inhaltsteilen. Die Teile enthalten mehr als nur Text, da text und image gemischt werden können, wodurch ein Diagramm- oder Screenshot-Tool Claude ein echtes Bild liefern kann. Strings eignen sich für skalare und JSON-Daten, während Listen von Teilen für multimodale Ausgaben geeignet sind.

    Sagen Sie klar, wenn etwas fehlschlägt. Markieren Sie einen fehlgeschlagenen Aufruf mit is_error: true sowie einer erklärenden Nachricht wie „Fehler: Es wurde kein Kalenderevent gefunden, das der Anfrage entspricht“, niemals einen leeren Wert oder einfach nur „Fehler“. Von allen Gewohnheiten im Umgang mit Ergebnissen ist diese am wichtigsten. Ein klarer Fehler ermöglicht es Claude, mit anderen Argumenten erneut zu versuchen, ein anderes Tool auszuwählen oder dem Benutzer mitzuteilen, was passiert ist, während ein versteckter Fehler dazu führt, dass der Prozess stecken bleibt. Ein umfangreiches Ergebnis kann außerdem cache_control enthalten, wodurch später Kosten für eine erneute Verarbeitung eingespart werden.

    Das Fortsetzungsvertrag

    Drei strenge Regeln, von denen jede ein häufiger Fehlerpunkt darstellt:

    • Ein tool_result pro tool_use. Wenn einer weggelassen wird, scheitert die Anfrage mit einem 400-Fehler, da die Modelle für jeden von ihnen ausgegebenen Toolaufruf eine eins-zu-eins-Antwort erwarten.
    • Senden Sie denselben tools-Array erneut. Jeder Anfrage, der tool_use- oder tool_result-Blöcke enthält, muss die Tools definieren, auf die sie verweisen, andernfalls wird sie abgelehnt.
    • Die Ergebnisse bilden eine eigene Turnierung. Liefern Sie die tool_result-Blöcke als Benachrichtigung an den Benutzer, platziert am Anfang ihres Inhalts. Nachfolgende Anweisungen in dieser Turnierung sind nicht zulässig. Jede neue Anweisung wird in einer separaten Benachrichtigung gesendet, sobald die Tool-Turnierung abgeschlossen ist.

    Jedes Ergebnis ist als unzuverlässiger Eingang zu betrachten

    Ein tool_result ist keine neutrale Datenmenge. Es handelt sich um Text, der in den Kontext des Modells eingeht und den nächsten Schritt beeinflusst. Egal, ob er aus dem öffentlichen Internet stammt, aus einem von einem Benutzer bereitgestellten Dokument oder aus einem System, das nicht vollständig unter Ihrer Kontrolle steht, kann er injizierte Anweisungen enthalten, die dazu dienen, den Agenten zu manipulieren – beispielsweise den Befehl, frühere Anweisungen zu ignorieren und die Datenbank zu versenden. Das Modell könnte diesem Befehl folgen. Das ist Prompt-Injection, und in einem agierenden Loop stellt dies ein reales Produktionsrisiko dar, kein hypothetisches.

    Abwehrmaßnahmen sind strukturell geprägt und befinden sich innerhalb des von Ihnen geschriebenen Loops:

    • Geben Sie dem Agenten nur die geringsten Berechtigungen, die er benötigt. Ein Tool, das ihm fehlt, bedeutet, dass er nicht dazu manipuliert werden kann, eine bestimmte Aktion auszuführen.
    • Führen Sie risikoreiche Tools in einer Sandbox aus.
    • Sanitisieren bedeutet, Ausgaben in Aktionen umzuwandeln, beispielsweise indem Dateipfade gegenüber einem festen Verzeichnis abgeglichen werden, um das Durchwandern zu verhindern.
    • Lassen Sie den Schritt nach der Tool-Nutzung streichen, indem alles entfernt wird, was wie eine Anweisung und nicht wie Daten aussieht.
    • Alles mit echten Konsequenzen sollte hinter menschlicher Freigabe stehen.

    Ein Tool-Ergebnis sollte niemals in der Lage sein, etwas zu autorisieren, was der Tool-Aufruf selbst nicht kann.

    Betrachten Sie die Ergebnisse auch als Kontext, den Sie kuratieren. Jedes Ergebnistoken bleibt für den Rest des Gesprächs im Fenster, daher sollten kurze, gut strukturierte Ausgaben angestrebt werden: konsistentes JSON oder beschriftete Felder sind besser als Prosa, die das Modell entschlüsseln muss. Schleifen, die viele Ergebnisse anhäufen, können die Tool-Ergebnis-Löschfunktion nutzen, eine Beta-Funktion zur Kontextverwaltung, die veraltete Ergebnisse entfernt, wenn die Grenze näher rückt. Verwenden Sie sie, bevor die Schleife groß genug wird, um das Fenster zu überfüllen.

    7. Zweite Iteration: eine abhängige Aufrufung

    Sowohl die Ergebnisse als auch die notwendigen Daten sind zurückgekehrt, weshalb die API erneut aufgerufen wird – diesmal mit der gesamten Nachrichtenliste sowie den Tool-Definitionen. Die Kalenderantwort gibt 15:00 Uhr in Canary Wharf an, und die Wettervorhersage sagt Regen voraus; dennoch kann die API nicht angeben, wann losgefahren werden soll, da die Reisezeit von einem Ort abhängt, den sie gerade erst erfahren hat. Diese Abhängigkeit ist der Grund, warum der Aufruf in der ersten Iteration nicht parallel durchgeführt werden konnte. Er musste in einem späteren Schritt erfolgen.

    {
      "role": "assistant",
      "stop_reason": "tool_use",
      "content": [
        {
          "type": "tool_use",
          "id": "toolu_02Tt",
          "name": "get_travel_time",
          "input": {
            "origin": "home",
            "destination": "Canary Wharf, London"
          }
        }
      ]
    }
    

    Man führt das Tool durch denselben Ablauf von Prüfung vor der Nutzung, Ausführung und Verarbeitung nach der Nutzung und gibt das einzige Ergebnis zurück:

    {
      "role": "user",
      "content": [
        { "type": "tool_result", "tool_use_id": "toolu_02Tt", "content": "{\"minutes\": 45}" }
      ]
    }
    

    Die Struktur der Schleife entspricht der ersten Iteration. Nur die Anzahl der Aufrufe sowie ihre Abhängigkeiten unterscheiden sich. Das ist das Muster, das man sich merken sollte: Die Schleife ändert von Durchlauf zu Durchlauf ihre Form nicht und wiederholt sich, bis Claude aufhört, Fragen zu stellen.

    8. Dritte Iteration: Synthese und end_turn

    Der dritte API-Aufruf zeigt, dass Claude bereits alle benötigten Fakten besitzt. Es werden keine weiteren Tools angefordert, daher schreibt es die Antwort. end_turn ersetzt den zuvor genannten Stoppgrund, und die Schleife endet.

    {
      "role": "assistant",
      "stop_reason": "end_turn",
      "content": [
        {
          "type": "text",
          "text": "Yes, bring an umbrella — rain is forecast in London tomorrow, around 12°C. Your meeting is at 3:00 PM in Canary Wharf, roughly 45 minutes away, so leave home by about 2:00 PM to arrive with a buffer."
        }
      ]
    }
    

    Insgesamt sind das drei Iterationen: zwei parallele Aufrufe, ein abhängiger Aufruf und eine Synthese. Das Modell entscheidet, was und wann abgerufen werden soll, und Ihr Code bestimmt, wie jeder Aufruf abläuft, ob er erlaubt ist und wie die Ergebnisse zurückgegeben werden. Der Kontext wächst bei jedem Schritt, da die gesamte Historie erneut übermittelt wird, doch drei Schritte passen problemlos in den Rahmen.

    9. Der gesamte Loop im Code

    Alles, was bisher beschrieben wurde, fasst sich auf einen Loop im Client SDK zusammen. Er prüft stop_reason, leitet jedes angeforderte Tool über Ihre Vor- und Nachschrittanweisungen für die Tool-Nutzung, antwortet auf jeden Aufruf mit einem Ergebnis und setzt die Verarbeitung fort, bis Claude fertig ist.

    import anthropic
    client = anthropic.Anthropic()
    
    messages = [{"role": "user", "content": user_request}]
    MAX_ITERATIONS = 10
    for _ in range(MAX_ITERATIONS):
        response = client.messages.create(
            model="claude-opus-4-8", max_tokens=1024, tools=tools, messages=messages,
        )
        messages.append({"role": "assistant", "content": response.content})
        if response.stop_reason != "tool_use":
            break   # end_turn (or another reason): done
        results = []
        for block in (b for b in response.content if b.type == "tool_use"):
            if not pre_tool_use(block):   # your guard - may block the call
                results.append({"type": "tool_result", "tool_use_id": block.id,
                                "content": "Blocked by policy.", "is_error": True})
                continue
            try:
                output = execute(block.name, block.input)   # run it (concurrently if independent)
                output = post_tool_use(block, output)   # redact / log / reshape
                results.append({"type": "tool_result", "tool_use_id": block.id, "content": output})
            except Exception as e:
                results.append({"type": "tool_result", "tool_use_id": block.id,
                                "content": f"Error: {e}", "is_error": True})
        messages.append({"role": "user", "content": results})   # one result per tool_use
    print(response.content[-1].text)
    

    Die Schleife erläutert einige Punkte. Sie halten selbst die messages bereit, da die API keinen Zustand speichert. Jeder stop_reason außer tool_use beendet die Schleife. Eine feste Iterationsgrenze verhindert, dass ein Agent außer Kontrolle gerät, daher sollte man in der Produktion niemals eine unbegrenzte Schleife verwenden. Alle Arten von Fehlern, blockierte Aufrufe sowie Ausnahmen werden als is_error-Werte zurückgegeben, anstatt den Ablauf zu stören. Der fertige Code berücksichtigt außerdem max_tokens (ein abgebrochener Ablauf – erhöhen Sie daher die Grenze oder fahren Sie fort) sowie pause_turn (einen Server-Tool-Ablauf, der erneut gesendet werden muss). Beides kann innerhalb derselben Schleife auftreten.

    Erinnerungs-Checkliste

    • Tools werden im tools-Array mit name, description und input_schema deklariert, und jeder Anfrage werden Tokens für die Eingabedaten zu diesen Definitionen abgezogen.
    • tool_choice bestimmt, ob ein Tool aufgerufen wird: auto, any, tool oder none. Erweitertes Denken funktioniert nur mit auto und none, und strict: true zwingt die Argumente dazu, exakt dem Schema zu entsprechen.
    • Ein stop_reason von "tool_use" gibt Ihnen die Kontrolle zurück. Erkennen Sie Aufrufe, indem Sie content nach type == "tool_use" filtern – niemals nach Position.
    • Paralleler Tool-Use bedeutet mehrere tool_use-Blöcke in einer Antwort. Die Ausführungsreihenfolge, ob parallel oder sequenziell, liegt bei Ihnen und nicht beim Modell. Abhängige Aufrufe erfolgen in späteren Schritten.
    • Führen Sie alle angeforderten Tools aus und antworten Sie einmal: Eine einzige Benutzeraktion, bei der für jede tool_use ein tool_result über tool_use_id abgeglichen wird, wobei der tools-Array unverändert bleibt. Fehlt ein Ergebnis, wird 400 zurückgegeben.
    • Ihre Verantwortung liegt bei den Lücken während der Ausführung. Validieren und schützen Sie vor dem Ausführen sowie verarbeiten und redigieren Sie danach. Das sind Schritte, die Sie selbst programmieren, keine Funktionen, die Sie konfigurieren.
    • tool_result.content kann ein String oder eine Blockliste sein. Bei Fehlern setzen Sie is_error: true zusammen mit einer hilfreichen Nachricht und halten Sie die Ergebnisse kurz und strukturiert.
    • Betrachten Sie Tool-Ergebnisse als unzuverlässigen Kontext. Mindestberechtigungen, Sandboxes, Sanitierung sowie menschliche Freigabe bei bedeutenden Aktionen sind die Lösung gegen Prompt-Injection.
    • Die Schleife läuft bis zu end_turn, behält ihren eigenen Zustand bei und benötigt eine feste Obergrenze für die Anzahl der Iterationen.

    Verwandte Artikel

  • Praktische Hinweise: Inside ARD – Wie die Agentic Resource Discovery Spec tatsächlich funktioniert — Detaillierte Anleitung zu den Praktischen Hinweisen: Inside ARD – Wie die Agentic Resource Discovery Spec tatsächlich funktioniert: Verträge, Überprüfungen sowie Code-Blöcke für Teams, die dieses Muster einsetzen.