Возможности
ВОЗМОЖНОСТИ

Вызов инструментов (tool calling)

Подключение функций к моделям — модель просит вызвать вашу функцию, вы исполняете её локально, отдаёте результат и получаете финальный ответ.

Tool calling позволяет модели запросить у вас выполнение функции (получить погоду, прочитать БД, отправить письмо), получить результат и продолжить диалог с учётом этого результата. Сама модель не исполняет код — она только описывает, что и с какими аргументами надо вызвать. Исполняет — ваш клиент.

Поддерживается большинством современных моделей: Claude (Sonnet, Opus, Haiku), GPT-4o и новее, Gemini Pro/Flash, Llama 3.1+, Mistral Large. Конкретная карточка модели в каталоге показывает поддержку.

Как это работает

Жизненный цикл одного «раунда» вызова инструмента:

  1. Вы шлёте запрос с messages и tools (описанием доступных функций).
  2. Модель решает: ответить текстом или попросить вызвать функцию. В случае второго — возвращает finish_reason: "tool_calls" и массив tool_calls[] в assistant-сообщении.
  3. Вы локально исполняете эти функции, формируете ответы.
  4. Шлёте новый запрос: добавляете assistant-сообщение с tool_calls и одно или несколько role: "tool" сообщений с результатами.
  5. Модель формирует финальный ответ для пользователя.

При параллельных вызовах модель может попросить вызвать несколько функций за один шаг.

Минимальный пример

Шаг 1 — запрос с описанием функции:

curl -s https://api.hubris.pw/v1/chat/completions \
  -H "Authorization: Bearer sk-gw-..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "anthropic/claude-haiku-4.5",
    "messages": [
      {"role": "user", "content": "Какая погода в Москве?"}
    ],
    "tools": [
      {
        "type": "function",
        "function": {
          "name": "get_weather",
          "description": "Возвращает текущую погоду в указанном городе.",
          "parameters": {
            "type": "object",
            "properties": {
              "city": {"type": "string", "description": "Название города"},
              "units": {"type": "string", "enum": ["celsius", "fahrenheit"]}
            },
            "required": ["city"]
          }
        }
      }
    ]
  }'

Ответ модели — она просит вызвать get_weather:

{
  "id": "chatcmpl-...",
  "choices": [{
    "index": 0,
    "message": {
      "role": "assistant",
      "content": null,
      "tool_calls": [
        {
          "id": "call_abc123",
          "type": "function",
          "function": {
            "name": "get_weather",
            "arguments": "{\"city\":\"Москва\",\"units\":\"celsius\"}"
          }
        }
      ]
    },
    "finish_reason": "tool_calls"
  }]
}

Шаг 2 — исполняете функцию у себя и шлёте результат. Важно: сохраните id вызова из tool_calls[].id и проставьте его в tool_call_id.

curl -s https://api.hubris.pw/v1/chat/completions \
  -H "Authorization: Bearer sk-gw-..." \
  -d '{
    "model": "anthropic/claude-haiku-4.5",
    "messages": [
      {"role": "user", "content": "Какая погода в Москве?"},
      {
        "role": "assistant",
        "content": null,
        "tool_calls": [{
          "id": "call_abc123",
          "type": "function",
          "function": {
            "name": "get_weather",
            "arguments": "{\"city\":\"Москва\",\"units\":\"celsius\"}"
          }
        }]
      },
      {
        "role": "tool",
        "tool_call_id": "call_abc123",
        "content": "{\"temperature\": -3, \"conditions\": \"снег\"}"
      }
    ],
    "tools": [ /* те же tools, что и в первом запросе */ ]
  }'

Модель ответит текстом с учётом результата:

{
  "choices": [{
    "message": {
      "role": "assistant",
      "content": "В Москве сейчас −3 °C и идёт снег. Одевайтесь теплее."
    },
    "finish_reason": "stop"
  }]
}

tool_choice — как заставить или запретить вызовы

По умолчанию (auto) модель сама решает, нужен ли инструмент. Можно переопределить:

