Claude API Tool Use: Function Calling Anleitung für die Produktion

April 19, 2026 · 17 min read · claude-api, tool-use, function-calling, llm-tools
Claude API Tool Use: Function Calling Anleitung für die Produktion

Tool Use ist das Standardmuster für jede Claude-Workload jenseits von Chat. Wenn Sie etwas bauen, das aus einer Datenbank liest, eine API anspricht, eine Datei schreibt oder zwischen Logikzweigen entscheidet, sollten Sie Tools verwenden. Wenn nicht, prompten Sie wahrscheinlich zu viel und engineeren zu wenig.

Ich betreibe zehn Claude-basierte Agents in der Produktion als Bash-Skripte auf einem Debian-VPS. Jeder einzelne nutzt Tool Use, nicht Prompt Chaining, um zu entscheiden, was als Nächstes zu tun ist. Das Modell wählt ein Tool, ich führe es aus, ich gebe das Ergebnis zurück, das Modell macht weiter. Diese Schleife ist langweilig, vorhersagbar und debuggbar. Sie schlägt “JSON aus der freien Antwort des Modells parsen” jedes Mal.

Diese Anleitung ist das, was ich mir gewünscht hätte, als ich Claude zum ersten Mal an echte Systeme angebunden habe. Schemas, der Call Loop, parallele Calls, Streaming, MCP und die Failure Modes, die Sie in Woche drei einholen werden.

Was Tool Use tatsächlich ist

Tools sind typisierte Funktionssignaturen, die Sie dem Modell übergeben. Das Modell führt sie nicht aus. Es fordert einen Aufruf an. Sie fangen diese Anfrage ab, führen beliebigen Code in Ihrer Runtime aus, geben das Ergebnis zurück, und das Modell setzt die Argumentation mit diesem Ergebnis in seinem Context fort.

Diese Unterscheidung ist wichtig. Das Modell führt keinen Code auf den Servern von Anthropic aus. Jeder Tool-Aufruf ist ein Vertrag zwischen der Ausgabe des Modells und Ihrer Runtime. Sie bestimmen, was das Tool tut. Sie bestimmen, was als gültiges Ergebnis zählt. Sie entscheiden, ob erneut versucht, verweigert oder an einen Menschen eskaliert wird.

Das ist das mentale Modell, das Sie brauchen:

user message
  > model: "I want to call tool X with args {...}"
  > your code: execute X, get result
  > back to model: "here is the result"
  > model: either calls more tools, or returns final answer

Ein Tool kann alles sein, was sich als Funktion ausdrücken lässt. Einen Nutzer per E-Mail suchen. Eine Karte belasten. Eine Vector-DB abfragen. Eine Datei lesen. Eine Telegram-Nachricht senden. Wenn Ihre Runtime es kann, kann das Modell es anfordern.

Anatomie einer Tool-Definition

Jedes Tool, das Sie an Claude senden, hat drei Felder:

{
  name: "lookup_order",
  description: "Look up an order by its order ID...",
  input_schema: {
    type: "object",
    properties: { order_id: { type: "string" } },
    required: ["order_id"],
  },
}

Der name ist ein Identifier. Verwenden Sie snake_case und halten Sie ihn über Versionen hinweg stabil.

Die description ist das, was das Modell tatsächlich liest, wenn es entscheidet, ob es dieses Tool aufrufen soll. Behandeln Sie sie wie einen Funktions-Docstring. Schreiben Sie, wann sie verwendet werden soll, wann nicht, und fügen Sie ein kurzes Beispiel für Sonderfälle hinzu. Eine vage Beschreibung (“sucht Bestellungen”) führt dazu, dass das Modell das Tool zur falschen Zeit aufruft oder den richtigen Moment ganz verpasst. Eine präzise Beschreibung (“Look up an order by its internal order ID. Use this when the user provides an order ID that starts with ORD-. Do not use this for customer email lookups; use lookup_customer for that.”) gibt dem Modell etwas, womit es arbeiten kann.

