Тема
Язык
·5 мин. чтения

Вызов функций через LLM API: полный рабочий цикл

Как работает вызов функций (использование инструментов) в API, совместимом с OpenAI: полный цикл на Python, который мы запустили на GPT-6 Luna, DeepSeek V4.1 Flash и Claude Haiku 5.5, с принудительным вызовом через tool_choice и форматом Anthropic Messages.

Вызов функций через LLM API: полный рабочий цикл

Вызов функций (также называемый вызовом инструментов или использованием инструментов) позволяет предоставить модели доступ к вашему коду. Вы описываете такие функции, как «найти заказ» или «рассчитать стоимость доставки». Модель решает, какую функцию вызвать и с какими аргументами; ваш код выполняет её и отправляет результат обратно. На этом цикле построен любой агент — от бота поддержки магазина до Claude Code.

В GetVibe API вызов функций работает через стандартную конечную точку /v1/chat/completions в формате OpenAI и через /v1/messages в формате Anthropic. Ниже приведён полный цикл, который мы запускали на трёх моделях от трёх разных разработчиков.

Как работает цикл

  1. Вы отправляете сообщения и список tools. Каждый инструмент содержит имя, описание и JSON Schema для своих параметров.
  2. Вместо текста модель возвращает tool_calls: какую функцию вызвать и с какими аргументами. Значение finish_reason — tool_calls.
  3. Ваш код выполняет функции и добавляет по одному сообщению с ролью tool для каждого вызова, передавая тот же tool_call_id.
  4. Вы снова отправляете историю. Модель либо запрашивает дополнительные вызовы, либо отвечает пользователю текстом.

Модель сама ничего не выполняет. Она лишь запрашивает вызов. Что именно будет выполнено и с какими разрешениями, решает ваш код.

Полный пример: ассистент службы поддержки магазина

Две функции: проверка статуса заказа и расчёт стоимости доставки. Пользователь одновременно спрашивает об обоих, и модель вызывает обе функции за один ход.

import json
import os
from openai import OpenAI

client = OpenAI(base_url="https://getvibeapi.com/v1", api_key=os.environ["GETVIBE_API_KEY"])
MODEL = "gpt-6-luna"

def get_order_status(order_id: str) -> dict:
    # здесь выполняется поиск в вашей базе данных или CRM
    return {"order_id": order_id, "status": "out for delivery", "eta": "2026-10-24"}

def get_shipping_quote(zip_code: str) -> dict:
    return {"zip_code": zip_code, "price_usd": 7.5, "days": 2}

TOOLS = [
    {"type": "function", "function": {
        "name": "get_order_status",
        "description": "Look up an order by its ID",
        "parameters": {"type": "object",
                       "properties": {"order_id": {"type": "string", "description": "Order ID, e.g. A-1042"}},
                       "required": ["order_id"]}}},
    {"type": "function", "function": {
        "name": "get_shipping_quote",
        "description": "Courier shipping price and delivery time to a US ZIP code",
        "parameters": {"type": "object",
                       "properties": {"zip_code": {"type": "string"}},
                       "required": ["zip_code"]}}},
]
FUNCTIONS = {"get_order_status": get_order_status, "get_shipping_quote": get_shipping_quote}

messages = [
    {"role": "system", "content": "Вы — ассистент службы поддержки магазина. Отвечайте кратко."},
    {"role": "user", "content": "Где мой заказ A-1042? И сколько стоит доставка в 94110?"},
]

for _ in range(5):  # ограничиваем количество раундов
    resp = client.chat.completions.create(model=MODEL, messages=messages, tools=TOOLS)
    msg = resp.choices[0].message
    if not msg.tool_calls:
        print(msg.content)
        break
    messages.append(msg.model_dump(exclude_none=True))
    for call in msg.tool_calls:
        args = json.loads(call.function.arguments)
        result = FUNCTIONS[call.function.name](**args)
        messages.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps(result)})

Мы запустили этот код без изменений на gpt-6-luna, deepseek-v4.1-flash и claude-haiku-5.5, изменив только MODEL. В первом раунде все три модели вызвали обе функции: get_order_status с A-1042 и get_shipping_quote с 94110. Во втором раунде все три ответили текстом, указав статус доставки, ETA, цену 7.50 и срок доставки в два дня.

