Claude Platform Docs
  • Messages
  • Managed Agents
  • Admin

Search...
⌘K
Erste Schritte
Einführung in ClaudeSchnellstart
Entwickeln mit Claude
FunktionsübersichtVerwendung der Messages APIStop-Gründe und FallbackAblehnungen und FallbackFallback-Guthaben
Modellfähigkeiten
Erweitertes DenkenAdaptives DenkenEffortAufgabenbudgets (Beta)Schnellmodus (Forschungsvorschau)Strukturierte AusgabenZitateStreaming von MessagesBatch-VerarbeitungSuchergebnisseStreaming von AblehnungenMehrsprachige UnterstützungEmbeddings
Tools
ÜbersichtFunktionsweise der Tool-NutzungTutorial: Einen Tool-nutzenden Agenten erstellenTools definierenTool-Aufrufe verarbeitenParallele Tool-NutzungTool Runner (SDK)Strikte Tool-NutzungServer-ToolsWebsuche-ToolWeb-Fetch-ToolCodeausführungs-ToolAdvisor-ToolTool-Suche-ToolMemory-ToolBash-ToolTexteditor-ToolComputer-Use-ToolFehlerbehebung
Tool-Infrastruktur
Tool-ReferenzTool-Kontext verwaltenTool-KombinationenTool-Nutzung mit Prompt-CachingProgrammatischer Tool-AufrufFeingranulares Tool-Streaming
Kontextverwaltung
KontextfensterKompaktierungKontextbearbeitungPrompt-CachingSystemnachrichten während der KonversationEinen Orchestrierungsmodus erstellenCache-Diagnose (Beta)Token-Zählung
Arbeiten mit Dateien
Files APIPDF-Unterstützung
Skills
ÜbersichtSchnellstartBest PracticesSkills für UnternehmenSkills in der API
MCP
Remote-MCP-ServerMCP-Connector
Claude auf Cloud-Plattformen
Amazon BedrockAmazon Bedrock (Legacy)Claude Platform auf AWSGoogle CloudMicrosoft Foundry

Log in
Tutorial: Einen Tool-nutzenden Agenten erstellen
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Claude Platform Docs

Solutions

  • AI agents
  • Code modernization
  • Coding
  • Customer support
  • Education
  • Financial services
  • Government
  • Life sciences

Partners

  • Claude on AWS
  • Claude on Google Cloud

Learn

  • Blog
  • Courses
  • Use cases
  • Connectors
  • Customer stories
  • Engineering at Anthropic
  • Events
  • Powered by Claude
  • Service partners
  • Startups program

Company

  • Anthropic
  • Careers
  • Economic Futures
  • Research
  • News
  • Responsible Scaling Policy
  • Security and compliance
  • Transparency

Learn

  • Blog
  • Courses
  • Use cases
  • Connectors
  • Customer stories
  • Engineering at Anthropic
  • Events
  • Powered by Claude
  • Service partners
  • Startups program

Help and security

  • Availability
  • Status
  • Support
  • Discord

Terms and policies

  • Privacy policy
  • Responsible disclosure policy
  • Terms of service: Commercial
  • Terms of service: Consumer
  • Usage policy
Messages/Tools

Tutorial: Einen Tool-nutzenden Agenten erstellen

Eine geführte Schritt-für-Schritt-Anleitung von einem einzelnen Tool-Aufruf bis zu einer produktionsreifen agentischen Schleife.

Dieses Tutorial baut einen Kalenderverwaltungs-Agenten in fünf konzentrischen Ringen auf. Jeder Ring ist ein vollständiges, lauffähiges Programm, das genau ein Konzept zum vorherigen Ring hinzufügt. Am Ende wirst du die agentische Schleife von Hand geschrieben und sie dann durch die Tool-Runner-SDK-Abstraktion ersetzt haben.

Das Beispiel-Tool ist create_calendar_event. Sein Schema verwendet verschachtelte Objekte, Arrays und optionale Felder, sodass du sehen wirst, wie Claude mit realistischen Eingabeformen umgeht, statt nur mit einem einzelnen flachen String.