Das input_schema ist JSON Schema. Hier lassen die meisten Leute Wert auf dem Tisch liegen. Wenn ein Feld nur einen von fünf Werten haben soll, verwenden Sie enum. Wenn ein String ein Format hat, deklarieren Sie es. Wenn ein Feld Pflicht ist, listen Sie es in required auf. Je enger Ihr Schema, desto weniger halluziniert das Modell Formen, mit denen Sie nicht umgehen können.

Eine solide Tool-Definition sieht so aus:

{
  name: "create_ticket",
  description:
    "Create a customer support ticket. Use this after you have " +
    "confirmed the customer's identity and collected the issue " +
    "description. Do not call this to log internal notes; use " +
    "`add_internal_note` for that. Example: user reports a broken " +
    "checkout flow, you call this with category='checkout', " +
    "priority='high'.",
  input_schema: {
    type: "object",
    properties: {
      customer_id: { type: "string", description: "Internal customer ID." },
      category: {
        type: "string",
        enum: ["checkout", "shipping", "billing", "account", "other"],
      },
      priority: {
        type: "string",
        enum: ["low", "normal", "high", "urgent"],
      },
      summary: { type: "string", maxLength: 200 },
    },
    required: ["customer_id", "category", "priority", "summary"],
  },
}

Jedes produktionsreife Tool, das ich ausgeliefert habe, folgte grob dieser Form. Wenn Ihr Schema einen TypeScript-Compile nicht überstehen würde, ist es nicht eng genug.

Tool-Choice-Strategien

Der Parameter tool_choice steuert, wie das Modell entscheidet, ob es Tools überhaupt einsetzt.

{ "type": "auto" } ist der Standard. Das Modell entscheidet. Es kann direkt antworten, ohne ein Tool aufzurufen, oder es kann ein oder mehrere Tools aufrufen. Verwenden Sie dies für allgemeine Agents, die manchmal chatten und manchmal handeln.

{ "type": "any" } zwingt das Modell, irgendein Tool aufzurufen, lässt ihm aber die Wahl, welches. Verwenden Sie dies, wenn das Modell eine Entscheidung als Tool-Aufruf ausdrücken soll und Sie niemals eine freie Antwort wollen.

{ "type": "tool", "name": "specific_tool" } erzwingt ein bestimmtes Tool. Das ist das Muster, das ich für strukturierte Ausgabe verwende. Geben Sie dem Modell ein Tool, dessen Schema die gewünschte Rückgabeform ist, erzwingen Sie dieses Tool, parsen Sie die Argumente. Zuverlässiger als Prefill-and-Parse, wenn Sie das Schema wirklich brauchen. Siehe Claude API structured output für den vollständigen Vergleich von Tool-Forcing gegenüber Prefill.

{ "type": "none" } deaktiviert Tools für diesen Turn. Nützlich, wenn das Modell zusammenfassen oder erklären soll, ohne eine Aktion auszuführen.

Der Call Loop

Hier ist die Schleife, die jeder Tool-nutzende Agent ausführt, als Pseudocode:

messages = [user_message]
while iterations < budget:
  response = claude.messages.create(tools=TOOLS, messages=messages, ...)
  messages.append({ role: "assistant", content: response.content })
  if response.stop_reason == "end_turn":
    return response
  if response.stop_reason == "tool_use":
    tool_results = []
    for block in response.content:
      if block.type == "tool_use":
        result = execute(block.name, block.input)
        tool_results.append({
          type: "tool_result",
          tool_use_id: block.id,
          content: result,
        })
    messages.append({ role: "user", content: tool_results })
  iterations += 1

Zwei Stop-Reasons sind hier relevant. end_turn bedeutet, dass das Modell fertig ist und der letzte Textblock die Antwort ist. tool_use bedeutet, dass das Modell ein oder mehrere Tools aufrufen möchte. Bei tool_use führen Sie jeden tool_use-Block in der Antwort aus, verpacken jedes Ergebnis in einen tool_result-Block mit der passenden tool_use_id und senden sie als eine einzige User-Nachricht zurück.

In TypeScript mit dem Anthropic SDK:

import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();
const MAX_ITERATIONS = 10;