Что важно в этом коде

  • Полностью добавляйте сообщение модели с вызовами инструментов в историю. Без него ваше сообщение tool отвечает на вызов, которого модель не видит, и многие модели просто вызывают ту же функцию снова — цикл зацикливается.
  • Одно сообщение tool на каждый вызов с соответствующим tool_call_id. Модель может одновременно запросить несколько вызовов, как в этом примере.
  • Аргументы приходят в виде строки. arguments — это JSON внутри строки. Разберите и проверьте его, поскольку модель может ошибиться в значении.
  • Ограничивайте количество раундов. Без ограничения ошибка в функции может превратить цикл в бесконечный, а счёт за токены — в бесконечный расход.

tool_choice: когда вызов обязателен

По умолчанию модель сама решает, вызвать инструмент или ответить текстом ("auto"). Параметр tool_choice меняет это поведение:

  • "none" — никогда не вызывать инструменты;
  • "required" — вызвать хотя бы один инструмент;
  • {"type": "function", "function": {"name": "..."}} — вызвать конкретную функцию.

Последняя форма удобна для извлечения данных. Схема параметров функции определяет структуру ответа:

curl https://getvibeapi.com/v1/chat/completions \
  -H "Authorization: Bearer $GETVIBE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek-v4.1-flash",
    "messages": [{"role": "user", "content": "Jane Doe, [email protected], хочет демонстрацию в четверг"}],
    "tools": [{
      "type": "function",
      "function": {
        "name": "save_lead",
        "description": "Save a sales lead to the CRM",
        "parameters": {
          "type": "object",
          "properties": {"name": {"type": "string"}, "email": {"type": "string"}, "request": {"type": "string"}},
          "required": ["name", "email", "request"]
        }
      }
    }],
    "tool_choice": {"type": "function", "function": {"name": "save_lead"}}
  }'

Ответом был вызов save_lead со значениями name «Jane Doe», email «[email protected]» и request «Хочет демонстрацию в четверг».

Есть один нюанс: некоторые модели Claude, включая Claude Sonnet 5.5 и Claude Opus 5.5, не принимают принудительный выбор инструмента. GetVibe преобразует такой запрос в auto с теми же инструментами, поэтому вместо ошибки вы получаете ответ, но затем модель самостоятельно решает, вызывать ли инструмент. Для строгого JSON от этих моделей используйте структурированные выходные данные.

Формат Anthropic: /v1/messages

В Anthropic SDK инструменты выглядят немного иначе: схема параметров передаётся в input_schema, а вызов возвращается как блок содержимого tool_use.

curl https://getvibeapi.com/v1/messages \
  -H "x-api-key: $GETVIBE_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-haiku-5.5",
    "max_tokens": 512,
    "tools": [{
      "name": "get_order_status",
      "description": "Look up an order by its ID",
      "input_schema": {"type": "object", "properties": {"order_id": {"type": "string"}}, "required": ["order_id"]}
    }],
    "messages": [{"role": "user", "content": "Где заказ A-1042?"}]
  }'

В ответе были stop_reason со значением tool_use и блок tool_use, вызывающий get_order_status с order_id A-1042. Результат нужно отправить обратно в следующем сообщении пользователя как блок tool_result с тем же tool_use_id.

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

  • Высоконагруженные боты и простые инструменты — DeepSeek V4.1 Flash ($0.0112 вход · $0.0445 выход за 1 млн токенов) или Claude Haiku 5.5 ($0.0267 вход · $0.1334 выход за 1 млн токенов).
  • Агенты с большим количеством инструментов и длинными планами — GPT-6 Luna ($0.0055 вход · $0.0274 выход за 1 млн токенов) или Claude Sonnet 5.5.

Циклы агентов повторно отправляют один и тот же длинный префикс в каждом раунде, поэтому кэширование промптов здесь очень важно. Подробнее о полях запроса читайте в документации по вызову инструментов.

API для вызова функцийвызов инструментов в LLMпример вызова функций OpenAItool_choiceиспользование инструментов Anthropicинструменты для LLM-агентов

Попробуйте GetVibe API бесплатно

GPT, Claude, Gemini и другие модели через единый API, совместимый с OpenAI. Оплата в USD картой или криптовалютой.

Похожие статьи

Вызов функций через LLM API: полный рабочий цикл | GetVibe API