Was Function Calling bei LLMs wirklich macht
Fragen Sie ein Modell âwie ist das Wetter gerade in Austin" ohne jede Verbindung zur AuĂenwelt, und es hat zwei Optionen: sagen, dass es das nicht weiĂ, oder sich etwas ausdenken. Function Calling gibt ihm eine dritte Option. Es beschreibt, was es braucht, gibt diese Beschreibung an Ihren Code weiter und wartet auf eine echte Antwort, bevor es antwortet.
Der Name ist etwas irrefĂŒhrend. Das Modell ruft nichts auf. Es gibt einen Block strukturierter Daten aus, der sagt, welches Tool es möchte und mit welchen Argumenten, und Ihre Anwendung entscheidet, ob sie es ausfĂŒhrt und was sie mit dem Ergebnis macht. âTool Use" ist der genauere Begriff und der, den Anthropics Dokumentation verwendet; OpenAI und Google sprechen meist von Function Calling. Der Mechanismus ist unter beiden Namen derselbe. Das Modell erzeugt immer nur eine Anfrage, nie den Seiteneffekt.
Warum das Modell Tools anfragt, sie aber nie selbst ausfĂŒhrt
Stellen Sie sich einen Kunden an einem Tresen vor, der auf Gerichte auf der Speisekarte zeigen und sagen kann, wie viele er möchte, aber nie hinter den Tresen geht. Das Modell ist dieser Kunde: Es liest die Speisekarte, die Sie ihm gegeben haben (die Tool-Definitionen), wÀhlt ein Gericht aus und sagt, wie viele es möchte (die Argumente). Ihr Code ist die Person hinter dem Tresen, die die Bestellung zusammenstellt und eine Bestellung ablehnen kann, die keinen Sinn ergibt.
Diese Trennung ist das gesamte Sicherheitsmodell. Ein Tool-Call ist ein Vorschlag, den Ihr Code validieren oder ablehnen kann, genau wie jede andere Eingabe aus einer nicht vertrauenswĂŒrdigen Quelle. Denn genau das ist er. Ein Modell, das durch Prompt Injection von einer bösartigen Webseite manipuliert wurde, kann trotzdem nur einen Tool-Call anfragen. Es kann Ihre Validierung nicht ĂŒberspringen und direkt auf die Datenbank zugreifen.
Wie man ein Tool mit JSON-Schema definiert
Jeder Anbieter will fĂŒr jedes Tool dieselben drei Dinge: einen Namen, eine Beschreibung, mit der das Modell entscheidet, wann das Tool passt, und ein JSON-Schema fĂŒr die Argumente. Hier ist ein Wetter-Tool fĂŒr die OpenAI Chat Completions API:
| |
Stecken Sie mehr Zeit in die Beschreibung als in das Schema. Das Modell wĂ€hlt ein Tool, indem es die Anfrage des Nutzers mit den Beschreibungen in der Liste vergleicht, die Sie ihm geschickt haben. Eine vage Beschreibung (âWetterzeug") wird entweder von einem besser beschriebenen Tool verdrĂ€ngt, das etwas anderes macht, oder schlĂ€gt bei Anfragen zu, die es nicht behandeln sollte. Schreiben Sie sie so, als mĂŒssten Sie die Funktion einem Kollegen erklĂ€ren, der genau einen Satz darĂŒber lesen wird.
Wie der Request-Response-Zyklus beim Function Calling funktioniert
Ein Tool-Call braucht mindestens zwei Requests. Hier ist der komplette Ablauf mit der OpenAI API:
| |
Die erste Antwort beantwortet die Frage nicht. Sie kommt mit
finish_reason gleich tool_calls und ohne Textinhalt zurĂŒck, weil das
Modell entschieden hat, dass es get_weather braucht, bevor es etwas
NĂŒtzliches sagen kann. call.function.arguments kommt als JSON-String
an, nicht als bereits geparstes Objekt, also ist json.loads nicht
optional. get_weather fĂŒhren Sie selbst aus (es ist eine ganz normale
Python-Funktion; das Modell hat keine Möglichkeit, sie auszufĂŒhren), und
hÀngen danach das Ergebnis als Nachricht mit role: "tool" und der
passenden tool_call_id an.
Erst der zweite Request, der nun dieses Ergebnis enthÀlt, liefert Ihnen
einen echten Satz zurĂŒck. Wenn Sie die Assistant-Nachricht mit ihren
tool_calls anhÀngen, aber das passende Tool-Ergebnis weglassen, lehnt die
API den nÀchsten Request ab, statt zu raten.
Wie sich Anthropics Tool Use von OpenAIs Function Calling unterscheidet
Gleicher Mechanismus, andere Feldnamen. Wenn Sie zwischen Anbietern wechseln oder beide unterstĂŒtzen, entstehen Ihre Bugs genau hier:
| Konzept | OpenAI | Anthropic |
|---|---|---|
| Feld fĂŒr die Tool-Liste | tools, jedes Tool verpackt in {"type": "function", "function": {...}} | tools, jedes Tool flach: {"name", "description", "input_schema"} |
| SchlĂŒssel fĂŒr das Argumentschema | parameters | input_schema |
| Anfrage des Modells | tool_calls-Array auf der Nachricht, arguments als JSON-String | tool_use-Content-Block, input bereits als geparstes Objekt |
| Ergebnis zurĂŒcksenden | neue Nachricht, role: "tool", tool_call_id | neue User-Nachricht, Content-Block type: "tool_result", tool_use_id |
| Fehlgeschlagenen Aufruf signalisieren | kein eigenes Feld: Fehler in content ablegen | is_error: true am tool_result-Block |
Die Falle liegt im Format der Argumente. Anthropic gibt Ihnen input schon
als geparstes Python-Dict oder JS-Objekt; OpenAI gibt Ihnen einen String,
den Sie selbst durch json.loads schicken mĂŒssen. Code, der fĂŒr den einen
Anbieter geschrieben und auf den anderen gerichtet wird, lÀsst sich
problemlos importieren und scheitert dann beim ersten Tool-Call. Wenn Sie
beide unterstĂŒtzen, schreiben Sie eine einzige Normalisierungsfunktion,
durch die beide Pfade laufen, bevor Ihre Tool-Implementierungen die
Argumente ĂŒberhaupt sehen.
Wie parallele Tool-Calls und mehrstufige Schleifen funktionieren
Beide APIs können in einer einzigen Antwort mehr als einen Tool-Call
zurĂŒckgeben. Fragen Sie nach dem Wetter in drei StĂ€dten, und Sie erhalten
drei EintrĂ€ge in tool_calls, nicht drei separate Hin- und RĂŒckfahrten.
FĂŒhren Sie sie aus (parallel, wenn sie unabhĂ€ngig sind) und hĂ€ngen Sie alle
drei Ergebnisse an, bevor der Folge-Request geht. Jede vom Modell
ausgegebene Call-ID braucht ein Ergebnis; schicken Sie nur eines von drei
zurĂŒck, und der Request schlĂ€gt fehl.
Manche Aufgaben brauchen mehrere Runden: einen Nutzer nachschlagen, dann dessen Bestellverlauf, dann die ĂŒberfĂ€llige Bestellung markieren. Schreiben Sie das als Schleife, die so lange das Modell aufruft und ausfĂŒhrt, was es verlangt, bis eine Antwort ohne Tool-Calls zurĂŒckkommt. Setzen Sie dann eine Obergrenze. Nichts in der API hindert ein Modell daran, neunmal hintereinander dasselbe Tool anzufragen, wenn die Ergebnisse es keiner Antwort nĂ€herbringen. Ein festes Limit, etwa 10 oder 20 Iterationen, macht daraus einen klaren Fehler statt einer auĂer Kontrolle geratenen Rechnung.
HĂ€ufige Fehler beim Function Calling
Argumente als vertrauenswĂŒrdige Eingabe behandeln. args["city"]
stammt aus einem Modell, was bedeutet, dass es aus jedem Text stammt, der
die Konversation gefĂŒttert hat, einschlieĂlich einer gescrapten Webseite
oder eines Dokuments, das das Modell zusammenfassen sollte. Validieren Sie
es, bevor es eine Datenbankabfrage oder einen Shell-Befehl erreicht. Ein
Tool, das SQL durch Interpolieren der Modellargumente baut, hat dieselbe
Injection-AngriffsflÀche wie eines, das SQL aus einem Webformular baut.
Dem Schema wie einer Garantie vertrauen. Das Modell hÀlt sich meist an
required und enum, aber nicht perfekt. FrĂŒher oder spĂ€ter ĂŒbergibt es
"unit": "F" statt "fahrenheit" oder lÀsst ein Pflichtfeld weg.
Validieren Sie, und geben Sie als Tool-Ergebnis eine klare Fehlermeldung
zurĂŒck, statt abzustĂŒrzen. Sagen Sie dem Modell, was falsch war, und es
kann in der nÀchsten Runde oft mit korrigierten Argumenten erneut
versuchen.
Das Modell destruktive Tools allein auswÀhlen lassen. Wenn ein Tool
Daten löscht oder eine E-Mail verschickt, ist tool_choice auf automatisch
zu lassen die falsche Standardeinstellung. Halten Sie destruktive Tools aus
der Liste heraus, bis ein Mensch die konkrete Aktion genehmigt hat, oder
machen Sie den Effekt umkehrbar (einen Entwurf statt einer versendeten
E-Mail) und lassen Sie einen separaten Schritt ihn bestÀtigen.
Wann man Function Calling nicht einsetzen sollte
Jeder Tool-Call fĂŒgt dem Modell eine zusĂ€tzliche Hin- und RĂŒckfahrt hinzu, plus die Latenz, die das Tool selbst mitbringt. Wenn das âTool" ohnehin nur eine statische Tatsache zurĂŒckgeben wĂŒrde, legen Sie diese Tatsache in den Prompt oder in den abgerufenen Kontext und sparen Sie sich die Hin- und RĂŒckfahrt; dafĂŒr ist das RAG-Retrieval da. Und wenn die Entscheidung eigentlich eine Klassifikation mit einer kleinen, festen Menge an Ergebnissen ist (dieses Ticket an eine von vier Warteschlangen weiterleiten), antwortet ein typisierter, nicht generativer Aufruf schneller und gĂŒnstiger, als ein allgemeines Chat-Modell ein Tool auswĂ€hlen zu lassen. Genau dafĂŒr sind System-One-Modelle gebaut.
Function Calling rechtfertigt seine Kosten, wenn die Aktion von Laufzeitdaten abhĂ€ngt, die das Modell nicht im Prompt haben kann, und die Menge möglicher Aktionen zu offen ist, um sie als Zustandsmaschine festzulegen. Es ist auĂerdem die Schleife hinter jedem CLI-Coding-Agenten: eine Datei lesen, einen Test ausfĂŒhren, entscheiden, was als NĂ€chstes kommt, ein weiteres Tool aufrufen.
Beginnen Sie mit einem Tool, einer fest codierten Python-Funktion dahinter und einer Schleife, die nach einer einzigen Hin- und RĂŒckfahrt stoppt. Bringen Sie Argumentvalidierung und Fehlerpfad in Ordnung, bevor Sie ein zweites Tool hinzufĂŒgen. Die meisten Bugs in einem Setup mit mehreren Tools stellen sich als das erste Tool heraus, das Argumente falsch behandelt, mit denen es nicht gerechnet hat.