Function Calling
Einem LLM 299 Endpoints als 299 Tools zu geben, liegt nahe – und ist falsch. Hier siehst du den Aufbau, der funktioniert, und die vier Fehler, die du von Anfang an ausschließen solltest.
Definiere keine 299 Tools
Bei allen großen Anbietern wird das Modell schlechter, je länger die Tool-Liste ist: Die Schemas füllen das Kontextfenster, bevor das Gespräch überhaupt beginnt, und sobald sich die Beschreibungen mehrerer Tools überschneiden, wählt das Modell ungenauer aus. Bei 299 Endpoints, von denen die meisten dieselben vier Felder erwarten, würdest du Tausende Tokens pro Runde ausgeben – nur damit das Modell schlechter auswählt.
Definiere ein Tool, höchstens zwei. Das Modell übergibt die Route als Argument, statt zwischen Hunderten Schemas wählen zu müssen.
Der Aufbau mit einem Tool
{
"name": "occult_api",
"description":
"Vedic astrology calculations from the Occult API. Call this for anything involving a birth chart, panchanga, dasha, muhurta, matching or numerology. Do not compute astrology yourself - planetary positions require an ephemeris and cannot be derived from a date.",
"input_schema": {
"type": "object",
"properties": {
"route": {
"type": "string",
"description": "Endpoint path, e.g. /api/astro/panchanga/. Use the catalogue at https://occultapi.com/llms.txt to choose one."
},
"body": {
"type": "object",
"description": "Request body. Always include date_time (ISO 8601 with offset), latitude, longitude, timezone_as_float. Batch calculations with a keys array where the endpoint supports it."
}
},
"required": ["route", "body"]
}
}Die Beschreibung hat zwei Aufgaben. Sie sagt, wann das Tool zum Einsatz kommt, und sie sagt dem Modell, dass es nicht selbst rechnen soll – das ist wichtiger, als es klingt. Fragt man ein Modell nach einem Nakshatra, liefert es bereitwillig ein plausibles aus seinen Trainingsdaten, wenn ihm niemand sagt, dass Planetenpositionen eine Ephemeride brauchen.
Der Handler
async function occultApi({ route, body }) {
const response = await fetch(`${process.env.OCCULT_API_BASE}${route}`, {
method: "POST",
headers: {
"X-API-Key": process.env.OCCULT_API_KEY, // server-side only
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
const payload = await response.json();
// 402 means out of credits. It is NOT transient - retrying spends nothing
// and fixes nothing, so surface it rather than backing off.
if (response.status === 402) {
return { error: "insufficient_credits", retryable: false };
}
// The envelope is the same on every endpoint: branch on is_error, and hand
// the model the message rather than a stack trace it cannot act on.
if (payload.is_error) {
return { error: payload.message, retryable: false };
}
return payload.data;
}Drei Dinge darin solltest du beibehalten, wenn du ihn anpasst. Der Schlüssel wird auf dem Server gelesen – ein Schlüssel im Browser-Code ist ein Schlüssel, mit dem bald jemand anderes bezahlt. Ein 402 wird nicht wiederholt – er heißt, dass das Guthaben leer ist; eine Backoff-Schleife kostet nur Zeit und löst nichts. Die Fehlermeldung wird durchgereicht – die API sagt, welches Feld falsch war, und ein Modell mit dieser Information korrigiert seine Anfrage in der nächsten Runde selbst.
Der Aufbau mit zwei Tools – wenn das Modell suchen muss
Stellen deine Nutzer offene Fragen, weiß das Modell nicht, welche Route es braucht. Gib ihm dann zusätzlich ein Such-Tool. Die Suche kostet keine Credits – das Erkunden ist also gratis, abgerechnet wird nur die Antwort.
[
{
"name": "occult_search",
"description": "Find the right Occult API endpoint by name or by what it calculates, e.g. 'manglik' or 'sunrise'. Returns routes and their request fields. Costs nothing.",
"input_schema": {
"type": "object",
"properties": { "query": { "type": "string" } },
"required": ["query"]
}
},
{
"name": "occult_call",
"description": "Call an Occult API endpoint found with occult_search. One credit per successful call (the PDF reports and chat cost 25); failures are free.",
"input_schema": {
"type": "object",
"properties": {
"route": { "type": "string" },
"body": { "type": "object" }
},
"required": ["route", "body"]
}
}
]Lass occult_search auf /llms.txt oder die ausführlichere /llms-full.txt zugreifen – beide gibt es genau dafür. Erzeugt dein Framework Tools aus einer Spezifikation, nimm die OpenAPI-3.1-Spezifikation.
Vier Fehler, die du von Anfang an ausschließen solltest
- Ein Aufruf pro Berechnung. Die meisten Endpoints erwarten ein
keys-Array und berechnen mehrere Dinge in einer Anfrage für einen Credit. Ein Modell ohne Anleitung ruft viermal auf und zahlt viermal. Schreib das in die Tool-Beschreibung. - Einen 402 wiederholen. Das ist ein Guthaben-, kein Netzwerkproblem. Markier ihn im Handler als nicht wiederholbar – am Statuscode allein erkennt das Modell den Unterschied nicht.
- Der Schlüssel landet beim Client. Tools werden auf deinem Server ausgeführt. Das Modell muss den Schlüssel nie sehen, und jedes Design, in dem es ihn sehen könnte, ist nur eine Prompt-Injection von einem Leak entfernt.
- Erfundene Feldnamen. Modelle raten
dateoderlat. Die echten Felder heißendate_time,latitude,longitudeundtimezone_as_float. Schreib sie in die Beschreibung, statt das Modell sie erst über einen 400 herausfinden zu lassen.
So sieht ein echter Aufruf aus
curl -X POST https://api.occultapi.com/api/astro/panchanga/ \
-H 'X-API-Key: yt_live_your_key_here' \
-H 'Content-Type: application/json' \
-d '{
"date_time": "2026-09-17T06:00:00+05:30",
"latitude": 26.9124,
"longitude": 75.7873,
"timezone_as_float": 5.5,
"keys": ["tithi", "nakshatra_segments", "yogam", "karana"]
}'Vier Berechnungen, ein Credit. Die Antwort enthält X-Credits-Charged und X-Credits-Remaining – der einfachste Weg, laufende Kosten in deiner eigenen Oberfläche anzuzeigen.