async function runAgent(userMessage: string) {
  const messages: Anthropic.MessageParam[] = [
    { role: "user", content: userMessage },
  ];

  for (let i = 0; i < MAX_ITERATIONS; i++) {
    const response = await client.messages.create({
      model: "claude-sonnet-4-6",
      max_tokens: 4096,
      tools: TOOLS,
      messages,
    });

    messages.push({ role: "assistant", content: response.content });

    if (response.stop_reason === "end_turn") {
      return response;
    }

    if (response.stop_reason === "tool_use") {
      const toolResults: Anthropic.ToolResultBlockParam[] = [];
      for (const block of response.content) {
        if (block.type === "tool_use") {
          const result = await execute(block.name, block.input);
          toolResults.push({
            type: "tool_result",
            tool_use_id: block.id,
            content: JSON.stringify(result),
            is_error: result.error ? true : false,
          });
        }
      }
      messages.push({ role: "user", content: toolResults });
      continue;
    }

    break;
  }
  throw new Error("Iteration budget exhausted");
}

Das ist die gesamte Form eines Tool-nutzenden Agents. Alles andere sind Schema-Design, Fehlerbehandlung und Guardrails.

Parallele Tool-Aufrufe

Das Modell kann mehrere tool_use-Blöcke in einer Antwort ausgeben. Wenn ein Nutzer fragt “suche Bestellung ORD-123 und prüfe, ob [email protected] ein offenes Ticket hat”, gibt Claude oft beide Aufrufe gleichzeitig zurück. Führen Sie sie parallel aus. Geben Sie jedes Ergebnis im nächsten User-Turn zurück, jeweils mit der richtigen tool_use_id versehen.

const toolResults = await Promise.all(
  response.content
    .filter((b): b is Anthropic.ToolUseBlock => b.type === "tool_use")
    .map(async (block) => {
      const result = await execute(block.name, block.input);
      return {
        type: "tool_result" as const,
        tool_use_id: block.id,
        content: JSON.stringify(result),
        is_error: !!result.error,
      };
    }),
);

Sie müssen für jeden tool_use-Block in derselben Nachricht ein tool_result zurückgeben. Verpassen Sie eines, und die API lehnt die nächste Anfrage ab. Das ist der häufigste Fehler, den ich sehe. Wenn ein Aufruf fehlschlägt, geben Sie dennoch ein tool_result mit is_error: true und einer kurzen Fehlermeldung zurück.

Fehlerbehandlung

Setzen Sie is_error: true im tool_result, wenn etwas schiefgelaufen ist. Halten Sie den content kurz und handlungsorientiert. Das Modell liest ihn und versucht es normalerweise mit anderen Argumenten erneut.

{
  type: "tool_result",
  tool_use_id: block.id,
  content: "Order not found. The ID 'ORD-xyz' did not match any order. Check the format: valid IDs start with ORD- followed by 6 digits.",
  is_error: true,
}

Geben Sie keine Stacktraces zurück. Das Modell interessiert das nicht, und Sie verbrennen Token mit Rauschen. Geben Sie den einen Satz zurück, den ein Junior-Entwickler brauchen würde: was fehlgeschlagen ist, warum, was stattdessen zu versuchen ist.

Bei transienten Fehlern (Timeouts, 429er, instabile Upstreams) haben Sie zwei Optionen. Retry innerhalb des Tools (vor dem Modell verborgen) oder den Fehler nach oben reichen und das Modell entscheiden lassen. Ich bevorzuge verborgene Retries mit exponentiellem Backoff und reiche den Fehler erst nach drei fehlgeschlagenen Versuchen nach oben. Das Modell muss nicht wissen, dass Ihr Upstream wackelt.

Disambiguierung über Schemas

Die meisten Probleme nach dem Muster “das Modell hat das falsche Tool aufgerufen” sind Schema-Probleme, keine Prompting-Probleme. Wenn Sie zwei Tools haben, die beide plausibel zu einer Anfrage passen, rät das Modell. Ziehen Sie die Schemas so eng, dass sie nicht verwechselt werden können.

Schlecht:

{ name: "send_message", input_schema: { properties: { message: { type: "string" } } } }
{ name: "create_note", input_schema: { properties: { text: { type: "string" } } } }

Besser:

{
  name: "send_customer_email",
  description: "Send an email to the customer's registered address. Use only when the customer has asked for a written response.",
  input_schema: { properties: { customer_id: { type: "string" }, subject: { type: "string" }, body: { type: "string" } }, required: ["customer_id", "subject", "body"] }
}
{
  name: "add_internal_note",
  description: "Add a note visible only to support agents. The customer will not see this. Use for triage context.",
  input_schema: { properties: { ticket_id: { type: "string" }, note: { type: "string", maxLength: 1000 } }, required: ["ticket_id", "note"] }
}

Enums und Pflichtfelder erledigen den größten Teil der Arbeit. Wenn Ihr Schema dem Modell erlaubt, einen String zu raten, wird es irgendwann falsch raten.

Streaming von Tool-Aufrufen

Tool-Argumente können lang sein. Wenn Sie einen 2-KB-JSON-Blob als Tool-Input erzeugen, können Sie mit Streaming Fortschritt anzeigen oder früh mit dem Parsen beginnen. Claude sendet input_json_delta-Events innerhalb von content_block_delta-Events, während der Tool-Aufruf generiert wird.

const stream = client.messages.stream({
  model: "claude-sonnet-4-6",
  max_tokens: 4096,
  tools: TOOLS,
  messages,
});

let partialJson = "";
for await (const event of stream) {
  if (event.type === "content_block_delta" && event.delta.type === "input_json_delta") {
    partialJson += event.delta.partial_json;
    // parse partial_json with a tolerant parser if you need live progress
  }
}
const finalMessage = await stream.finalMessage();

Streaming lohnt sich, wenn Tool-Argumente groß sind oder wenn Sie einem Nutzer Fortschritt anzeigen möchten. Für die meisten Tool-Aufrufe (kurze Argumente, schnelles Modell) ist einfaches Request/Response simpler und genauso schnell.

Kombinationen, die zählen

Tool Use lässt sich mit allem anderen kombinieren, was Claude bietet. Diese drei Kombinationen kommen ständig vor.

Tool Use und Prompt Caching. Tool-Definitionen sind oft der größte statische Block in Ihrem System. Cachen Sie sie. Fügen Sie cache_control: { type: "ephemeral" } am letzten Tool im Array hinzu (oder an Ihrem System-Prompt, falls Tools klein sind), und Sie zahlen bei Cache-Treffern 10 % der Input-Kosten. Für einen Agent, der in einer Schleife über hundert Iterationen mit denselben Tool-Definitionen läuft, macht das viel aus. Siehe Claude prompt caching für die vollständige Aufschlüsselung.

Tool Use und Extended Thinking. Mit aktiviertem Extended Thinking plant das Modell in seinem Thinking-Block, bevor es entscheidet, welches Tool aufgerufen wird. Sie erhalten sichtbar bessere Tool-Auswahl bei mehrstufigen Problemen: Das Modell überlegt “I need to first look up the customer, then check recent tickets, then decide whether to escalate” innerhalb des Thinking-Blocks und dispatcht dann das richtige Tool. Aktivieren Sie Thinking für Agents, die drei oder mehr Tools verketten müssen, um zu einer Antwort zu gelangen.

Tool Use und MCP. MCP (Model Context Protocol) ist ein Standard, um Tools einmal zu definieren und sie in jeden Client einzubinden. Wenn Claude ein MCP-Tool aufruft, sehen Sie einen normalen tool_use-Block. Der Unterschied ist, dass der MCP-Server, nicht Ihr Anwendungscode, die Ausführung übernimmt. Ich betreibe meinen eigenen TickTick-MCP-Server für persönliches Task-Management, und der Client-Code behandelt diese Tools identisch zu handdefinierten. Wenn Sie eine Tool-Oberfläche ausliefern, die andere Claude-Clients wiederverwenden sollen, schreiben Sie sie als MCP-Server. Siehe Build an MCP server in TypeScript.

Häufige Failure Modes und Lösungen

