Direkt zum Inhalt

Function Calling

Einem LLM 299 Endpoints als 299 Tools zu geben, liegt nahe – und ist falsch. Hier siehst du den Aufbau, der funktioniert, und vier typische 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. 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 von Schemas wählen zu müssen.

Der Aufbau mit einem Tool

Tool-Definition
{
  "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, dass das Modell nicht selbst rechnen soll. Das ist wichtiger, als es klingt: Fragt man ein Modell nach einem Nakshatra, erfindet es aus seinen Trainingsdaten bereitwillig ein plausibles – wenn ihm niemand sagt, dass Planetenpositionen Ephemeriden brauchen.

Der Handler

node
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 ändert nichts. Die Fehlermeldung wird durchgereicht – die API sagt, welches Feld falsch war, und mit dieser Information korrigiert das Modell seine Anfrage in der nächsten Runde selbst.

Der Aufbau mit zwei Tools – wenn das Modell erst suchen muss

Stellen deine Nutzer offene Fragen, weiß das Modell nicht, welche Route es braucht. Gib ihm dann zusätzlich ein Such-Tool. Suchen kostet keine Credits – die Erkundung ist also kostenlos, und nur die Antwort wird abgerechnet.

Tool-Definitionen
[
  {
    "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 für diesen Zweck. Falls dein Framework Tools aus einer Spezifikation erzeugt, gibt es außerdem eine OpenAPI-3.1-Spezifikation.

Vier Fehler, die du von Anfang an ausschließen solltest

  • Ein Aufruf pro Berechnung. Die meisten Endpoints nehmen ein keys-Array und berechnen mehrere Werte in einer Anfrage für einen Credit. Ein Modell ohne Anleitung ruft viermal auf und zahlt viermal. Schreib es in die Tool-Beschreibung.
  • Einen 402 wiederholen. Das ist ein Guthabenproblem, 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. Bei jedem Aufbau, in dem es ihn sehen könnte, ist er nur eine Prompt-Injection vom Leak entfernt.
  • Erfundene Feldnamen. Modelle raten gern date oder lat. Die echten Felder heißen date_time, latitude, longitude und timezone_as_float. Schreib sie in die Beschreibung, statt das Modell sie über einen 400 herausfinden zu lassen.

So sieht ein echter Aufruf aus

curl
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, die laufenden Kosten in deiner eigenen Oberfläche anzuzeigen.

Weiter