Jeder Ring läuft eigenständig. Kopiere einen beliebigen Ring in eine neue Datei, und er wird ohne den Code aus früheren Ringen ausgeführt.

Ring 1: Ein Tool, ein Turn

Das kleinstmögliche Tool-nutzende Programm: ein Tool, eine Benutzernachricht, ein Tool-Aufruf, ein Ergebnis. Der Code ist ausführlich kommentiert, damit du jede Zeile dem Tool-Nutzungs-Lebenszyklus zuordnen kannst.

Die Anfrage sendet ein tools-Array zusammen mit der Benutzernachricht. Wenn Claude sich entscheidet, ein Tool aufzurufen, kommt die Antwort mit stop_reason: "tool_use" und einem tool_use-Content-Block zurück, der den Tool-Namen, eine eindeutige id und den strukturierten input enthält. Dein Code führt das Tool aus und sendet dann das Ergebnis in einem tool_result-Block zurück, dessen tool_use_id mit der id aus dem Aufruf übereinstimmt.

# Ring 1: Einzelnes Tool, einzelner Turn.

import json

import anthropic

# Erstelle einen Client. Er liest ANTHROPIC_API_KEY aus der Umgebung.
client = anthropic.Anthropic()

# Definiere ein Tool. Das input_schema ist ein JSON-Schema-Objekt, das
# die Argumente beschreibt, die Claude beim Aufruf dieses Tools übergeben soll.
# Dieses Schema enthält verschachtelte Objekte (recurrence), Arrays (attendees)
# und optionale Felder – näher an realen Tools als ein flaches String-Argument.
tools = [
    {
        "name": "create_calendar_event",
        "description": "Create a calendar event with attendees and optional recurrence.",
        "input_schema": {
            "type": "object",
            "properties": {
                "title": {"type": "string"},
                "start": {"type": "string", "format": "date-time"},
                "end": {"type": "string", "format": "date-time"},
                "attendees": {
                    "type": "array",
                    "items": {"type": "string", "format": "email"},
                },
                "recurrence": {
                    "type": "object",
                    "properties": {
                        "frequency": {"enum": ["daily", "weekly", "monthly"]},
                        "count": {"type": "integer", "minimum": 1},
                    },
                },
            },
            "required": ["title", "start", "end"],
        },
    }
]

# Sende die Anfrage des Nutzers zusammen mit der Tool-Definition. Claude entscheidet
# anhand der Anfrage und der Tool-Beschreibung, ob es das Tool aufruft.
response = client.messages.create(
    model="claude-opus-4-8",
    max_tokens=1024,
    tools=tools,
    tool_choice={"type": "auto", "disable_parallel_tool_use": True},
    messages=[
        {
            "role": "user",
            "content": "Schedule a 30-minute sync with [email protected] and [email protected] next Monday at 10am.",
        }
    ],
)

# Wenn Claude ein Tool aufruft, hat die Antwort den stop_reason "tool_use"
# und das content-Array enthält neben etwaigem Text einen tool_use-Block.
print(f"stop_reason: {response.stop_reason}")

# Finde den tool_use-Block. Eine Antwort kann Textblöcke vor dem tool_use-Block
# enthalten, also durchsuche das content-Array, statt eine Position anzunehmen.
tool_use = next(block for block in response.content if block.type == "tool_use")
print(f"Tool: {tool_use.name}")
print(f"Input: {tool_use.input}")

# Führe das Tool aus. In einem echten System würde dies deine Kalender-API aufrufen.
# Hier ist das Ergebnis hartcodiert, damit das Beispiel in sich geschlossen bleibt.
result = {"event_id": "evt_123", "status": "created"}