Jeder Tool-nutzende Agent scheitert grob auf die gleiche Weise. Hier sind die, die ich am häufigsten sehe, und was sie behebt.

Das Modell ruft das Tool mit der falschen Form auf. Dem Argument fehlt ein Pflichtfeld, oder ein String wird übergeben, wo ein Array erwartet wird. Lösung: Schema enger ziehen. Fügen Sie required, enum, maxLength hinzu. Wenn das Schema nicht lockerer sein kann als die Wahrheit, kann das Modell es nicht verletzen.

Das Modell weigert sich, ein Tool aufzurufen, das Sie aufgerufen haben möchten. Es antwortet immer wieder im Freitext. Lösung: Die Beschreibung ist zu restriktiv, oder das Modell denkt, dass die Anfrage des Nutzers nicht passt. Schwächen Sie die “do not use when…"-Klauseln in der Beschreibung ab. Wenn das Modell immer handeln soll, wechseln Sie zu tool_choice: { type: "any" } und lassen Sie den Chat-only-Zweig weg.

Das Modell halluziniert einen Tool-Namen. Es erfindet search_customers, obwohl Sie nur lookup_customer_by_email definiert haben. Lösung: Verwenden Sie tool_choice mit einem konkreten Tool, wenn Sie einen konkreten Aufruf wollen. Oder benennen Sie Ihr Tool in die Phrase um, nach der das Modell immer wieder greift. Das Modell sagt Ihnen, was es erwartet hat.

Endlosschleife. Der Agent ruft immer wieder dasselbe Tool mit denselben Argumenten auf. Lösung: Immer die Iterationen begrenzen. Ich setze standardmäßig 10, manchmal 20. Erkennen Sie auch exakte Wiederholungen: Wenn die letzten beiden Assistant-Turns byteidentisch sind, stoppen Sie und geben Sie das letzte Ergebnis zurück. Etwas Upstream ist kaputt, und mehr Iterationen werden es nicht richten.

Schema-Mismatch scheitert leise erfolgreich. Der Tool-Aufruf liefert Daten in einer Form, die das Modell nicht erwartet hat, und das Modell produziert Unsinn. Lösung: Validieren Sie Tool-Ergebnisse gegen ein Response-Schema, bevor Sie sie zurückgeben. Vertrauen Sie nicht einmal Ihrem eigenen Upstream.

Ein realistisches Beispiel: Customer-Support-Triage

Hier ist die vollständige Schleife für einen Support-Agent mit drei Tools. Er sucht eine Bestellung, erstellt bei Bedarf ein Ticket und sendet dem Kunden eine E-Mail. Das Beispiel demonstriert parallele Aufrufe, Fehlerbehandlung und Iterationsbudget.

import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();
const MAX_ITERATIONS = 8;

const TOOLS: Anthropic.Tool[] = [
  {
    name: "lookup_order",
    description:
      "Look up an order by its order ID. Use this when the user " +
      "references an order ID (format: ORD- followed by 6 digits). " +
      "Returns order status, shipping info, and customer ID.",
    input_schema: {
      type: "object",
      properties: {
        order_id: { type: "string", pattern: "^ORD-[0-9]{6}$" },
      },
      required: ["order_id"],
    },
  },
  {
    name: "create_ticket",
    description:
      "Create a customer support ticket. Call this after you have " +
      "identified the customer and understood the issue. Do not call " +
      "for general questions that can be answered directly.",
    input_schema: {
      type: "object",
      properties: {
        customer_id: { type: "string" },
        category: {
          type: "string",
          enum: ["shipping", "refund", "damaged", "wrong_item", "other"],
        },
        priority: {
          type: "string",
          enum: ["low", "normal", "high", "urgent"],
        },
        summary: { type: "string", maxLength: 280 },
      },
      required: ["customer_id", "category", "priority", "summary"],
    },
  },
  {
    name: "email_customer",
    description:
      "Send an email to the customer. Use once the ticket is created " +
      "and you have a concrete next step to communicate. Keep the body " +
      "short, courteous, and free of internal jargon.",
    input_schema: {
      type: "object",
      properties: {
        customer_id: { type: "string" },
        subject: { type: "string", maxLength: 100 },
        body: { type: "string", maxLength: 2000 },
      },
      required: ["customer_id", "subject", "body"],
    },
  },
];

