Wenn ein Entwickler zum ersten Mal sieht, wie eine LLM eine Funktion „aufruft“, entsteht ein intuitiver Fehler:
Es scheint, als hätte das Modell die Anfrage an die Datenbank oder API selbst ausgeführt.
Das ist nicht der Fall, und genau dieser Fehler erzeugt eine ganze Klasse von Architekturfehlern.
Spoiler: Eine LLM gibt nur strukturiertes JSON mit dem Funktionsnamen und den Argumenten zurück –
die gesamte Ausführung findet in Ihrem Code statt.
⚡ Kurz gesagt
- ✅ LLM – Orchestrator, nicht Ausführender: Das Modell formuliert die JSON-Anfrage, Ihr Code führt sie aus
- ✅ Function Calling = Tool Use: Unterschiedliche Bezeichnungen von OpenAI und Anthropic für dieselbe Mechanik
- ✅ tool_choice: auto – das Modell entscheidet selbst; required – erzwungener Aufruf; none – nur Text
- ✅ RAG und Tool Use – unterschiedliche Abstraktionsebenen: RAG kann eines der Werkzeuge in einem Tool Use-System sein
- 🎯 Sie erhalten: ein klares Verständnis der Funktionsaufrufmechanik und wo sie mit Ihrer RAG-Pipeline überschneidet
- 👇 Unten – detaillierte Erklärungen, Codebeispiele und Tabellen
📚 Inhaltsverzeichnis des Artikels
⸻
Was ist Function Calling – das Modell als Orchestrator, nicht als Ausführender
Das Grundprinzip, das ständig verwechselt wird:
Eine LLM führt eine Funktion nicht selbst aus.
Sie analysiert nur den Kontext, bestimmt, welche Funktion mit welchen Argumenten aufgerufen werden soll –
und gibt eine strukturierte JSON-Anfrage zurück. Die Ausführung erfolgt zur Laufzeit Ihrer Anwendung.
Um zu verstehen, warum das so ist, muss man die Architektur aus dem richtigen Blickwinkel betrachten.
Eine LLM ist ein zustandsloser Text-Transformer. Sie hat keine Sockets, kann keine Verbindung zu einer Datenbank öffnen,
kann keine HTTP-Anfrage stellen. Alles, was sie tut, ist, Token als Eingabe zu empfangen und Token als Ausgabe zu generieren.
Function Calling ist einfach eine Vereinbarung über das Format dieser Ausgabetoken:
anstatt natürlichem Text generiert das Modell strukturiertes JSON,
das Ihr Code als Handlungsanweisung interpretiert.
Der vollständige Aufrufzyklus
Symflower (2025)
beschreibt dies so: Eine LLM bittet Agent Scaffolding, im Namen von ihr einen Tool-Aufruf auszuführen.
Comet (2026)
detailliert den Zyklus durch das TAO-Muster – Thought → Action → Observation:
1. Benutzeranfrage → LLM
↓
2. LLM analysiert den Kontext (Gedanke)
→ gibt JSON mit Funktionsnamen und Argumenten zurück
↓
3. Agent Scaffolding parst das JSON (Aktion)
→ führt die Funktion in Ihrem Code aus
→ erhält das Ergebnis
↓
4. Das Ergebnis wird als Tool-Ergebnis (Beobachtung) an die LLM zurückgegeben
↓
5. LLM generiert die endgültige Antwort an den Benutzer
Beachten Sie: Zwischen Schritt 2 und Schritt 4 ist die LLM überhaupt nicht beteiligt.
Sie „wartet“, bis Ihr Code die Arbeit erledigt und das Ergebnis zurückgibt.
Deshalb entstehen Fehler bei Tool-Aufrufen meist nicht im Modell,
sondern zwischen Schritt 3 und 4 – in Ihrem Code zur Verarbeitung des Ergebnisses.
Diese Architektur wird als Agent Scaffolding bezeichnet – eine Schicht zwischen der LLM und der Außenwelt,
die den Aufrufzyklus steuert. In einfachen Fällen sind es ein paar Zeilen Python.
In komplexen Fällen sind es vollwertige Frameworks wie LangGraph oder AutoGen.
Aber das Prinzip bleibt dasselbe: Das Modell entscheidet, was zu tun ist, der Code führt es aus.
Terminologischer Leitfaden: Function Calling vs. Tool Use
Beide Begriffe beschreiben dieselbe Mechanik – aber aus unterschiedlichen Perspektiven:
-
Function Calling – der ursprüngliche Begriff von OpenAI (erschienen in GPT-4, Juni 2023).
Der Fokus liegt darauf, dass das Modell eine Funktion „aufruft“ – daher der Name.
Das Modell gibt ein Objekt mit
function.name und function.arguments zurück.
-
Tool Use – ein breiterer Begriff von Anthropic und ein allgemeiner Industriestandard 2024–2025.
Der Fokus liegt darauf, dass das Modell ein „Werkzeug verwendet“ – betont, dass dies nur eines der Mittel ist
und kein Selbstzweck. Umfasst benutzerdefinierte Funktionen + integrierte Werkzeuge (Code-Interpreter, Websuche, Dateilesen).
Wie
Martin Fowler (2025)
anmerkt: „tool calling“ ist ein allgemeinerer und modernerer Begriff; beide Begriffe existieren aus historischen Gründen nebeneinander.
Es ist auch erwähnenswert: In der Anthropic-Dokumentation wird anstelle von required any verwendet,
und die Beschreibungen der Werkzeuge selbst werden über input_schema anstelle von parameters übergeben –
geringfügige syntaktische Unterschiede bei identischer Logik.
Warum das Modell das überhaupt kann
Function Calling ist keine eingebaute „Fähigkeit“ der LLM im Hardware-Sinne.
Es ist das Ergebnis von Fine-Tuning auf synthetischen Beispielen, bei denen die richtige Antwort JSON und kein Text ist.
Wie
Simplicity is SOTA (2025)
beschreibt, generieren Anbieter Tausende von Beispielen für Anfragen → Tool-Aufrufe mit einer Chain-of-Thought-Reasoning-Spur,
bei der das Modell lernt, nicht nur JSON zu generieren,
sondern auch zu begründen, warum dieses spezielle Werkzeug in diesem speziellen Kontext benötigt wird.
Die Qualität des Tool Callings hängt direkt von der Qualität der Werkzeugbeschreibungen ab.
Das Modell ist darauf trainiert, die Absicht anhand der Beschreibung zu erkennen – wenn die Beschreibung vage oder fehlend ist,
wird das Modell das Werkzeug entweder nicht aufrufen oder das falsche aufrufen.
Mehr dazu erfahren Sie in Wie das LLM-Modell entscheidet, wann es suchen soll – die Mechanik der Entscheidungsfindung.
Parallele Aufrufe: wenn ein Werkzeug nicht ausreicht
Moderne Modelle unterstützen parallele Tool-Aufrufe in einem einzigen Durchgang –
wenn für die Antwort gleichzeitig mehrere unabhängige Quellen benötigt werden.
Zum Beispiel kann die Anfrage „Vergleiche die Bedingungen der Verträge A und B“ zwei parallele Aufrufe von
search_documents mit unterschiedlichen Parametern auslösen, anstatt zwei sequentielle.
# Antwort des Modells bei parallelen Tool-Aufrufen:
{
"tool_calls": [
{
"id": "call_001",
"function": {
"name": "search_documents",
"arguments": "{\"query\": \"Bedingungen von Vertrag A\", \"top_k\": 3}"
}
},
{
"id": "call_002",
"function": {
"name": "search_documents",
"arguments": "{\"query\": \"Bedingungen von Vertrag B\", \"top_k\": 3}"
}
}
]
}
Ihr Code muss beide Ergebnisse verarbeiten und sie im nächsten Nachrichtenblock
als zwei separate tool_result-Blöcke zurückgeben.
Wenn Sie nur einen zurückgeben, erhält das Modell einen unvollständigen Kontext und kann den zweiten Teil der Antwort halluzinieren.
⚠️ Stolperstein #1: Unsichtbarer Fehler zwischen Schritt 3 und 4
Der häufigste Fehler in der Architektur: Der Entwickler glaubt, das Modell habe „eine Datenbankabfrage ausgeführt“,
obwohl es tatsächlich nur eine JSON-Anfrage formuliert hat und die Ausführung aufgrund eines Fehlers im Tool-Call-Verarbeitungscode möglicherweise gar nicht stattgefunden hat.
Die LLM erhält in der Zwischenzeit ein leeres oder fehlerhaftes Ergebnis – und generiert weiterhin eine Antwort,
als wäre nichts geschehen, oft halluzinierend, anstatt das Problem anzuerkennen.
Minimale Checkliste für einen zuverlässigen Zyklus:
- Protokollieren Sie den gesamten Zyklus: Tool-Call-Anfrage → Ausführung → Ergebnis → Modellantwort
- Überprüfen Sie, ob
arguments erfolgreich mit json.loads() deserialisiert wurden, bevor Sie fortfahren
- Behandeln Sie Ausnahmen, wenn die Funktion einen Fehler zurückgibt – und übergeben Sie diesen Fehler explizit zurück an die LLM
- Geben Sie bei parallelen Aufrufen immer die Ergebnisse für alle
tool_call.id zurück
Wie ein Aufruf technisch aussieht: JSON Schema, tool_choice auto/required/none
Damit das Modell von den Werkzeugen weiß, müssen diese im JSON Schema-Format beschrieben und in die API-Anfrage übergeben werden.
Die Syntax unterscheidet sich je nach Anbieter – und dieser Unterschied ist praktisch:
Code, der für OpenAI geschrieben wurde, funktioniert nicht mit der Anthropic API ohne die Änderung eines wichtigen Feldes.
OpenAI vs. Anthropic Syntax: Wo der Code bricht
Der Hauptunterschied: OpenAI verwendet den Schlüssel parameters,
Anthropic – input_schema. Der Rest der Struktur ist identisch.
# OpenAI / OpenAI-kompatible API
tools = [
{
"type": "function",
"function": {
"name": "search_documents",
"description": "Sucht relevante Fragmente in der Unternehmenswissensdatenbank",
"parameters": { # ← OpenAI: "parameters"
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Text der Suchanfrage"
},
"top_k": {
"type": "integer",
"description": "Anzahl der Fragmente (Standard 5)"
}
},
"required": ["query"]
}
}
}
]
# Anthropic Claude API (nativ)
tools = [
{
"name": "search_documents",
"description": "Sucht relevante Fragmente in der Unternehmenswissensdatenbank",
"input_schema": { # ← Anthropic: "input_schema", ohne "function"-Wrapper
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Text der Suchanfrage"
},
"top_k": {
"type": "integer",
"description": "Anzahl der Fragmente (Standard 5)"
}
},
"required": ["query"]
}
}
]
Wenn Sie LiteLLM oder LangChain verwenden – diese abstrahieren diesen Unterschied
und konvertieren das Format automatisch. Bei direkter Arbeit mit dem Anthropic SDK – nur input_schema.
Was das Modell zurückgibt und wie man das Ergebnis zurückgibt
Die meisten Tutorials stoppen damit, wie das Modell einen Tool-Aufruf zurückgibt.
Aber am häufigsten bleiben Entwickler beim nächsten Schritt hängen –
wie man das Ergebnis der Ausführung korrekt im nächsten Nachrichtenblock zurückgibt.
Schritt 1. Das Modell gibt einen Tool-Aufruf anstelle von Text zurück:
# Antwort des Modells (stop_reason: "tool_use")
{
"content": [
{
"type": "tool_use",
"id": "toolu_01XFDUDYJgAACTvYkLMeDRVQ", # ← id wird für den nächsten Schritt benötigt
"name": "search_documents",
"input": {
"query": "Bedingungen für die Kündigung des Vertrags",
"top_k": 5
}
}
],
"stop_reason": "tool_use"
}
Beachten Sie: In der Anthropic API heißt das Feld input (bereits ein Objekt),
nicht arguments (ein String wie bei OpenAI). Die Deserialisierung mit json.loads()
ist nur bei der Arbeit mit dem OpenAI-Format erforderlich.
Schritt 2. Ihr Code führt die Funktion aus und formuliert die nächste Anfrage:
import anthropic, json
client = anthropic.Anthropic()
# Erste Anfrage
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=1024,
tools=tools,
messages=[{"role": "user", "content": "Welche Bedingungen gelten für die Kündigung des Vertrags?"}]
)
# Erhalten Sie den Tool-Aufruf aus der Antwort
tool_use_block = next(b for b in response.content if b.type == "tool_use")
tool_result = search_documents(**tool_use_block.input) # Ihre Funktion
# Zweite Anfrage – geben Sie das Ergebnis zurück
follow_up = client.messages.create(
model="claude-opus-4-6",
max_tokens=1024,
tools=tools,
messages=[
{"role": "user", "content": "Welche Bedingungen gelten für die Kündigung des Vertrags?"},
{"role": "assistant", "content": response.content}, # ← die gesamte Antwort des Modells
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": tool_use_block.id, # ← id aus Schritt 1
"content": json.dumps(tool_result, ensure_ascii=False)
}
]
}
]
)
Drei kritische Details dieses Zyklus:
-
tool_use_id im Ergebnis muss exakt mit id aus dem Tool-Aufruf übereinstimmen –
andernfalls gibt die API einen Validierungsfehler zurück
-
In
messages wird die gesamte Antwort des Modells (response.content) übergeben,
nicht nur der Text – das Modell muss seinen eigenen Tool-Aufruf im Kontext sehen
-
Bei parallelen Aufrufen (mehrere Tool-Aufrufe in einer Antwort) –
müssen Sie für jede
id ein tool_result zurückgeben,
andernfalls gibt die nächste Anfrage einen Fehler zurück
Der Parameter tool_choice
Der Parameter tool_choice steuert den Entscheidungsmodus für den Aufruf eines Werkzeugs.
Offizielle Anthropic-Dokumentation
definiert vier Optionen:
| Wert |
Verhalten |
Wann zu verwenden |
⚠️ Stolperstein |
auto |
Das Modell entscheidet selbst: Text oder Tool-Aufruf |
Typisches Konversationsszenario. Standard, wenn Tools übergeben werden. |
Das Modell ruft das Tool möglicherweise nicht auf, wenn die Beschreibung unklar ist oder es sich „sicher“ ist, die Antwort aus eigenem Wissen zu geben – auch wenn die Daten veraltet sind |
any / required |
Das Modell muss mindestens ein Werkzeug aufrufen |
Strukturierte Ausgabe, obligatorische Protokollierung, erzwungene Abfrage an externe API |
Ruft das Werkzeug auch bei „Hallo“ auf – unnötige Token und Verzögerung. Nicht kompatibel mit erweiterter Denkweise in Claude (HTTP 400) |
none |
Das Modell ruft kein Werkzeug auf, generiert nur Text |
Antwort ausschließlich aus dem übergebenen Kontext; letzter Schritt nach Erhalt aller Ergebnisse |
Wenn Sie none zusammen mit tool_result in messages übergeben – gibt die API einen Fehler zurück: Tool-Definitionen müssen vorhanden sein |
{"type": "tool", "name": "..."} |
Erzwungener Aufruf eines bestimmten Werkzeugs |
Testen eines einzelnen Werkzeugs, deterministische Pipeline |
Nicht kompatibel mit erweiterter Denkweise. Das Modell generiert keinen Text vor dem Tool-Aufruf – auch wenn es explizit darum gebeten wird |
Hinweis zur Terminologie: OpenAI verwendet required,
Anthropic – any, um „mindestens ein Werkzeug aufrufen“ zu bezeichnen.
LiteLLM konvertiert automatisch zwischen den Formaten.
Dies ist nicht nur ein konzeptioneller Unterschied – es ist ein Unterschied darin, wer den Ablauf kontrolliert.
In einer RAG-Pipeline ist die Entscheidung zur Suche in der Architektur kodiert.
Bei Tool Use ist das Modell ein aktiver Teilnehmer an dieser Entscheidung.
Das Verständnis dieser Grenze bestimmt, welche Probleme Sie in der Produktion haben werden und wo Sie sie suchen müssen.
Klassisches RAG: deterministische Pipeline
Benutzeranfrage
→ Anfrage-Embedding ← Umwandlung von Text in einen Vektor
→ Suche in Vektor-DB (immer, bedingungslos)
→ Neuordnung der Ergebnisse
→ Kontextbildung (Prompt Stuffing)
→ Übergabe an LLM
→ Antwort
Jeder Schritt erfolgt unabhängig vom Inhalt der Anfrage.
Wenn der Benutzer fragt „wie viel ist 2+2“ – wird die Pipeline trotzdem ein Embedding erstellen,
zu Qdrant gehen, die Top-5-Fragmente abrufen und sie dem Modell im Kontext übergeben.
Das Modell erhält unnötigen Kontext und ist gezwungen, ihn zu ignorieren.
Der erste Schritt dieser Pipeline – das Embedding – verdient besondere Aufmerksamkeit:
hier wird Text in einen numerischen Vektor umgewandelt, der eine semantische Bedeutung trägt und nicht nur Schlüsselwörter.
Wie das technisch funktioniert –
Embeddings in einfachen Worten: Wie KI Bedeutung versteht, nicht nur Wörter
.
Mehr über die vollständige Mechanik der RAG-Pipeline von Chunking bis Reranking:
RAG im Jahr 2026: von PoC bis Produktion – der vollständige Leitfaden
.
Über den prinzipiellen Unterschied zwischen den Fähigkeiten einer „reinen“ LLM und einem RAG-System –
LLM vs. RAG im Jahr 2026: Warum es nicht dasselbe ist
.
Das ist kein Fehler – es ist ein bewusster architektonischer Preis für Vorhersehbarkeit.
Tool Use: das Modell als aktiver Agent
Benutzeranfrage
→ LLM analysiert Kontext und Absichten
→ Entscheidung: mit eigenem Wissen antworten / Tool aufrufen / mehrere Tools parallel aufrufen
↓ wenn Tool-Aufruf
→ Welches Werkzeug? Mit welchen Parametern?
→ JSON → Agent Scaffolding → Ausführung → Ergebnis → LLM
→ Endgültige Antwort
Das Modell generiert nicht nur Text – es trifft Entscheidungen über den Ablauf.
Auf die Frage „wie viel ist 2+2“ wird es direkt antworten, ohne ein Werkzeug zu berühren.
Auf die Frage „welche Bedingungen für die Vertragsauflösung“ – wird es search_documents aufrufen.
Auf die Frage „vergleiche Verträge A und B“ – vielleicht zwei parallele Aufrufe desselben Werkzeugs
mit unterschiedlichen Parametern.
Wo die eigentliche Grenze verläuft
Schlüsselanalogie: RAG ist ein Bibliothekar, der immer vor der Antwort zum Regal geht.
Tool Use ist ein Berater, der zuerst nachdenkt und dann entscheidet, ob er in die Dokumente schauen muss.
Der Berater ist effektiver – aber seine Entscheidungen sind weniger vorhersehbar.
| Merkmal |
RAG-Pipeline |
Tool Use |
| Wer entscheidet „suchen oder nicht“ |
Architektur – sucht immer |
Modell – abhängig vom Kontext |
| Anzahl der Datenquellen |
Normalerweise eine (Vektor-DB) |
Beliebige Anzahl von Tools |
| Vorhersehbarkeit des Verhaltens |
Hoch – immer derselbe Weg |
Niedriger – hängt von der Entscheidung des Modells ab |
| Latenz |
Stabil und vorhersehbar |
Variabel: von 0 bis N Tool-Aufrufen |
| Kosten pro Anfrage |
Fest |
Abhängig von der Anzahl der Aufrufe |
| Effizienz bei einfachen Anfragen |
Niedrig – unnötiger Abruf immer |
Hoch – das Modell überspringt das Überflüssige |
| Komplexität des Debugging |
Niedrig – ein deterministischer Pfad |
Höher – es müssen alle Entscheidungszyklen protokolliert werden |
| Risiko, das Benötigte „nicht zu finden“ |
Nur wenn der Retriever schlecht ist |
Zusätzlich, wenn das Modell beschließt, nicht zu suchen |
RAG innerhalb von Tool Use: was es bringt und was es kostet
Eine RAG-Pipeline kann als eines der Werkzeuge in einem Tool-Use-System implementiert werden –
das heißt, search_knowledge_base(query) wird zu einem Tool, das das Modell bei Bedarf aufruft.
Dies bringt einen echten Vorteil: unnötige Embedding-Anfragen und Suchen finden nicht statt,
es werden keine Token für die Kontextbildung verschwendet.
Aber es gibt einen Preis:
-
Neue Fehlerpunkte.
Bei klassischem RAG ist der Abruf garantiert. Bei Tool Use – kann das Modell entscheiden, nicht zu suchen,
wenn eine Suche kritisch erforderlich ist. Besonders gefährlich, wenn das Modell „sicher“
in der Antwort aus eigenem Wissen ist, aber dieses Wissen veraltet ist.
-
Die Qualität der Tool-Beschreibung wird entscheidend.
Wenn die
description vage ist oder das Szenario nicht abdeckt – wird das Modell das Tool nicht aufrufen.
Bei klassischem RAG beeinflusst die Beschreibung die Suchentscheidung überhaupt nicht.
Details zum Schreiben von Beschreibungen – in TU-2.
-
Die Beobachtbarkeit ist schwieriger.
In einer RAG-Pipeline gibt es immer ein Protokoll des Abrufs und des Ergebnisses.
Bei Tool Use müssen die Entscheidungen des Modells (aufgerufen/nicht aufgerufen),
die Aufrufparameter und das Ergebnis separat protokolliert werden – um zu verstehen, wo die Antwort falsch gelaufen ist.
Praktisches Fazit: wann was wählen
Bleiben Sie bei klassischem RAG, wenn:
die einzige Datenquelle die Unternehmensdokumentenbasis ist,
alle Anfragen eine Suche erfordern,
Vorhersehbarkeit und einfache Fehlersuche entscheidend sind,
die SLA für die Latenz streng ist.
Wechseln Sie zu Tool Use, wenn:
es mehrere verschiedene Datenquellen gibt (DB + API + Dateien),
ein Teil der Anfragen überhaupt keine externen Daten benötigt,
die Möglichkeit paralleler Anfragen an verschiedene Systeme erforderlich ist,
Sie ein agentisches System aufbauen, bei dem der Abruf nur eines von vielen Szenarien ist.
⚠️ Stolperstein
Das gefährlichste Szenario bei „RAG über Tool Use“:
Das Modell antwortet selbstbewusst und kohärent, aber ohne Tool-Aufruf –
weil es beschlossen hat, die Antwort selbst zu kennen.
Im Unternehmenskontext (Verträge, Preise, Vorschriften) bedeutet dies eine Antwort,
die formal richtig, aber inhaltlich veraltet sein kann.
Protokollieren Sie immer stop_reason: wenn es "end_turn" ohne vorheriges
"tool_use" ist – hat das Modell nicht gesucht. Entscheiden Sie, ob dies für Ihr Szenario akzeptabel ist.
Wo RAG und Tool Use sich überschneiden – und wo sie auseinandergehen
Der vorherige Abschnitt zeigte den Unterschied in der architektonischen Logik.
Hier ist die Praxis: wie diese beiden Ansätze in realen Systemen interagieren,
welche Kombinationsmuster funktionieren und wo die Grenze zwischen ihnen bewusst verschwimmt.
Drei Kombinationsmuster
Muster 1: RAG als eigenständiger Pipeline (ohne Tool Use)
Der klassische Fall. Retrieve findet immer statt, das Modell erhält den Kontext automatisch.
Geeignet, wenn alle Anfragen eine Suche erfordern und Vorhersehbarkeit wichtiger ist als Effizienz.
AskYourDocs
in der Basis-Konfiguration ist genau dieses Muster.
Muster 2: RAG als eines der Werkzeuge in einem Tool Use System
Das Modell erhält search_knowledge_base(query) als Tool und entscheidet, wann es aufgerufen werden soll.
Einfache Anfragen („Was ist PDF?“, „Hallo“) werden ohne Retrieve verarbeitet.
Komplexe oder spezifische Anfragen lösen eine Suche aus.
Dies erhöht die Effizienz, fügt aber einen neuen Fehlerpunkt hinzu: Das Modell ruft das Tool möglicherweise nicht auf, wenn es nötig wäre.
Muster 3: Mehrere spezialisierte Werkzeuge + RAG als eines davon
Die leistungsfähigste und komplexeste Variante.
Das Modell hat gleichzeitig Zugriff auf mehrere Werkzeuge:
tools = [
search_knowledge_base(query), # RAG für Unternehmensdokumente
get_contract_status(contract_id), # Anfrage an CRM/ERP
calculate_deadline(date, days), # Datumsberechnung
send_notification(user_id, text), # Aktion in einem externen System
]
Hier ist RAG nicht mehr die gesamte Pipeline, sondern ein spezialisiertes Werkzeug unter anderen.
Das Modell entscheidet selbst über die Kombination: zum Beispiel zuerst search_knowledge_base,
um die Vertragsbedingungen zu finden, dann get_contract_status, um den aktuellen Status zu überprüfen,
und schließlich eine Antwort basierend auf beiden Ergebnissen zu generieren.
Wo die Grenze verschwimmt: RAG mit interner Auswahl-Logik
Es gibt eine Zwischenvariante, die oft unterschätzt wird:
eine klassische RAG-Pipeline mit Pre-Retrieval-Routing im Inneren.
Bevor die Vektordatenbank abgefragt wird, entscheidet ein einfacher Klassifikator oder Prompt,
ob für diese Anfrage überhaupt ein Retrieve benötigt wird.
# Vereinfachte Pre-Retrieval-Routing-Logik
def should_retrieve(query: str) -> bool:
# Einfacher heuristischer Klassifikator
factual_keywords = ["Vertrag", "Bedingungen", "Preis", "Reglement", "Frist"]
return any(kw in query.lower() for kw in factual_keywords)
def answer(query: str) -> str:
if should_retrieve(query):
context = retriever.search(query)
return llm.generate(query, context=context)
else:
return llm.generate(query) # ohne Retrieve
Dies ist kein „reines“ Tool Use – die Entscheidung trifft der Code, nicht das Modell.
Aber auch kein „reines“ RAG – ein Retrieve findet nicht immer statt.
Ein solcher Hybrid bietet die Vorhersehbarkeit einer klassischen Pipeline
plus einen Teil der Effizienz des Tool Use-Ansatzes.
Der Preis dafür ist die Wartung des Klassifikators und das Risiko von Fehlalarmen.
Vergleich der Muster
| Muster |
Wer entscheidet über Retrieve |
Komplexität |
Am besten geeignet für |
| RAG-Pipeline |
Architektur (immer) |
Niedrig |
Eine Wissensbasis, alle Anfragen erfordern Suche |
| RAG + Pre-Retrieval-Routing |
Klassifikator im Code |
Mittel |
Gemischte Anfragen, Vorhersehbarkeit erforderlich |
| RAG als Tool in Tool Use |
LLM (basierend auf Kontext) |
Mittel |
Überwiegend dokumentenbezogene Anfragen + kleiner Prozentsatz an „reinen“ LLM-Anfragen |
| Mehrere Tools + RAG als eines davon |
LLM (basierend auf Kontext) |
Hoch |
Agentensysteme, mehrere Datenquellen, komplexe Workflows |
Wo sie sich konkret überschneiden: gemeinsame Komponenten
Unabhängig vom Muster stützen sich beide Ansätze auf die gleichen grundlegenden Komponenten:
-
Embedding-Modell – wird in RAG für die Vektorsuche benötigt und kann in Tool Use für die Tool-Suche benötigt werden, wenn es 50+ Werkzeuge gibt.
Wie Embeddings Text in einen semantischen Vektor umwandeln –
Embeddings in einfachen Worten: Wie KI Bedeutung versteht, nicht nur Wörter
.
-
Vektordatenbank – speichert in RAG Dokumenten-Chunks,
in Tool RAG-Systemen speichert sie Werkzeugbeschreibungen für die semantische Suche im Werkzeugregister.
-
Reranker – bewertet in RAG die Relevanz von Fragmenten neu,
in Tool Use kann er die Relevanz von Werkzeugen bei einem großen Register neu bewerten.
-
Observability-Schicht – in beiden Fällen ist es entscheidend zu protokollieren,
was gefunden/aufgerufen wurde und was in den Kontext des Modells gelangt ist.
⚠️ Fallstrick #3: Die Illusion der Wahl
Der häufigste architektonische Fehler beim Übergang von RAG zu Tool Use:
Der Entwickler ist überzeugt, dass „das Modell intelligent ist und selbst entscheidet, wann es suchen soll“ –
und investiert keine Zeit in eine qualitativ hochwertige description des Werkzeugs.
Dadurch ruft das Modell entweder das Werkzeug bei Anfragen, wo es benötigt wird, nicht auf,
oder ruft es bei Anfragen auf, wo es überflüssig ist.
Ein Werkzeug ohne klare Beschreibung ist eine Bibliothek ohne Katalog:
technisch verfügbar, aber praktisch unerreichbar.
Details zur Mechanik dieser Entscheidung und wie man eine Beschreibung schreibt – in
TU-2: Wie das Modell entscheidet, wann es sucht.
Dies ist eine der häufigsten terminologischen Vermischungen im Jahr 2026. Wenn Entwickler sehen, wie ein Modell get_weather() oder search_documents() aufruft, sagen sie: „Ich habe einen Agenten erstellt.“ Tatsächlich haben sie eine LLM mit einem Werkzeug erstellt – das ist ein wichtiger Schritt, aber keine Agentur.
Was ein Agent wirklich ist
Comet (2026) definiert einen Agenten anhand von drei obligatorischen Komponenten:
- Schleife (Loop): Ein Agent macht nicht einen Aufruf und stoppt. Er arbeitet in einer Schleife: denken → handeln → beobachten → wieder denken. Die Anzahl der Schritte ist nicht im Voraus festgelegt.
- Gedächtnis (Memory): Ein Agent erinnert sich daran, was er bereits getan hat, welche Ergebnisse er erzielt hat, und nutzt dies für zukünftige Entscheidungen. Nicht nur die Dialoghistorie – sondern auch die Zwischenergebnisse der Ausführung.
- Planung (Planning): Ein Agent kann eine komplexe Aufgabe in Teilaufgaben zerlegen, die Reihenfolge der Aktionen festlegen, den Plan ändern, wenn etwas schiefgeht.
Tool Use ohne diese drei Komponenten ist einfach nur LLM mit RPC-Aufrufen. Technisch unterscheidet es sich nicht davon, wie ein normales Programm eine Funktion aufruft. Der Unterschied liegt nur darin, wer entscheidet, welche Funktion aufgerufen wird: der Programmierer (Code) oder das Modell (Prompt).
Spektrum der Komplexität: vom einfachen Aufruf zum echten Agenten
Agentur ist keine binäre Eigenschaft (entweder Agent oder nicht), sondern ein Spektrum. Es ist praktisch, in „Graden der Agentur“ zu denken:
| Level | Was es kann | Beispiel | Ist das ein Agent? |
| L0: Single Tool Call | Ein Aufruf, ein Ergebnis, dann die Antwort | „Wie ist das Wetter in Kiew?“ → get_weather → Antwort | ❌ Nein, normales Tool Use |
| L1: Sequential Tool Calls | Mehrere Aufrufe nacheinander, ohne Rückmeldung zwischen ihnen | „Finde Dokument A und Dokument B“ → zwei Aufrufe nacheinander | ❌ Nein, nur eine Pipeline |
L2: Conditional Tool Calls | Das Ergebnis des ersten Aufrufs beeinflusst den zweiten | „Finde den Vertrag → wenn er aktiv ist, prüfe die Bedingungen“ | ⚠️ Teilweise – es gibt Ansätze von Planung |
| L3: ReACT-style Agent | Vollständige Schleife: Thought → Action → Observation → wiederholen | „Plane ein Meeting: finde freie Slots → wähle den besten → sende Einladung“ | ✅ Ja, klassischer Agent |
| L4: Autonomous Agent | Wie L3 + Langzeitgedächtnis + eigenständige Planung von Teilaufgaben | „Bereite den Monatsbericht vor“ → entscheidet selbst, welche Daten gesammelt werden, in welcher Reihenfolge, und tut dies | ✅ Ja, vollwertiger Agent |
Schlussfolgerung: Tool Use erscheint auf Level L0. Aber erst auf L3 erscheint echte Agentur – Schleife + Planung.
Warum es wichtig ist, das zu verstehen
Entwickler, die Tool Use mit Agenten verwechseln, machen drei typische Fehler:
- Fügen keine Schleife hinzu. Sie machen einen Aufruf, erhalten ein Ergebnis – und denken, das sei ein Agent. Aber wenn für die Antwort zwei Werkzeuge benötigt werden, stürzt das System ab.
- Übergeben keinen Ausführungskontext. Ein Agent muss nicht nur das Ergebnis der Funktion zurückerhalten, sondern auch Metainformationen: ob die Ausführung erfolgreich war, wie lange sie gedauert hat, welche Fehler aufgetreten sind. Ohne dies ist der Agent „blind“.
- Erwarten Magie. „Ich habe Werkzeuge hinzugefügt – warum baut das Modell nicht selbst einen komplexen Plan?“ Weil Planung eine separate Fähigkeit ist, die entweder richtiges Prompting oder spezielle Frameworks (LangGraph, AutoGen, CrewAI) erfordert.
Wie eine minimale Agentenschleife aussieht
Hier ist der prinzipielle Unterschied zwischen einem einmaligen Tool-Aufruf und einem zyklischen Agenten:
# ❌ Das ist KEIN Agent – das ist Tool Use response = client.messages.create( tools=[search_documents], messages=[{"role": "user", "content": "Finde Dokumente über den Vertrag"}] ) result = execute_tool(response.tool_call) final = client.messages.create( messages=[..., tool_result] ) # ✅ Das ist ein MINIMALER Agent – mit einer Schleife max_iterations = 5 while iterations < max_iterations and not finished: response = client.messages.create( tools=tools, messages=conversation_history ) if response.stop_reason == "tool_use": for tool_call in response.tool_calls: result = execute_tool(tool_call) conversation_history.append(tool_result(tool_call.id, result)) continue # ← Schleife! Wir kehren mit dem Ergebnis zum Modell zurück # stop_reason == "end_turn" – der Agent hat entschieden, dass die Antwort fertig ist finished = True return response.content
Der Unterschied liegt in einer Zeile – continue. Aber genau diese Zeile erzeugt die Schleife, die es dem Modell ermöglicht, mehrere Schritte zu tun, die Ergebnisse seiner Aktionen zu sehen und auf der Grundlage dessen, was es gesehen hat, weitere Entscheidungen zu treffen. Ohne Schleife ist es nur RPC. Mit Schleife – ein Keim eines Agenten.
⚠️ Fallstrick #4: Ein Agent ist nicht immer gut
Agenten klingen großartig. Aber sie haben einen echten Preis:
- Unvorhersehbare Anzahl von Aufrufen. Eine Anfrage kann 1 Tool-Aufruf generieren, eine andere 10 – abhängig von der Komplexität und Qualität der Prompts. Token-Kosten und Latenz werden undeterministisch.
- Risiko der Endlosschleife. Ohne Schutzmechanismen kann ein Agent in eine Endlosschleife geraten: ruft ein Werkzeug auf → erhält einen Fehler → ruft erneut auf → wieder ein Fehler. Fügen Sie immer
max_iterations und die Erkennung wiederholter Muster hinzu. - Schwieriges Debugging. Bei normalem Tool Use wissen Sie: Es gab einen Aufruf → Antwort erhalten. Bei einem Agenten – eine Kette von N Schritten, von denen jeder schiefgehen konnte. Beobachtbarkeitstools (langfuse, helicone, arize) werden nicht zur Option, sondern zur Notwendigkeit.
Praktischer Rat: Beginnen Sie mit L0 (Single Tool Call) oder L1 (Sequential). Fügen Sie Schleife und Planung nur hinzu, wenn eine einfache Pipeline wirklich an ihre Grenzen stößt. Ein Agent ist ein Werkzeug für komplexe Aufgaben, keine Standardarchitektur.
Kurz gesagt: Merken Sie sich die Formel
Tool Use = LLM entscheidet, welches Werkzeug aufgerufen werden soll.
Agent = Tool Use + Schleife + Gedächtnis + Planung.
Wenn Sie nur die erste Zeile haben – haben Sie keinen Agenten. Und das ist in Ordnung. Die meisten Aufgaben erfordern keine vollständige Agentur. Aber es ist wichtig, die Dinge beim Namen zu nennen, um die richtigen Erwartungen bei Team und Stakeholdern zu wecken.
Von der RAG-Pipeline zu Tool Use: Was kommt als Nächstes
Wenn Sie aus dem
RAG-Hub
kommen, sieht Ihr aktueller Stack ungefähr so aus: Dokumente → Chunking → Embed → Qdrant → BM25 + Rerank → LLM.
Das ist eine klassische RAG-Pipeline – deterministisch, vorhersehbar, gut abgestimmt.
Der Tool Use Hub, den Sie gerade lesen, beschreibt, was um diese Pipeline herum geschieht:
- Wie das Modell entscheidet, ob überhaupt eine Suche gestartet wird → Wie das LLM-Modell entscheidet, wann es sucht – Mechanik der Entscheidungsfindung
AskYourDocs
– ein konkretes Produktbeispiel, bei dem die RAG-Pipeline eines der Werkzeuge in einem breiteren System ist:
hybride Suche in Unternehmensdokumenten, vollständige Datenisolierung auf dem Kundenserver,
ohne Vendor-Lock-in auf LLM-Provider-Ebene.
❓ Häufig gestellte Fragen
Was ist der Unterschied zwischen Function Calling und Tool Use?
Function Calling ist der ursprüngliche Begriff von OpenAI. Tool Use ist ein breiterer Begriff von Anthropic,
der auch integrierte Werkzeuge (Websuche, Code-Interpreter) umfasst.
Die Mechanik ist die gleiche: Das Modell gibt JSON zurück, Ihr Code führt es aus.
Führt die LLM die Funktion selbst aus?
Nein. Das Modell formuliert eine strukturierte JSON-Anfrage mit dem Funktionsnamen und den Argumenten.
Die Ausführung erfolgt immer auf der Seite Ihrer Anwendung.
Wodurch unterscheidet sich RAG von Tool Use?
RAG ist eine deterministische Pipeline, bei der Retrieve immer stattfindet.
Tool Use ist ein Mechanismus, bei dem das Modell selbst entscheidet, ob ein Werkzeugaufruf erforderlich ist.
RAG kann als eines der Werkzeuge in einem Tool Use-System implementiert werden.
Wann sollte tool_choice: required verwendet werden?
Nur in deterministischen Pipelines – strukturierte Ausgabe, obligatorisches Logging.
Im Konversationsmodus führt dies zu unnötigen Tool-Aufrufen und Token-Kosten.
Außerdem sind required / any nicht kompatibel mit Extended Thinking in Claude.
✅ Schlussfolgerungen
- Function Calling und Tool Use – die gleiche Mechanik, unterschiedliche Namen. Das Modell formuliert JSON, Ihr Code führt es aus.
tool_choice bietet drei Kontrollmodi: auto (Standard), required (erzwungen), none (nur Text).
- RAG-Pipelines und Tool Use existieren auf unterschiedlichen Abstraktionsebenen – die erste ist deterministisch, die zweite adaptiv.
- RAG kann ein Werkzeug in einem Tool Use-System sein – aber das erhöht die Unvorhersehbarkeit und erfordert eine genaue Werkzeugbeschreibung.
- Klassisches RAG bleibt die beste Wahl für Produkte mit einer einzigen Wissensbasis und strengen Anforderungen an die Vorhersehbarkeit.
Nächster Schritt: Wie genau das Modell entscheidet, ob es ein Werkzeug aufrufen soll oder nicht –
und wie die Werkzeugbeschreibung dies beeinflusst – wird in
TU-2: Wie das Modell entscheidet, wann es sucht.
Quellen
Symflower – Function calling in LLM agents (2025) ·
Martin Fowler – Function calling using LLMs (2025) ·
Anthropic Docs – How to implement tool use ·
Prompt Engineering Guide – Function Calling with LLMs ·
Simplicity is SOTA – How LLMs are trained for function calling (2025) ·
Berkeley BFCL V4 (2025) ·
Comet – Agent Orchestration (2026)