# Sende das Ergebnis zurück. Der tool_result-Block gehört in eine user-Nachricht und
# seine tool_use_id muss mit der id aus dem obigen tool_use-Block übereinstimmen. Die
# vorherige Antwort des Assistenten wird mitgesendet, damit Claude den vollen Verlauf hat.
followup = client.messages.create(
    model="claude-opus-4-8",
    max_tokens=1024,
    tools=tools,
    tool_choice={"type": "auto", "disable_parallel_tool_use": True},
    messages=[
        {
            "role": "user",
            "content": "Schedule a 30-minute sync with [email protected] and [email protected] next Monday at 10am.",
        },
        {"role": "assistant", "content": response.content},
        {
            "role": "user",
            "content": [
                {
                    "type": "tool_result",
                    "tool_use_id": tool_use.id,
                    "content": json.dumps(result),
                }
            ],
        },
    ],
)

# Mit dem Tool-Ergebnis in der Hand erzeugt Claude eine finale Antwort in natürlicher
# Sprache und stop_reason wird zu "end_turn".
print(f"stop_reason: {followup.stop_reason}")
final_text = next(block for block in followup.content if block.type == "text")
print(final_text.text)

Was du erwarten kannst

Output
stop_reason: tool_use
Tool: create_calendar_event
Input: {'title': 'Sync', 'start': '2026-03-30T10:00:00', 'end': '2026-03-30T10:30:00', 'attendees': ['[email protected]', '[email protected]']}
stop_reason: end_turn
I've scheduled your 30-minute sync with Alice and Bob for next Monday at 10am.

Der erste stop_reason ist tool_use, weil Claude auf das Kalenderergebnis wartet. Nachdem du das Ergebnis gesendet hast, ist der zweite stop_reason end_turn, und der Inhalt ist natürliche Sprache für den Benutzer.

Ring 2: Die agentische Schleife

Ring 1 ging davon aus, dass Claude das Tool genau einmal aufrufen würde. Echte Aufgaben benötigen oft mehrere Aufrufe: Claude könnte ein Ereignis erstellen, die Bestätigung lesen und dann ein weiteres erstellen. Die Lösung ist eine while-Schleife, die weiterhin Tools ausführt und Ergebnisse zurückgibt, bis stop_reason nicht mehr "tool_use" ist.

Die andere Änderung ist der Gesprächsverlauf. Anstatt das messages-Array bei jeder Anfrage von Grund auf neu zu erstellen, führe eine fortlaufende Liste und hänge daran an. Jeder Turn sieht den vollständigen vorherigen Kontext.

# Ring 2: Die agentische Schleife.

import json

import anthropic

client = anthropic.Anthropic()

tools = [
    {
        "name": "create_calendar_event",
        "description": "Create a calendar event with attendees and optional recurrence.",
        "input_schema": {
            "type": "object",
            "properties": {
                "title": {"type": "string"},
                "start": {"type": "string", "format": "date-time"},
                "end": {"type": "string", "format": "date-time"},
                "attendees": {
                    "type": "array",
                    "items": {"type": "string", "format": "email"},
                },
                "recurrence": {
                    "type": "object",
                    "properties": {
                        "frequency": {"enum": ["daily", "weekly", "monthly"]},
                        "count": {"type": "integer", "minimum": 1},
                    },
                },
            },
            "required": ["title", "start", "end"],
        },
    }
]


def run_tool(name, tool_input):
    if name == "create_calendar_event":
        return {"event_id": "evt_123", "status": "created", "title": tool_input["title"]}
    return {"error": f"Unknown tool: {name}"}


# Bewahre den gesamten Gesprächsverlauf in einer Liste auf, damit jeder Turn den vorherigen Kontext sieht.
messages = [
    {
        "role": "user",
        "content": "Schedule a weekly team standup every Monday at 9am for the next 4 weeks. Invite the whole team: [email protected], [email protected], [email protected].",
    }
]

response = client.messages.create(
    model="claude-opus-4-8",
    max_tokens=1024,
    tools=tools,
    tool_choice={"type": "auto", "disable_parallel_tool_use": True},
    messages=messages,
)