async function execute(name: string, input: unknown): Promise<{ ok: boolean; data?: unknown; error?: string }> {
  try {
    switch (name) {
      case "lookup_order":
        return { ok: true, data: await lookupOrder((input as { order_id: string }).order_id) };
      case "create_ticket":
        return { ok: true, data: await createTicket(input as CreateTicketInput) };
      case "email_customer":
        return { ok: true, data: await emailCustomer(input as EmailCustomerInput) };
      default:
        return { ok: false, error: `Unknown tool: ${name}` };
    }
  } catch (err) {
    return { ok: false, error: err instanceof Error ? err.message : String(err) };
  }
}

export async function runSupportAgent(userMessage: string) {
  const messages: Anthropic.MessageParam[] = [
    { role: "user", content: userMessage },
  ];

  for (let i = 0; i < MAX_ITERATIONS; i++) {
    const response = await client.messages.create({
      model: "claude-sonnet-4-6",
      max_tokens: 4096,
      system:
        "You are a customer support triage agent. When a customer " +
        "reports an issue, look up the relevant order, create a ticket, " +
        "and send a brief confirmation email. Keep tone direct and " +
        "helpful. If you cannot find the order, ask the customer for " +
        "clarification rather than guessing.",
      tools: TOOLS,
      messages,
    });

    messages.push({ role: "assistant", content: response.content });

    if (response.stop_reason === "end_turn") {
      return response;
    }

    if (response.stop_reason === "tool_use") {
      const toolBlocks = response.content.filter(
        (b): b is Anthropic.ToolUseBlock => b.type === "tool_use",
      );
      const toolResults = await Promise.all(
        toolBlocks.map(async (block) => {
          const result = await execute(block.name, block.input);
          return {
            type: "tool_result" as const,
            tool_use_id: block.id,
            content: result.ok
              ? JSON.stringify(result.data)
              : `Error: ${result.error}`,
            is_error: !result.ok,
          };
        }),
      );
      messages.push({ role: "user", content: toolResults });
      continue;
    }

    break;
  }

  throw new Error("Support agent exhausted iteration budget");
}

Das ist ein vollständiger Agent. Parallele Ausführung über Promise.all, Fehlerbehandlung über is_error, Iterationsobergrenze, enge Schemas. Legen Sie ihn in einen HTTP-Handler, einen Queue-Worker oder einen Telegram-Bot, und Sie haben etwas, das ein Team tatsächlich nutzen kann.

Mehr dazu, wann Sie einen solchen Agent bauen und wann Sie ein Vendor-Angebot kaufen sollten, finden Sie unter AI agents: build vs buy. Wann Sie Claude statt OpenAI für dieses Muster wählen sollten, beschreibt Claude API vs OpenAI for business automation.

Produktions-Guardrails

Alles oben ergibt einen funktionierenden Agent. Das Folgende hält ihn am Leben.

Iterationsbudget. Begrenzen Sie immer die Iterationen. 10 ist ein vernünftiger Standard. Protokollieren Sie die Iterationsnummer in jeder Schleife. Wenn Sie konsistent die Obergrenze erreichen, sind Ihre Tools falsch, nicht das Modell.

Kosten-Cap pro Aufruf. Verfolgen Sie Input- plus Output-Token pro Lauf. Setzen Sie eine harte Grenze. Geben Sie bei Überschreitung einen Fehler zurück, statt eine außer Kontrolle geratene Schleife zu Opus-Preisen abzurechnen.

PII-Redaktion in tool_results. Wenn ein Tool eine rohe E-Mail, Telefonnummer oder Zahlungsdaten zurückgibt, sieht das Modell diese und kann sie in seiner Endantwort wiedergeben. Redigieren Sie beim Eingang (Kundendaten im Tool-Ergebnis maskieren) oder filtern Sie beim Ausgang (Regex-Treffer aus dem Endtext entfernen).