ЗначениеЭффект
"auto" (по умолчанию)Модель сама решает: текст или вызов
"none"Запретить вызовы, модель ответит только текстом
"required"Заставить вызвать какой-нибудь инструмент
{ "type": "function", "function": { "name": "X" } }Заставить вызвать именно функцию X
"tool_choice": { "type": "function", "function": { "name": "get_weather" } }

Параллельные вызовы

Если в одном шаге модель решит вызвать несколько функций сразу (например, погоду в трёх городах) — в tool_calls[] придёт несколько элементов. Вы исполняете их параллельно, шлёте обратно столько же role: "tool" сообщений с соответствующими tool_call_id.

Отключить параллельные вызовы (модель будет звать функции по одной):

"parallel_tool_calls": false

Стриминг

При stream: true поля tool_calls приходят в delta.tool_calls[] по частям — имя функции и аргументы могут разбиться на несколько чанков. Собирайте по index:

data: {"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"call_abc","type":"function","function":{"name":"get_weather"}}]}}]}
data: {"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\"city\":"}}]}}]}
data: {"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\"Москва\"}"}}]}}]}
data: {"choices":[{"index":0,"finish_reason":"tool_calls"}]}

Финальный чанк с finish_reason: "tool_calls" означает, что модель закончила формировать вызов и ждёт результата.

OpenAI SDK

Официальные SDK OpenAI поддерживают tools «как есть».

Python:

from openai import OpenAI

client = OpenAI(
    base_url="https://api.hubris.pw/v1",
    api_key="sk-gw-...",
)

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Возвращает текущую погоду в указанном городе.",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {"type": "string"},
                "units": {"type": "string", "enum": ["celsius", "fahrenheit"]},
            },
            "required": ["city"],
        },
    },
}]

resp = client.chat.completions.create(
    model="anthropic/claude-haiku-4.5",
    messages=[{"role": "user", "content": "Какая погода в Москве?"}],
    tools=tools,
)

msg = resp.choices[0].message
if msg.tool_calls:
    for call in msg.tool_calls:
        args = json.loads(call.function.arguments)
        result = get_weather(**args)  # ваша локальная функция
        # ... добавьте assistant + tool сообщения и сделайте второй вызов

TypeScript:

import OpenAI from 'openai';

const client = new OpenAI({
  baseURL: 'https://api.hubris.pw/v1',
  apiKey: 'sk-gw-...',
});

const resp = await client.chat.completions.create({
  model: 'anthropic/claude-haiku-4.5',
  messages: [{ role: 'user', content: 'Какая погода в Москве?' }],
  tools: [
    {
      type: 'function',
      function: {
        name: 'get_weather',
        description: 'Возвращает текущую погоду в указанном городе.',
        parameters: {
          type: 'object',
          properties: {
            city: { type: 'string' },
            units: { type: 'string', enum: ['celsius', 'fahrenheit'] },
          },
          required: ['city'],
        },
      },
    },
  ],
});

const msg = resp.choices[0].message;
if (msg.tool_calls?.length) {
  for (const call of msg.tool_calls) {
    const args = JSON.parse(call.function.arguments);
    const result = await getWeather(args);
    // ... добавьте assistant + tool сообщения и сделайте второй вызов
  }
}

Биллинг

Tool-calling не имеет отдельного тарифа. Списываются обычные prompt- и completion-токены за каждый шаг диалога:

  • Шаг 1 (модель просит вызвать функцию) — prompt_tokens за описание инструментов и сообщения, completion_tokens за сгенерированный tool_calls[].
  • Шаг 2 (вы шлёте результат) — prompt_tokens за весь диалог (включая role: "tool" сообщения), completion_tokens за финальный ответ.

Описания инструментов считаются как часть промпта на каждом шаге, где они переданы. Если у вас 10 функций по 200 токенов каждая — это +2000 prompt-токенов за вызов.

Что дальше

Обновлено:

Вызов инструментов (tool calling) · Hubris