# Schleife, bis Claude keine Tools mehr anfordert. Jede Iteration führt das angeforderte
# Tool aus, hängt das Ergebnis an den Verlauf an und bittet Claude fortzufahren.
while response.stop_reason == "tool_use":
    tool_use = next(block for block in response.content if block.type == "tool_use")
    result = run_tool(tool_use.name, tool_use.input)

    messages.append({"role": "assistant", "content": response.content})
    messages.append(
        {
            "role": "user",
            "content": [
                {
                    "type": "tool_result",
                    "tool_use_id": tool_use.id,
                    "content": json.dumps(result),
                }
            ],
        }
    )

    response = client.messages.create(
        model="claude-opus-4-8",
        max_tokens=1024,
        tools=tools,
        tool_choice={"type": "auto", "disable_parallel_tool_use": True},
        messages=messages,
    )

final_text = next(block for block in response.content if block.type == "text")
print(final_text.text)

Was du erwarten kannst

Output
I've set up your weekly team standup for the next 4 Mondays at 9am with Alice, Bob, and Carol invited.

Die Schleife könnte einmal oder mehrmals durchlaufen, je nachdem, wie Claude die Aufgabe aufteilt. Dein Code muss das nicht mehr im Voraus wissen.

Ring 3: Mehrere Tools, parallele Aufrufe

Agenten haben selten nur eine Fähigkeit. Füge ein zweites Tool hinzu, list_calendar_events, damit Claude den bestehenden Zeitplan überprüfen kann, bevor etwas Neues erstellt wird.

Wenn Claude mehrere unabhängige Tool-Aufrufe zu machen hat, könnte es mehrere tool_use-Blöcke in einer einzigen Antwort zurückgeben. Deine Schleife muss alle davon verarbeiten und alle Ergebnisse zusammen in einer Benutzernachricht zurücksenden. Iteriere über jeden tool_use-Block in response.content, nicht nur über den ersten.

# Ring 3: Mehrere Tools, parallele Aufrufe.

import json

import anthropic

client = anthropic.Anthropic()

tools = [
    {
        "name": "create_calendar_event",
        "description": "Create a calendar event with attendees and optional recurrence.",
        "input_schema": {
            "type": "object",
            "properties": {
                "title": {"type": "string"},
                "start": {"type": "string", "format": "date-time"},
                "end": {"type": "string", "format": "date-time"},
                "attendees": {
                    "type": "array",
                    "items": {"type": "string", "format": "email"},
                },
                "recurrence": {
                    "type": "object",
                    "properties": {
                        "frequency": {"enum": ["daily", "weekly", "monthly"]},
                        "count": {"type": "integer", "minimum": 1},
                    },
                },
            },
            "required": ["title", "start", "end"],
        },
    },
    {
        "name": "list_calendar_events",
        "description": "List all calendar events on a given date.",
        "input_schema": {
            "type": "object",
            "properties": {
                "date": {"type": "string", "format": "date"},
            },
            "required": ["date"],
        },
    },
]


def run_tool(name, tool_input):
    if name == "create_calendar_event":
        return {"event_id": "evt_123", "status": "created", "title": tool_input["title"]}
    if name == "list_calendar_events":
        return {"events": [{"title": "Existing meeting", "start": "14:00", "end": "15:00"}]}
    return {"error": f"Unknown tool: {name}"}


messages = [
    {
        "role": "user",
        "content": "Check what I have next Monday, then schedule a planning session that avoids any conflicts.",
    }
]

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

while response.stop_reason == "tool_use":
    # Eine einzelne Antwort kann mehrere tool_use-Blöcke enthalten. Verarbeite alle
    # und gib alle Ergebnisse zusammen in einer User-Nachricht zurück.
    tool_results = []
    for block in response.content:
        if block.type == "tool_use":
            result = run_tool(block.name, block.input)
            tool_results.append(
                {
                    "type": "tool_result",
                    "tool_use_id": block.id,
                    "content": json.dumps(result),
                }
            )

    messages.append({"role": "assistant", "content": response.content})
    messages.append({"role": "user", "content": tool_results})

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

final_text = next(block for block in response.content if block.type == "text")
print(final_text.text)

Was du erwarten kannst

Output
I checked your calendar for next Monday and found an existing meeting from 2pm to 3pm. I've scheduled the planning session for 10am to 11am to avoid the conflict.