Audit-Logging. Jeder Tool-Aufruf erhält eine Zeile in einem Log: Timestamp, User-ID, Tool-Name, Input, Output, Latenz, Fehler. Wenn in der Produktion etwas schiefgeht, brauchen Sie den vollständigen Call-Trace. Modell-Response-IDs helfen, Logs mit Nutzungsdaten auf Anthropic-Seite zu korrelieren.

Rate Limits pro Nutzer. Das Modell ruft gerne zehn Mal in zehn Sekunden email_customer auf, wenn die Schleife entgleist. Setzen Sie einen Rate Limit vor jedes Tool mit Seiteneffekt.

Human-in-the-Loop für risikoreiche Aktionen. Rückerstattung, Löschung, Produktionsfreigabe: Lassen Sie das Modell diese nicht direkt ausführen. Das Tool stellt die Aktion zur menschlichen Freigabe in die Queue und gibt “queued, awaiting approval” zurück. Der Plan des Modells bleibt klar, das Risiko bleibt begrenzt.

Testen von Tool-Calling-Agents

Tool-Calling-Agents brauchen echte Tests, nicht nur das Augenscheinen von Outputs.

Mocken Sie die Tools. Treffen Sie keine echten APIs in Unit-Tests. Mocken Sie execute, um fertige Ergebnisse zurückzugeben. Behaupten Sie, dass das Modell die richtigen Tools in der richtigen Reihenfolge mit den richtigen Argumenten aufgerufen hat.

Prüfen Sie die Aufrufform, nicht nur den finalen Text. Die letzte Assistant-Nachricht kann aus den falschen Gründen korrekt sein. Prüfen Sie, dass das Modell lookup_order vor create_ticket aufgerufen hat. Prüfen Sie, dass create_ticket die Customer-ID aus dem Lookup-Ergebnis erhalten hat.

Fuzzen Sie die Schemas. Senden Sie merkwürdig geformte Nutzereingaben. Emoji. Falsche Order-ID-Formate. Gemischte Sprachen. Stellen Sie sicher, dass das Modell entweder das richtige Tool aufruft oder nachfragt und niemals Ihre Execute-Funktion mit einer unerwarteten Eingabeform abstürzen lässt.

Spielen Sie aufgezeichnete Konversationen erneut ab. Zeichnen Sie echte Nutzerkonversationen auf (mit Einwilligung), entfernen Sie PII und spielen Sie sie gegen neue Prompt- oder Tool-Änderungen ab. Das ist der wertvollste Regressionstest, den ich für Agents habe.

Für Agents, die auf Claude Code selbst aufbauen, siehe Claude Code SDK agents für ein Muster, das Multi-Turn-, Multi-Tool-Flows out-of-the-box behandelt.

Wann Tool Use das falsche Muster ist

Tool Use ist der Standard, aber nicht immer richtig.

Bei reiner Textgenerierung (Zusammenfassungen, Übersetzungen, Umschreibungen) lassen Sie Tools weg und geben Text zurück. Tools bringen Latenz und Token-Kosten.

Bei strukturierter Ausgabe, deren Schema Sie bereits kennen, erzwingen Sie ein einzelnes Tool (tool_choice: { type: "tool", name: "..." }), statt einen Multi-Turn-Agent laufen zu lassen. Ein Call rein, ein Call raus.

Für alles, wo ein statischer Prompt plus ein Template funktionieren würde, verwenden Sie das Template. Bauen Sie keinen Agent, nur weil das Wort “Agent” gerade en vogue ist.

Verwandte Artikel

Download the AI Automation Checklist (PDF)

Checkliste herunterladen Download the checklist

Kostenloses 2-seitiges PDF. Kein Spam. Free 2-page PDF. No spam.

Kein Newsletter. Keine Weitergabe. Nur die Checkliste. No newsletter. No sharing. Just the checklist.

Ihre Checkliste ist bereit Your checklist is ready

Klicken Sie unten zum Herunterladen. Click below to download.

PDF herunterladen Download PDF Ergebnisse gemeinsam durchgehen? → Walk through your results together? →