Перейти до вмісту

Виклик функцій

Перетворити кожен із 299 ендпоінтів на окремий інструмент для LLM — очевидний підхід, але хибний. Ось структура, яка працює, і чотири збої, від яких варто захиститися заздалегідь.

Не створюйте 299 інструментів

У всіх великих провайдерів якість падає, щойно список інструментів росте: схеми з’їдають контекстне вікно ще до початку розмови, а точність вибору знижується, коли описи кількох інструментів перетинаються. З 299 ендпоінтами, більшість з яких приймають ті самі чотири поля, ви витрачали б тисячі токенів на кожен хід лише для того, щоб модель гірше обирала.

Створіть один інструмент або два. Модель передає маршрут як аргумент, а не обирає з-поміж сотень схем.

Схема з одним інструментом

визначення інструмента
{
  "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"]
  }
}

Опис виконує дві задачі. Він каже, коли варто звертатися до інструмента, і каже не рахувати самостійно — а це важливіше, ніж здається. Модель, яку попросили назвати накшатру, охоче вигадає правдоподібну з навчальних даних, якщо ніщо не підкаже їй, що для положень планет потрібні ефемериди.

Обробник

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

Три речі в ньому варто зберегти, коли адаптуватимете код під себе. Ключ зчитується на сервері: ключ у коді браузера — це ключ, яким уже витрачає кредити хтось інший. 402 не повторюється: цей код означає порожній баланс, тож цикл повторів лише гає час і нічого не виправляє. Повідомлення про помилку передається моделі: API каже, яке поле неправильне, і модель, отримавши це, виправить свій запит на наступному ході.

Схема з двома інструментами — коли моделі треба досліджувати

Якщо ваші користувачі ставлять відкриті запитання, модель не знатиме, який маршрут їй потрібен. Дайте їй ще й інструмент пошуку: пошук не коштує кредитів, тож дослідження безкоштовне, а платите ви лише за відповідь.

визначення інструментів
[
  {
    "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"]
    }
  }
]

Спрямуйте occult_search на /llms.txt або повнішу версію /llms-full.txt — обидва файли існують саме для цього. Є також специфікація OpenAPI 3.1, якщо ваш фреймворк генерує інструменти з неї.

Чотири збої, від яких варто захиститися

  • Окремий виклик на кожен розрахунок. Більшість ендпоінтів приймають масив keys і рахують кілька речей одним запитом за один кредит. Модель, залишена сама собі, зробить чотири виклики й витратить чотири кредити. Напишіть про це в описі інструмента.
  • Повтор після 402. Це проблема балансу, а не мережі. Позначте цей код як такий, що не повторюється, в обробнику: за одним лише кодом статусу модель різниці не побачить.
  • Ключ потрапляє на клієнт. Інструменти мають виконуватися на вашому сервері. Моделі ключ ніколи не потрібен, а будь-яка архітектура, де модель може його побачити, — це витік ключа за одну промпт-ін’єкцію.
  • Вигадані назви полів. Моделі вгадують date чи lat. Справжні поля — date_time, latitude, longitude і timezone_as_float. Укажіть їх в описі, а не чекайте, доки модель дізнається про них через помилку 400.

Як виглядає справжній виклик

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

Чотири розрахунки — один кредит. Відповідь містить заголовки X-Credits-Charged і X-Credits-Remaining — це найпростіший спосіб показувати поточні витрати у вашому інтерфейсі.

Далі