Die Bezeichnung “Tool Calling” oder “Function Calling” ist an sich oft verwirrend, weil es den Anschein erweckt, als würde das neuronale Netz (LLM) den Code selbst ausführen.
Wie funktioniert Tool Calling in OpenClaw oder GitHub Copilot tatsächlich?
Die gesamte Magie eines “Agenten” (egal ob OpenClaw, NanoClaw, ZeroClaw, Hermes, GitHub Copilot oder ChatGPT) entsteht aus einem Dialog (Ping-Pong) zwischen dem Modell und dem Executor (nehmen wir OpenClaw als Beispiel).
Das Modell führt den Code niemals selbst aus. Ein LLM ist lediglich ein Textgenerator. Es hat keine Ahnung, wie man Bash, Node.js oder Python ausführt, wie man eine Datei liest, eine Datenbankabfrage macht oder sich auf einer Website einloggt.
Stellen wir uns vor, ein Benutzer schreibt in Telegram: “Wie viel Zucker brauche ich für das Charlotte-Rezept?”.
Unter der Haube verpackt Telegram diese Anfrage als JSON-Objekt und reicht sie an OpenClaw weiter:
{
"message": {
"text": "Wie viel Zucker brauche ich für das Charlotte-Rezept?",
"chat": { "id": 123456789 }
}
} Schritt 1: OpenClaw bereitet den Weg vor (System Prompt)
OpenClaw ist dumm - es weiß nicht, was es mit dieser Benutzeranfrage anfangen soll - es nimmt einfach die Nachricht des Benutzers, “hängt” eine Liste seiner Werkzeuge (Tools) im JSON Schema-Format an und sendet die Anfrage an das Modell - es fragt das Modell im Grunde: Hier ist, was ich kann, und hier ist die Anfrage des Benutzers - was soll ich damit machen?
Es sendet eine solche Anfrage an das Modell:
{
"messages": [
{
"role": "user",
"content": "Wie viel Zucker brauche ich für das Charlotte-Rezept?"
}
],
"tools": [
{
"type": "function",
"function": {
"name": "search_files",
"description": "Sucht Dateien nach Name oder Muster",
"parameters": {
"type": "object",
"properties": {
"query": { "type": "string" }
},
"required": ["query"]
}
}
},
{
"type": "function",
"function": {
"name": "read_file",
"description": "Liest den Dateiinhalt",
"parameters": {
"type": "object",
"properties": {
"path": { "type": "string" }
},
"required": ["path"]
}
}
},
{
"type": "function",
"function": {
"name": "list_files",
"description": "Zeigt die Liste der Dateien in einem Verzeichnis",
"parameters": {
"type": "object",
"properties": {
"path": { "type": "string" }
}
}
}
},
{
"type": "function",
"function": {
"name": "run_terminal_command",
"description": "Führt einen Befehl im Terminal aus",
"parameters": {
"type": "object",
"properties": {
"command": { "type": "string" }
},
"required": ["command"]
}
}
},
{
"type": "function",
"function": {
"name": "http_request",
"description": "Führt eine HTTP-Anfrage an eine externe API aus",
"parameters": {
"type": "object",
"properties": {
"url": { "type": "string" },
"method": { "type": "string" }
},
"required": ["url", "method"]
}
}
}
]
} Schritt 2: Das Modell versteht, was zu tun ist
Das Modell (zum Beispiel GPT-4o, Claude 3.7 Sonnet oder Gemini 1.5 Pro) empfängt diese Anfrage. Es sieht die Frage des Benutzers und sieht direkt vor sich eine ganze Reihe von Werkzeugen. Dann gleicht es die Aufgabe des Benutzers mit den verfügbaren Tools ab und versucht, ein geeignetes auszuwählen.
Da der Benutzer nach einem Rezept fragt, muss das Modell erraten, wo es danach suchen soll. Und genau hier liegt eine wichtige Nuance: Das Modell kann einen Fehler machen und das falsche Tool auswählen.
Zum Beispiel könnte es denken: “Aha, ein Rezept! Ich werde im Internet danach suchen!” und versuchen, einen http_request an Google zu stellen. Oder das Modell könnte versuchen, den Dateinamen zu “erraten” und sofort read_file mit dem Pfad path="charlotte.txt" aufrufen, was zu einem Fehler führt, falls der Pfad nicht existiert. Wenn jedoch ein gutes Suchwerkzeug vorhanden ist (und vielleicht die richtigen Systemanweisungen), wird das Modell erkennen, dass es besser ist, zuerst auf der lokalen Festplatte nach einer Datei zu suchen, und wird search_files wählen.
In der Praxis erfolgt die Auswahl nicht durch “Magie”, sondern durch die Kombination mehrerer Signale: wonach der Benutzer fragt, wie die Tools benannt sind, was in ihrer description steht, welche Argumente sie akzeptieren und was zuvor in diesem Dialog passiert ist.
Daher erfordert das Lösen einer Aufgabe oft eine ganze Kette von Aufrufen. Zum Beispiel bittet das Modell den Agenten zuerst, search_files aufzurufen, um den genauen Dateipfad zu finden, und erst dann bittet es darum, read_file aufzurufen, um den Inhalt zu lesen.
Unser Beispiel für eine Kette:
- Der Benutzer schreibt: “Wie viel Zucker brauche ich für das Charlotte-Rezept?”.
- Das Modell formuliert eine Antwort und bittet OpenClaw (GitHub Copilot, Antigravity oder ChatGPT), das Tool
search_filesmit dem Parameterquery="charlotte"aufzurufen, damit dieses die Suchergebnisse zurückgibt, da das Modell den genauen Pfad zum Rezept noch nicht kennt. - OpenClaw durchsucht die Festplatte und liefert dem Modell ein paar Optionen zurück, zum Beispiel:
[{"path":"/alte_archive/omas_charlotte.txt"}, {"path":"/dokumente/charlotte_rezept.txt"}]. Das Modell analysiert diese Liste und entscheidet selbst, welche Datei am besten passt. - Das Modell hat aus der Liste den richtigen Pfad ausgewählt und sendet eine zweite Anfrage an OpenClaw mit einem neuen Tool Call — diesmal ist es
read_filemit dem Argumentpath=/dokumente/charlotte_rezept.txt. Das heißt, es sagt OpenClaw: “Lies diese Datei mitread_file“. - OpenClaw liest die Datei und sendet deren Inhalt zurück an das Modell. Erst nachdem es den Text des Rezeptes studiert hat, schreibt das Modell die finale Antwort an den Benutzer.
Tool Calling muss also keine einzelne Aktion sein, sondern kann eine kleine Kette sein: gefunden -> gelesen -> geantwortet.
Das Modell liest die Datei NICHT selbst und sucht NICHT selbst auf der Festplatte oder im Internet — es wählt einfach ein Tool aus der Liste aus, die der Agent bereitstellt. Nach der Auswahl teilt es dem Agenten mit: “Verwende dieses Tool”. Der Agent wendet es physisch an und gibt das Ausführungsergebnis an das Modell zurück.
Technisch gesehen formuliert der allererste Schritt eine spezielle Antwort (JSON), in der das Modell sagt: “Hey, Agent (OpenClaw, GitHub Copilot oder ChatGPT), rufe diese Funktion search_files von dir mit dem Argument query="charlotte" auf und gib mir das Ergebnis zurück - ich werde es mir ansehen”.
So sieht die erste Antwort des LLMs in OpenClaw aus:
{
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_search_6c3bc42b",
"type": "function",
"function": {
"name": "search_files",
"arguments": "{"query":"charlotte"}"
}
}
]
} Schritt 3: OpenClaw (der Executor) wendet das erste Tool an
OpenClaw erhält diese JSON-Struktur auf dem Server. Es sieht: “Das Modell verlangt, search_files mit dem Parameter query="charlotte" auszuführen”.
Genau in diesem Moment führt der OpenClaw-Code auf dem Server physisch eine Dateisuche nach dem Wort “charlotte” auf der Festplatte durch. OpenClaw denkt nicht nach - es führt einfach die Funktion aus und gibt das Suchergebnis (ein Array der gefundenen Pfade) zurück an das Modell und hängt es an den Nachrichtenverlauf an.
Schritt 4: Das Modell analysiert das Ergebnis und bittet darum, die Datei zu lesen
Das Modell erhält die Liste der gefundenen Dateien: [{"path":"/alte_archive/omas_charlotte.txt"}, {"path":"/dokumente/charlotte_rezept.txt"}].
Es schaut diese an und trifft eine Entscheidung: “Aha, das Rezept, das ich brauche, befindet sich höchstwahrscheinlich in der zweiten Datei”. Und jetzt gibt es eine neue JSON-Antwort mit der Bitte aus, das zweite Tool aufzurufen — read_file:
{
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_read_d88b07ff",
"type": "function",
"function": {
"name": "read_file",
"arguments": "{"path":"/dokumente/charlotte_rezept.txt"}"
}
}
]
} Schritt 5: OpenClaw liest die Datei und gibt das Ergebnis zurück
OpenClaw empfängt diese neue Anweisung. Das Skript wird ausgeführt, liest physisch die Datei charlotte_rezept.txt von der Festplatte und erhält den Text: "Äpfel - 1 kg, Mehl - 200g, Zucker - 1 Tasse".
Nun erstellt OpenClaw eine neue Anfrage an das LLM und übergibt dabei den gesamten bisherigen Verlauf dieser Kette:
{
"messages": [
{
"role": "user",
"content": "Wie viel Zucker brauche ich für das Charlotte-Rezept?"
},
{
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_search_6c3bc42b",
"type": "function",
"function": {
"name": "search_files",
"arguments": "{"query":"charlotte"}"
}
}
]
},
{
"role": "tool",
"tool_call_id": "call_search_6c3bc42b",
"content": "[{"path":"/alte_archive/omas_charlotte.txt"}, {"path":"/dokumente/charlotte_rezept.txt"}]"
},
{
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_read_d88b07ff",
"type": "function",
"function": {
"name": "read_file",
"arguments": "{"path":"/dokumente/charlotte_rezept.txt"}"
}
}
]
},
{
"role": "tool",
"tool_call_id": "call_read_d88b07ff",
"content": "Äpfel - 1 kg, Mehl - 200g, Zucker - 1 Tasse"
}
],
"tools": [
{
"type": "function",
"function": {
"name": "search_files",
"description": "Sucht Dateien nach Name oder Muster",
"parameters": { "type": "object", "properties": { "query": { "type": "string" } }, "required": ["query"] }
}
},
{
"type": "function",
"function": {
"name": "read_file",
"description": "Liest den Dateiinhalt",
"parameters": { "type": "object", "properties": { "path": { "type": "string" } }, "required": ["path"] }
}
},
"..."
]
} Diese Anfrage fliegt wieder zum LLM-Modell (z.B. bei OpenAI).
Wichtige Nuance: Gedächtnis und Kontextfenster
Bemerken Sie, wie die Liste der
messageswächst? Klassische LLMs (zumindest die überwältigende Mehrheit der Modelle bis 2025-2026) arbeiten von Natur aus “ohne Gedächtnis” (sie sind stateless). Daher fügt OpenClaw (und jeder andere Agent) bei jeder neuen Interaktion alle vergangenen Nachrichten (Benutzeranfragen, Tool-Aufrufe und deren Ergebnisse) hinzu.Diese Nachrichten sammeln sich an und werden immer wieder übertragen, solange sie in das Kontextfenster passen (das Speicherlimit eines bestimmten Modells, z.B. 128 Tausend Token). Sobald der Dialogverlauf zu groß wird und dieses Limit überschreitet, beginnt der Agent, die ältesten Nachrichten vom Anfang des Verlaufs abzuschneiden (weshalb das Modell anfängt zu “vergessen”), um Platz für neue Schritte zu schaffen und innerhalb der Grenzen des Kontextfensters des Modells zu bleiben.
P.S. Die KI-Industrie entwickelt sich rasant. Mittlerweile kommen Modelle mit eingebautem Gedächtnis (Stateful APIs) und Agenten-Modelle auf den Markt, die wissen, wie man Dialogkontexte auf ihrer Seite speichert oder sogar ihre eigenen Tools “unter der Haube” haben. Dennoch ist der oben beschriebene Mechanismus der ‚stateless‘-Kommunikation (bei dem der Client selbst die gesamte Historie und die Tool-Schemas in JSON überträgt) die Basis, auf der 99 % der aktuellen KI-Anwendungen aufbauen.
Schritt 6: Die finale Antwort
Das LLM (z.B. OpenAI) schaut sich die aktualisierte Historie an. Es sieht:
- Der Benutzer hat nach der nötigen Zuckermenge für das Charlotte-Rezept gefragt.
- Ich habe darum gebeten, die Suchfunktion aufzurufen.
- Mir wurde eine Liste von zwei Dateien zurückgegeben.
- Ich habe darum gebeten, die Lesefunktion für die zweite Datei aufzurufen.
- Die Funktion hat die Datei gelesen und den Rezept-Text zurückgegeben.
Das Modell analysiert diesen Text und generiert die finale menschliche Antwort: “Für die Zubereitung der Charlotte benötigen Sie 1 Tasse Zucker”.
So sieht diese finale JSON-Ausgabe vom Modell technisch aus:
{
"role": "assistant",
"content": "Für die Zubereitung der Charlotte benötigen Sie 1 Tasse Zucker"
} Dieses JSON wird an OpenClaw zurückgegeben, und OpenClaw extrahiert den Text aus dem Feld content und zeigt ihn dem Benutzer in der Oberfläche an.
OpenClaw, GitHub Copilot und andere funktionieren absolut identisch: Sie stellen dem LLM eine Liste von Tools zur Verfügung, bitten es um eine Entscheidung und führen diese dann selbst lokal aus.