Weitere Informationen zur gleichzeitigen Ausführung und zu Reihenfolgegarantien findest du unter Parallele Tool-Nutzung.

Ring 4: Fehlerbehandlung

Tools schlagen fehl. Eine Kalender-API könnte ein Ereignis mit zu vielen Teilnehmern ablehnen, oder ein Datum könnte falsch formatiert sein. Wenn ein Tool einen Fehler auslöst, sende die Fehlermeldung mit is_error: true zurück, anstatt abzustürzen. Claude liest den Fehler und kann es mit korrigierter Eingabe erneut versuchen, den Benutzer um Klärung bitten oder die Einschränkung erklären.

# Ring 4: Fehlerbehandlung.

import json

import anthropic

client = anthropic.Anthropic()

tools = [
    {
        "name": "create_calendar_event",
        "description": "Create a calendar event with attendees and optional recurrence.",
        "input_schema": {
            "type": "object",
            "properties": {
                "title": {"type": "string"},
                "start": {"type": "string", "format": "date-time"},
                "end": {"type": "string", "format": "date-time"},
                "attendees": {
                    "type": "array",
                    "items": {"type": "string", "format": "email"},
                },
                "recurrence": {
                    "type": "object",
                    "properties": {
                        "frequency": {"enum": ["daily", "weekly", "monthly"]},
                        "count": {"type": "integer", "minimum": 1},
                    },
                },
            },
            "required": ["title", "start", "end"],
        },
    },
    {
        "name": "list_calendar_events",
        "description": "List all calendar events on a given date.",
        "input_schema": {
            "type": "object",
            "properties": {
                "date": {"type": "string", "format": "date"},
            },
            "required": ["date"],
        },
    },
]


def run_tool(name, tool_input):
    if name == "create_calendar_event":
        if "attendees" in tool_input and len(tool_input["attendees"]) > 10:
            raise ValueError("Too many attendees (max 10)")
        return {"event_id": "evt_123", "status": "created", "title": tool_input["title"]}
    if name == "list_calendar_events":
        return {"events": [{"title": "Existing meeting", "start": "14:00", "end": "15:00"}]}
    raise ValueError(f"Unknown tool: {name}")


messages = [
    {
        "role": "user",
        "content": "Schedule an all-hands with everyone: " + ", ".join(f"user{i}@example.com" for i in range(15)),
    }
]

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

while response.stop_reason == "tool_use":
    tool_results = []
    for block in response.content:
        if block.type == "tool_use":
            try:
                result = run_tool(block.name, block.input)
                tool_results.append(
                    {"type": "tool_result", "tool_use_id": block.id, "content": json.dumps(result)}
                )
            except Exception as exc:
                # Signalisiere den Fehler, damit Claude es erneut versuchen oder um Klärung bitten kann.
                tool_results.append(
                    {
                        "type": "tool_result",
                        "tool_use_id": block.id,
                        "content": str(exc),
                        "is_error": True,
                    }
                )

    messages.append({"role": "assistant", "content": response.content})
    messages.append({"role": "user", "content": tool_results})

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

final_text = next(block for block in response.content if block.type == "text")
print(final_text.text)

Was du erwarten kannst

Output
I tried to schedule the all-hands but the calendar only allows 10 attendees per event. I can split this into two sessions, or you can let me know which 10 people to prioritize.

Das is_error-Flag ist der einzige Unterschied zu einem erfolgreichen Ergebnis. Claude sieht das Flag und den Fehlertext und reagiert entsprechend. Siehe Tool-Aufrufe verarbeiten für die vollständige Referenz zur Fehlerbehandlung.

Ring 5: Die Tool-Runner-SDK-Abstraktion

Die Ringe 2 bis 4 haben dieselbe Schleife von Hand geschrieben: die API aufrufen, stop_reason prüfen, Tools ausführen, Ergebnisse anhängen, wiederholen. Der Tool Runner erledigt das für dich. Definiere jedes Tool als Funktion, übergib die Liste an tool_runner und rufe die finale Nachricht ab, sobald die Schleife abgeschlossen ist. Fehler-Wrapping, Ergebnisformatierung und Gesprächsverwaltung werden intern gehandhabt.

