Ir al contenido

Llamada a funciones

Lo que primero se le ocurre a cualquiera es dar a un LLM 299 endpoints como 299 herramientas, y es un error. Aquí verás el diseño que sí funciona y los cuatro fallos que conviene evitar desde el principio.

No definas 299 herramientas

Con todos los grandes proveedores, cuantas más herramientas, peores resultados. Los esquemas se comen la ventana de contexto antes de que empiece la conversación, y el modelo acierta menos al elegir en cuanto varias descripciones se solapan. Con 299 endpoints, casi todos con los mismos cuatro campos, gastarías miles de tokens en cada turno solo para que el modelo elija peor.

Define una herramienta, o dos. El modelo indica la ruta como argumento, en vez de tener que escoger entre cientos de esquemas.

Diseño con una sola herramienta

definición de la herramienta
{
  "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"]
  }
}

La descripción cumple dos funciones: dice cuándo usar la herramienta y le pide al modelo que no haga los cálculos por su cuenta. Esto último importa más de lo que parece. Si le pides un nakshatra y nada le dice que las posiciones planetarias exigen unas efemérides, el modelo te dará sin dudar uno que suena creíble, sacado de sus datos de entrenamiento.

El manejador

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;
}

Cuando lo adaptes, conserva tres cosas. La clave se lee en el servidor: una clave en el código del navegador acaba gastándola otro. El 402 no se reintenta: significa que no queda saldo, así que un bucle de reintentos solo pierde tiempo y no arregla nada. El mensaje de error se pasa tal cual: la API indica qué campo está mal y, con esa información, el modelo corrige su propia solicitud en el siguiente turno.

Diseño con dos herramientas, para cuando el modelo tiene que explorar

Si tus usuarios hacen preguntas abiertas, el modelo no sabrá qué ruta necesita. Dale también una herramienta de búsqueda. Buscar no cuesta créditos: la exploración sale gratis y solo se cobra la respuesta.

definiciones de las herramientas
[
  {
    "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"]
    }
  }
]

Haz que occult_search consulte /llms.txt o la versión completa, /llms-full.txt; ambos existen justo para esto. Si tu framework genera las herramientas a partir de una especificación, también tienes la especificación OpenAPI 3.1.

Cuatro fallos que conviene evitar desde el diseño

  • Una llamada por cálculo. La mayoría de los endpoints aceptan un array keys y calculan varias cosas en una sola solicitud, por un crédito. Si lo dejas a su aire, el modelo llamará cuatro veces y gastará cuatro créditos. Explícaselo en la descripción de la herramienta.
  • Reintentar un 402. Es un problema de saldo, no de red. Márcalo como no reintentable en el manejador: el modelo no puede distinguirlo solo por el código de estado.
  • Que la clave llegue al cliente. Las herramientas se ejecutan en tu servidor. El modelo nunca necesita ver la clave, y si tu diseño permite que la vea, basta una inyección de prompt para filtrarla.
  • Nombres de campo inventados. Los modelos suelen probar con date o lat, pero los campos reales son date_time, latitude, longitude y timezone_as_float. Ponlos en la descripción para que el modelo no tenga que descubrirlos a base de errores 400.

Así es una llamada real

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"]
  }'

Cuatro cálculos, un crédito. La respuesta trae las cabeceras X-Credits-Charged y X-Credits-Remaining: la forma más sencilla de mostrar el gasto acumulado en tu propia interfaz.

Siguiente