Вызов функций (также называемый вызовом инструментов или использованием инструментов) позволяет предоставить модели доступ к вашему коду. Вы описываете такие функции, как «найти заказ» или «рассчитать стоимость доставки». Модель решает, какую функцию вызвать и с какими аргументами; ваш код выполняет её и отправляет результат обратно. На этом цикле построен любой агент — от бота поддержки магазина до Claude Code.
В GetVibe API вызов функций работает через стандартную конечную точку /v1/chat/completions в формате OpenAI и через /v1/messages в формате Anthropic. Ниже приведён полный цикл, который мы запускали на трёх моделях от трёх разных разработчиков.
Как работает цикл
- Вы отправляете сообщения и список
tools. Каждый инструмент содержит имя, описание и JSON Schema для своих параметров. - Вместо текста модель возвращает
tool_calls: какую функцию вызвать и с какими аргументами. Значениеfinish_reason—tool_calls. - Ваш код выполняет функции и добавляет по одному сообщению с ролью
toolдля каждого вызова, передавая тот жеtool_call_id. - Вы снова отправляете историю. Модель либо запрашивает дополнительные вызовы, либо отвечает пользователю текстом.
Модель сама ничего не выполняет. Она лишь запрашивает вызов. Что именно будет выполнено и с какими разрешениями, решает ваш код.
Полный пример: ассистент службы поддержки магазина
Две функции: проверка статуса заказа и расчёт стоимости доставки. Пользователь одновременно спрашивает об обоих, и модель вызывает обе функции за один ход.
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.
Циклы агентов повторно отправляют один и тот же длинный префикс в каждом раунде, поэтому кэширование промптов здесь очень важно. Подробнее о полях запроса читайте в документации по вызову инструментов.