Das Python-SDK verwendet den @beta_tool-Decorator, um das Schema aus Type-Hints und dem Docstring abzuleiten. Das TypeScript-SDK verwendet betaZodTool mit einem Zod-Schema. Die anderen SDKs folgen demselben Muster mit ihren eigenen Helfern: BetaRunnableTool in C# und PHP, typisierte Tool-Klassen in Java und Ruby und toolrunner.NewBetaToolFromJSONSchema in Go.



Tool Runner ist in allen sieben SDKs verfügbar: Python, TypeScript, C#, Go, Java, PHP und Ruby. Siehe Tool Runner für die vollständige Referenz. Die cURL- und CLI-Tabs zeigen einen Hinweis anstelle von Code; behalte die Ring-4-Schleife für curl- oder CLI-basierte Skripte bei.

# Ring 5: Die Tool-Runner-SDK-Abstraktion.

import json

import anthropic
from anthropic import beta_tool

client = anthropic.Anthropic()


@beta_tool
def create_calendar_event(
    title: str,
    start: str,
    end: str,
    attendees: list[str] | None = None,
    recurrence: dict | None = None,
) -> str:
    """Create a calendar event with attendees and optional recurrence.

    Args:
        title: Event title.
        start: Start time in ISO 8601 format.
        end: End time in ISO 8601 format.
        attendees: Email addresses to invite.
        recurrence: Dict with 'frequency' (daily, weekly, monthly) and 'count'.
    """
    if attendees and len(attendees) > 10:
        raise ValueError("Too many attendees (max 10)")
    return json.dumps({"event_id": "evt_123", "status": "created", "title": title})


@beta_tool
def list_calendar_events(date: str) -> str:
    """List all calendar events on a given date.

    Args:
        date: Date in YYYY-MM-DD format.
    """
    return json.dumps({"events": [{"title": "Existing meeting", "start": "14:00", "end": "15:00"}]})


final_message = client.beta.messages.tool_runner(
    model="claude-opus-4-8",
    max_tokens=1024,
    tools=[create_calendar_event, list_calendar_events],
    messages=[
        {
            "role": "user",
            "content": "Check what I have next Monday, then schedule a planning session that avoids any conflicts.",
        }
    ],
).until_done()

for block in final_message.content:
    if block.type == "text":
        print(block.text)

Was du erwarten kannst

Output
I checked your calendar for next Monday and found an existing meeting from 2pm to 3pm. I've scheduled the planning session for 10am to 11am to avoid the conflict.

Die Ausgabe ist identisch mit Ring 3. Der Unterschied liegt im Code: etwa die Hälfte der Zeilen, keine manuelle Schleife, und das Schema befindet sich direkt neben der Implementierung.

Was du gebaut hast

Du hast mit einem einzelnen hartcodierten Tool-Aufruf begonnen und mit einem produktionsreifen Agenten geendet, der mehrere Tools, parallele Aufrufe und Fehler handhabt, und hast all das dann in den Tool Runner zusammengefasst. Dabei hast du jeden Teil des Tool-Nutzungs-Protokolls gesehen: tool_use-Blöcke, tool_result-Blöcke, tool_use_id-Abgleich, stop_reason-Prüfung und is_error-Signalisierung.

Nächste Schritte

Tools definieren

Schema-Spezifikation und Best Practices.

Tool Runner im Detail

Die vollständige SDK-Abstraktionsreferenz.

Fehlerbehebung

Häufige Tool-Nutzungs-Fehler beheben.

Was this page helpful?

  • Ring 1: Ein Tool, ein Turn
  • Ring 2: Die agentische Schleife
  • Ring 3: Mehrere Tools, parallele Aufrufe
  • Ring 4: Fehlerbehandlung
  • Ring 5: Die Tool-Runner-SDK-Abstraktion
  • Was du gebaut hast
  • Nächste Schritte