Паттерн · Inquir Compute

Бэкенд вызова инструментов (function calling): изолированные HTTP-обработчики для LLM

Модели OpenAI, Anthropic и Google вызывают обычные HTTP-эндпоинты. В Inquir у каждого маршрута инструмента — свой контейнер, API-ключ и секреты вне промпта.

Обновлено: 2026-06-28

Суть ответа

Бэкенд вызова инструментов (function calling): изолированные HTTP-обработчики для LLM. Каждая функция инструмента — отдельный HTTP-обработчик с API-ключом. Оркестратор (OpenAI, Anthropic и др.) вызывает URL со структурированным JSON.

Когда подходит и когда нет

  • Инструмент работает с секретными данными или вызывает платные API
  • Нужна изоляция зависимостей и логи с привязкой к конкретному инструменту

На что обратить внимание

  • Все инструменты в одном процессе — один баг в зависимости ломает всё сразу. Откат затрагивает весь сервис.
  • Без изоляции контейнеров утечка памяти в одном инструменте бьёт по остальным.
  • Secrets in environment variables shared across all tools: rotating one breaks everything.

Почему function calling нужен настоящий бэкенд

Function calling (OpenAI, Anthropic, Gemini) позволяет модели запрашивать вызовы инструментов. В демо они выполняются рядом с циклом модели. В проде нужны аутентификация, секреты, rate limiting, трассировка и async для шагов длиннее одного round-trip.

Без отдельного бэкенда каждый вызов инструмента — открытая функция с теми же привилегиями, что и всё остальное. Скомпрометированный контекст модели может утянуть секреты или вызвать нежелательные побочные эффекты.

Почему монолит под function calling не масштабируется

Все инструменты в одном процессе — один баг в зависимости ломает всё сразу. Откат затрагивает весь сервис.

Без изоляции контейнеров утечка памяти в одном инструменте бьёт по остальным.

Secrets in environment variables shared across all tools: rotating one breaks everything.

Изолированная serverless-модель для вызова функций моделью

Каждая функция инструмента — отдельный HTTP-обработчик с API-ключом. Оркестратор (OpenAI, Anthropic и др.) вызывает URL со структурированным JSON.

Секреты — в переменных окружения. Тёплый пул смягчает холодный старт при частых циклах вызова инструментов. Пайплайн продолжит работу, если один вызов занимает больше секунды.

Что нужно надёжному бэкенду вызова инструментов

Структурированный JSON в ответе

Стабильный контракт ответа — оркестратор не ломается при эволюции схемы.

Проверка доступа до обработчика

API-ключ на маршруте — инструмент не получает неаутентифицированный вызов.

Передача в фон

Долгий инструмент: сразу вернуть { jobId }, оркестратор опрашивает статус — либо включить тёплый контейнер.

Наблюдаемость

Каждый вызов инструмента — запись в истории с телом запроса и ответом; при инциденте проще найти причину.

Как подключить бэкенд инструментов к LLM

1

Описать схему инструмента

JSON Schema в системном промпте; у каждого инструмента — URL шлюза Inquir и маршрут.

2

Написать обработчик

Разобрать структурированный JSON из event.body, вызвать внешний сервис, вернуть JSON.

3

Настроить ключ и задержку

API-ключ на маршруте; при частых вызовах — тёплый пул.

Tool calling flow: schema to handler

The model sees a function definition; your orchestrator maps it to a gateway route; the gateway enforces auth; the handler runs in isolation.

tool-definition.json (passed to LLM)
{
  "type": "function",
  "function": {
    "name": "search_customer",
    "description": "Look up a customer by ID or email",
    "parameters": {
      "type": "object",
      "properties": {
        "query": { "type": "string", "description": "Customer ID or email" }
      },
      "required": ["query"]
    }
  }
}
tools/search-customer.mjs (gateway function)
export async function handler(event) {
  // Auth enforced at gateway — API key checked before this code runs
  const { query } = JSON.parse(event.body || '{}');
  if (!query) return { statusCode: 400, body: JSON.stringify({ error: 'query required' }) };
  const results = await db.customers.search(query); // DB_URL from workspace secrets
  return { statusCode: 200, body: JSON.stringify({ customers: results }) };
}
orchestrator/dispatch.mjs (model → gateway)
// When the model returns a tool_call, dispatch it to the gateway
async function dispatchToolCall(toolCall) {
  const { name, arguments: args } = toolCall.function ?? toolCall;
  // Map tool name to gateway route
  const routeMap = {
    search_customer: process.env.GATEWAY_URL + '/tools/search-customer',
  };
  const url = routeMap[name];
  if (!url) throw new Error(`Unknown tool: ${name}`);
  const res = await fetch(url, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-Api-Key': process.env.TOOLS_API_KEY, // auth enforced at gateway route
    },
    body: JSON.stringify(typeof args === 'string' ? JSON.parse(args) : args),
  });
  if (!res.ok) throw new Error(`Tool ${name} returned ${res.status}`);
  return res.json(); // structured result passed back to the model
}

Когда нужен отдельный бэкенд под вызов инструментов

Когда это уместно

  • Инструмент работает с секретными данными или вызывает платные API
  • Нужна изоляция зависимостей и логи с привязкой к конкретному инструменту

Когда лучше выбрать другое

  • Инструмент только форматирует строку без побочных эффектов

Вопросы и ответы

Как связать определение инструмента с URL Inquir?

OpenAI/Anthropic принимают JSON Schema в tools/functions; URL шлюза Inquir задаёт ваш оркестратор: при tool call POST на маршрут с API-ключом. Модель видит имя и схему, не секреты и не сырой URL в промпте.

Поддерживается параллельный вызов нескольких инструментов?

Да. Каждый параллельный вызов — отдельный HTTP-запрос к своему маршруту; Inquir масштабирует их независимо.