Als wir bei einem Energieversorgungskunden einen Agenten zur Automatisierung von SCADA-Berichten eingesetzt haben, verliefen die ersten Tage reibungslos. Dann begannen die stillen Fehler: Der Agent rief das richtige Tool auf, sendete aber Argumente im falschen Format — eine Zahl, wo ein String erwartet wurde, null, wo ein Wert erwartet wurde. Das Ergebnis? Das Tool lieferte einen Fehler zurück, der Agent ignorierte ihn und machte einfach weiter, als wäre nichts gewesen. Der Bericht wurde generiert, alles sah funktionsfähig aus — aber die Zahlen waren ungenau. Es dauerte mehrere Tage, bis wir die Ursache gefunden hatten.
Tool Calling — das Aufrufen externer Tools und Systeme über ein LLM — ist die Grundfähigkeit jedes Produktionsagenten. Und gleichzeitig seine größte Quelle stiller Fehler. Dieser Artikel konzentriert sich auf konkrete Muster: Wie Sie Tool-Schemata entwerfen, Argumente validieren, Fehler behandeln und eine Retry-Logik aufbauen, die unter realen Bedingungen funktioniert.
Warum Tool Calling versagt — nicht so, wie Sie denken
Wenn Entwickler die Unzuverlässigkeit von Agenten untersuchen, suchen sie die Ursache meist im Modell. Schlechtes Reasoning, unzureichendes Schlussfolgern, falsches Aufgabenverständnis. In der Praxis haben wir festgestellt, dass die meisten Produktionsvorfälle eine andere Ursache haben: schlechtes Schema-Design, fehlende Argumentvalidierung, unbehandelte Tool-Fehler.
Die vier häufigsten Versagensmuster, die wir sehen:
- Der Agent ruft das falsche Tool auf — weil die Tool-Beschreibungen zu ähnlich, vage oder nicht unterscheidend genug sind
- Der Agent ruft das richtige Tool mit falschen Argumenten auf — weil das Schema nicht präzise beschreibt, welche Werte gültig sind
- Der Agent ignoriert einen Tool-Fehler — weil niemand den Fall behandelt hat, in dem das Tool eine Ausnahme zurückgibt
- Der Agent gerät in eine Retry-Schleife — weil die Retry-Logik nicht begrenzt ist und kein exponentielles Backoff hat
Keines dieser Probleme hat mit der Intelligenz des Modells zu tun. Alle lassen sich auf der Ingenieurebene lösen. Und alle wiederholen sich unabhängig von der verwendeten Agentenarchitektur.
Schema-Design für Tools: Präzision vor Kürze
Das Tool-Schema ist das, was der Agent sieht, wenn er entscheidet, was er aufrufen soll. Ist das Schema ungenau, rät der Agent — und Raten in einem deterministischen System ist ein Problem.
Grundlegende Schema-Designregeln, die in der Praxis gelten:
Der Tool-Name muss ein aktives Verb + Objekt sein. get_sensor_reading ist gut. sensor ist schlecht. data ist sehr schlecht. Das LLM orientiert sich am Namen — wenn zwei Tool-Namen ähnlich klingen, werden sie vom Agenten vertauscht, unabhängig von der Qualität der Beschreibung.
Die Beschreibung muss unterscheiden, wann das Tool zu verwenden ist und wann nicht. Es reicht nicht, „gibt Sensordaten zurück" zu schreiben. Schreiben Sie: „Nur aufrufen, wenn Sie Live-Werte von einem bestimmten Gerät anhand der ID benötigen. Nicht für historische Daten verwenden — dafür ist get_sensor_history zuständig." Explizite Negation ist genauso wichtig wie die positive Beschreibung.
Jeder Parameter muss einen Typ, eine Beschreibung und ein Beispiel haben. sensor_id: string reicht nicht. Schreiben Sie: „Sensor-ID im Format PLANT_ZONE_NNN, z. B. A_LINE1_042. Geben Sie niemals nur die Zahl ohne Präfix an." Das Modell errät das Format nicht — Sie müssen es zeigen.
Optionale Parameter explizit kennzeichnen — und angeben, was der Standardwert ist und was passiert, wenn sie weggelassen werden. Ohne das generiert der Agent wiederholt null oder nimmt einen falschen Wert an.
Beispiel für ein Schema vor und nach der Überarbeitung:
# Vorher (typisches schlechtes Schema)
{
"name": "sensor_data",
"description": "Gets sensor data",
"parameters": {
"id": {"type": "string"},
"from": {"type": "string"},
"to": {"type": "string"}
}
}
# Nachher (produktionsreifes Schema)
{
"name": "get_sensor_reading",
"description": "Reads current live value from a field sensor.
Use ONLY for real-time values. For historical ranges use get_sensor_history instead.
Returns {value, unit, timestamp, status}. Throws SensorOfflineError if device unreachable.",
"parameters": {
"sensor_id": {
"type": "string",
"description": "Sensor identifier in format PLANT_ZONE_NNN, e.g. A_LINE1_042"
},
"unit": {
"type": "string",
"enum": ["raw", "normalized"],
"description": "Output unit type. Default: 'raw'",
"default": "raw"
}
},
"required": ["sensor_id"]
}Der Unterschied liegt nicht in der Eleganz — sondern darin, wie oft der Agent das richtige Tool mit gültigen Argumenten aufruft. Aus der Praxis: Durch die Korrektur der Schemata haben wir die Rate falscher Aufrufe um mehr als die Hälfte reduziert — ohne jede Änderung am Modell.
Argumentvalidierung: Dem Modell nicht blind vertrauen
Selbst wenn das Schema gut ist, generiert das Modell gelegentlich Argumente, die syntaktisch gültig, aber semantisch falsch sind. from_date: "2026-13-45" ist ein gültiger String, aber kein gültiges Datum. count: -5 ist eine gültige Zahl, ergibt aber keinen Sinn.
Die Validierung von Argumenten vor dem eigentlichen Tool-Aufruf ist eine Pflicht, keine Optimierung.
Drei Validierungsebenen, die wir empfehlen:
1. JSON-Schema-Validierung — die einfachste Ebene. Überprüfen Sie, ob der Agent den richtigen Typ für jeden Parameter gesendet hat. Die meisten Frameworks (LangGraph, LangChain) tun dies automatisch, wenn ein Schema vorhanden ist, aber eine explizite Ebene ist sicherer.
2. Domänenvalidierung — Überprüfung, ob die Werte im Kontext Ihrer Domäne sinnvoll sind. Daten in einem vernünftigen Bereich, IDs im richtigen Format, numerische Werte in einem gültigen Bereich. Das müssen Sie selbst programmieren — kein generisches Framework erledigt das für Sie.
3. Referenzielle Integrität — Überprüfung, ob die referenzierte Entität existiert. sensor_id: "A_LINE1_042" müssen Sie gegen das tatsächliche Sensorregister prüfen — das Modell hat keine Möglichkeit zu wissen, welche IDs gültig sind.
Wenn die Validierung fehlschlägt, werfen Sie nicht einfach eine Ausnahme. Geben Sie eine strukturierte Fehlermeldung zurück, die dem Modell mitteilt, *was* falsch war und *wie* es behoben werden kann:
# Schlecht
raise ValueError("Invalid sensor_id")
# Gut
return {
"error": "INVALID_ARGUMENT",
"parameter": "sensor_id",
"received": "A_LINE_42",
"message": "Format must be PLANT_ZONE_NNN. Did you mean A_LINE1_042?",
"hint": "Call list_sensors() to get valid IDs for this plant"
}Diese Fehlermeldung ist die Eingabe für den nächsten Schritt des Agenten — je informativer sie ist, desto größer die Chance, dass der Agent sich selbst korrigiert, ohne unnötige Eskalation.
Error Handling: Tool-Fehler sind normale Situationen, keine Ausnahmen
Eines der größten konzeptuellen Probleme, das wir in Produktionsagenten sehen: Der Code wurde für den Happy Path geschrieben. Wenn ein Tool einen Fehler zurückgibt, verhält sich der Agent unvorhersehbar — er hängt entweder fest oder arbeitet mit einem fehlerhaften Zustand weiter.
Produktionsrealität: Tools versagen. APIs haben Ausfälle. Datenbanken sind vorübergehend nicht verfügbar. SCADA-Systeme liefern Timeouts. Das sind keine Edge Cases — das sind alltägliche Ereignisse in industriellen Umgebungen.
Das grundlegende Error-Handling-Muster für jedes Tool:
def call_tool_safely(tool_fn, args, max_retries=3):
for attempt in range(max_retries):
try:
result = tool_fn(**args)
return {"status": "ok", "data": result}
except TransientError as e:
if attempt == max_retries - 1:
return {
"status": "error",
"type": "TRANSIENT",
"message": str(e),
"hint": "Service temporarily unavailable, retry later"
}
time.sleep(2 ** attempt) # exponential backoff
except PermanentError as e:
return {
"status": "error",
"type": "PERMANENT",
"message": str(e),
"hint": "Do not retry. Escalate to human operator."
}
except Exception as e:
return {
"status": "error",
"type": "UNKNOWN",
"message": str(e),
"hint": "Unexpected error. Log and escalate."
}Die wichtigsten Prinzipien:
- Unterscheiden Sie vorübergehende von dauerhaften Fehlern. Ein Timeout ist ein vorübergehender Fehler (retry). Ein Autorisierungsfehler ist dauerhaft (kein Retry, eskalieren). Das Modell muss wissen, was als nächstes zu tun ist.
- Exponentielles Backoff — keine feste Pause. Jeder Retry wartet doppelt so lange (1 s, 2 s, 4 s ...). Verhindert die Überlastung von Systemen bei Ausfällen.
- Maximale Anzahl von Retries — immer begrenzt. Ohne Limit kann der Agent in eine unendliche Schleife geraten. Aus der Praxis: Eine Retry-Rate von rund 12 % ist in Produktionssystemen üblich — wenn Sie sie nicht unter Kontrolle haben, können Sie die gesamten Aufrufe und Kosten verdoppeln.
- Strukturierte Fehlermeldung — der Agent muss eine Information über den Fehlertyp und den empfohlenen nächsten Schritt erhalten.
Mehr über die Kostenauswirkungen der Retry-Logik erfahren Sie im Artikel über die Kosten von KI-Agenten in der Produktion.
Idempotenz: Die vergessene Bedingung der Zuverlässigkeit
Wenn ein Agent einen Tool-Aufruf wiederholt, muss es sicher sein, ihn mehrfach mit denselben Argumenten aufzurufen. Wenn nicht — haben Sie ein Problem.
Idempotenter Aufruf: get_sensor_reading(sensor_id="A_LINE1_042") mehrfach aufzurufen liefert denselben (oder einen äquivalenten) Wert ohne Nebeneffekt. Sicher für Retry.
Nicht-idempotenter Aufruf: create_work_order(equipment_id="P-042", type="inspection") mehrfach aufzurufen erstellt mehrere Arbeitsaufträge. Katastrophal bei Retry.
Regel für Produktionssysteme: Jedes Tool, das einen Schreibvorgang, eine Mutation oder eine Aktion mit Nebeneffekten ausführt, muss vor doppeltem Aufruf geschützt sein.
Schutzmuster:
Idempotency Key — der Agent generiert einen eindeutigen Schlüssel für jede Aufgabe und sendet ihn mit dem Aufruf. Das Backend registriert den Schlüssel, und ein zweiter Aufruf mit demselben Schlüssel gibt das Ergebnis des ersten zurück, ohne die Aktion erneut auszuführen:
def create_work_order(equipment_id, type, idempotency_key):
existing = db.find_by_key(idempotency_key)
if existing:
return existing # Vrátime predchádzajúci výsledok
result = actually_create_work_order(equipment_id, type)
db.store(idempotency_key, result)
return resultZustandsprüfung vor der Aktion — vor einem Schreibvorgang prüfen, ob der Zustand bereits dem Ziel entspricht. Wenn ein Arbeitsauftrag für Gerät P-042 für heute bereits existiert, keinen neuen erstellen. Das ist einfacher als ein Idempotency Key und eignet sich für Geschäftsdomänen mit natürlicher Eindeutigkeit.
Explizite Dokumentation im Schema — jedes Tool mit Nebeneffekten muss in seiner Beschreibung enthalten: „Diese Aktion ist nicht umkehrbar / erstellt einen Datensatz. Nur aufrufen, wenn Sie sicher sind, dass die Bedingungen erfüllt sind." Ein Modell, das diese Information erhält, ist vorsichtiger.
Warum der Agent das falsche Tool aufruft — und wie man es reduziert
Eines der rätselhafteren Probleme: Der Agent ruft konsistent tool_A statt tool_B auf, obwohl tool_B das richtige wäre. Die Ursachen sind vielfältig, und jede hat eine andere Lösung.
Zu ähnliche Namen und Beschreibungen. Wenn Sie get_equipment_data und fetch_equipment_info haben, werden diese Tools vom Agenten verwechselt. Lösung: Gehen Sie den gesamten Tool-Satz durch und prüfen Sie, ob Namen und Beschreibungen eindeutig unterscheidend sind. Wenn zwei Kollegen ohne Lesen des Codes keinen Unterschied erkennen können, kann es das Modell auch nicht.
Zu viele Tools auf einmal. LLMs haben eine begrenzte Aufmerksamkeitskapazität. Wenn Sie einem Agenten 30 Tools in einem einzigen Prompt präsentieren, steigt die Wahrscheinlichkeit einer falschen Auswahl erheblich. Lösungsmuster: Toolset Routing — der Agent wählt zunächst eine Tool-Gruppe (z. B. „Sensor-Tools" vs. „Reporting-Tools") und dann ein konkretes Tool aus dieser Gruppe. Das ist der Zusammenhang mit dem MCP-Protokoll — Server dienen als natürliche Tool-Gruppen.
Fehlender Kontext im Prompt. Wenn der System-Prompt dem Agenten nicht mitteilt, in welchem Kontext er arbeitet, schätzt das Modell das passende Tool aus dem Konversationsverlauf. Expliziter Kontext im System-Prompt — „Du arbeitest im Produktionsmanagementsystem, nicht im HR-System" — reduziert Tool-Auswahlfehler.
Trainings-Bias des Modells. Einige Modelle haben Trainingsdaten, die bestimmte Aufrufmuster bevorzugen. Wenn ein Agent trotz korrektem Schema wiederholt das falsche Tool aufruft, versuchen Sie, den Tool-Namen zu ändern — manchmal hilft selbst das.
Retry-Logik: Fünf Regeln, die die Produktion retten
Retry ist ein unverzichtbarer Bestandteil zuverlässigen Tool Callings. Aber schlecht implementiertes Retry ist schlimmer als kein Retry — es kann einen vorübergehenden Ausfall in einen Kaskadenausfall verwandeln.
Regel 1: Nur vorübergehende Fehler wiederholen. HTTP 503 (Service Unavailable) und Timeout sind vorübergehend. HTTP 400 (Bad Request) und 403 (Forbidden) sind dauerhaft — Retry hilft nicht, Sie verschwenden nur Ressourcen.
Regel 2: Exponentielles Backoff mit Jitter. Eine feste Pause (Retry jede Sekunde) überlastet das System bei einem Ausfall. Exponentielles Backoff mit zufälligem Jitter (±20 %) verteilt die Last:
delay = min(base_delay * (2 ** attempt) + random.uniform(0, 0.3), max_delay)Regel 3: Absolutes Limit für Versuche. Drei Versuche sind meistens ausreichend. Fünf sind das Maximum. Mehr Retries → höheres Risiko eines Retry Storms (alle Agenten wiederholen gleichzeitig den ausgefallenen Dienst).
Regel 4: Circuit Breaker für wiederkehrende Ausfälle. Wenn ein bestimmtes Tool mehrfach hintereinander versagt, es vorübergehend „trennen" und alle weiteren Aufrufe sofort als CIRCUIT_OPEN zurückgeben. Nach einer Cooldown-Periode einen einzelnen Testaufruf zulassen. Das schützt auch Ihre Backend-Systeme.
Regel 5: Fallback-Aktion. Wenn Retry und Circuit Breaker versagen — was tut der Agent dann? Eskaliert er an einen menschlichen Operator, macht er ohne diese Information weiter oder hält er an? Jedes kritische Tool muss eine definierte Fallback-Strategie haben. Ohne sie ist der Agent bei einem Ausfall unvorhersehbar — was direkte Motivation für HITL-Gates ist.
Tool Calling vor der Produktion testen
Die Zuverlässigkeit von Tool Calling lässt sich nicht nur durch manuelles Testen des Happy Path überprüfen. Einige Testmuster, die wir empfehlen:
Mock-Toolset-Testing — Erstellen Sie Mock-Versionen aller Tools, die verschiedene Antwortkombinationen zurückgeben: Erfolg, vorübergehender Fehler, dauerhafter Fehler, fehlerhafte Ausgabe. Führen Sie den Agenten gegen diese Mocks aus und beobachten Sie das Verhalten.
Boundary-Testing von Argumenten — Testen Sie manuell, welche Argumente das Modell für Randeingaben generiert: leerer String, Null-Werte, extreme Zahlen, Daten in der Vergangenheit/Zukunft. Das Schema muss diese Fälle explizit ausschließen, sonst scheitert der Agent daran immer wieder.
Chaos-Testing — Mit einer bestimmten Wahrscheinlichkeit (z. B. 20 %) einen Fehler in das Tool während des Tests injizieren. Überprüft, ob Retry-Logik und Fallback-Verhalten in der Praxis funktionieren, nicht nur in Unit-Tests.
Trace Review — Für den Produktionseinsatz ist Observability und Tracing unerlässlich. Jeder Tool-Aufruf muss mit Argumenten, Ergebnis, Latenz und etwaigem Fehler erfasst werden. Ohne das wissen Sie bei einem Produktionsvorfall nicht einmal, wo Sie suchen sollen.
Häufige Fragen
Wie viele Tools kann ein Agent gleichzeitig haben?
Aus der Praxis: Bei mehr als 15–20 Tools in einem Kontext verschlechtert sich die Auswahlzuverlässigkeit deutlich. Die Lösung ist Toolset Routing oder MCP-Server — der Agent wählt zunächst die richtige Tool-Gruppe und dann ein konkretes Tool aus dieser Gruppe. Bei 50+ Tools ist hierarchische Navigation eine Notwendigkeit, keine Optimierung.
Was tun, wenn der Agent halluzinierte Argumente generiert — Werte, die nicht existieren?
Zwei Schritte: Erstens muss das Schema das Format gültiger Werte einschließlich Beispielen explizit zeigen. Zweitens muss die Validierung die Existenz referenzierter Entitäten prüfen (z. B. sensor_id gegen das Register) und einen strukturierten Fehler mit einem Hinweis zurückgeben, wie gültige Werte gefunden werden können. Ergänzend: Ein Tool list_available_X() (z. B. list_sensors()) hilft dem Agenten, gültige IDs selbst zu finden, ohne zu halluzinieren.
Ist es sicher, den Agenten nicht umkehrbare Aktionen automatisch ausführen zu lassen?
Das hängt vom Kontext ab. Für risikoarme Aktionen (Daten lesen, Berichte generieren) ist vollständige Automatisierung in Ordnung. Für nicht umkehrbare Aktionen (Bestellungen erstellen, Konfigurationen ändern, Nachrichten senden) empfehlen wir ein explizites HITL-Gate — der Agent schlägt die Aktion vor, ein menschlicher Operator genehmigt sie. Der EU AI Act fordert ab August 2026 menschliche Aufsicht für Hochrisiko-KI-Systeme — das impliziert direkt HITL für Aktionen mit potenziell schwerwiegenden Folgen.
Was ist der schnellste Weg, die Rate fehlerhafter Aufrufe zu senken?
Den größten Effekt hat in der Praxis die Korrektur der Tool-Schemata — konkret: unterscheidende Beschreibungen, Beispiele für gültige Werte und explizite negative Abgrenzung („nicht verwenden für ..."). Den zweiten großen Effekt hat die Reduzierung der Anzahl von Tools in einem Kontext. Diese beiden Änderungen erfordern keine Änderung des Modells oder der Architektur.
Wie überwacht man die Qualität des Tool Callings in der Produktion?
Erfassen Sie jeden Aufruf mit: Timestamp, tool_name, Argumenten (ohne PII), Status (ok/Fehler), Fehlertyp, Latenz, Versuchsnummer. Überwachen Sie die Fehlerrate pro Tool — wenn ein Tool eine dreimal höhere Fehlerquote als der Durchschnitt hat, ist das ein Signal für ein Schema-Audit. Tools wie Langfuse (self-hostable) oder LangSmith ermöglichen das ohne eigene Observability-Infrastruktur.
Fazit
*Tool Calling ist der Ort, an dem die meisten Zuverlässigkeitsprobleme von Agenten beginnen — und gleichzeitig der Ort, an dem sie sich rein auf der Ingenieurebene lösen lassen, ohne das Modell zu ändern. Gut entworfene Schemata, Argumentvalidierung, strukturiertes Error Handling und begrenzte Retry-Logik verwandeln einen unvorhersehbaren Agenten in ein betreibbares Werkzeug. Wenn Sie einen Agenten in die Produktion bringen möchten oder gerade Zuverlässigkeitsprobleme mit einem bestehenden System lösen, beurteilen wir Ihren konkreten Fall gerne — wir empfehlen Tool-Design, Validierungen und Error Handling für Ihre Umgebung.*
