Function Calling: полное руководство по GPT и Claude API для вызова инструментов (2026)
Кратко
- Function Calling (вызов инструментов, Tool Use) позволяет LLM в процессе ответа вызывать заданные вами функции — получать данные в реальном времени, работать с внешними системами, выполнять действия
- OpenAI и Claude поддерживают вызов инструментов — форматы API немного различаются, но логика одинаковая
- Через OpenAI-совместимый шлюз (например, Ofox.ai) один и тот же код работает с GPT, Claude, DeepSeek и 50+ другими моделями
- В продакшене ключевые вещи: качество описания инструментов, обработка ошибок, параллельный вызов, управление context window
Содержание
- Что такое Function Calling?
- Формат OpenAI Function Calling API
- Формат Claude Tool Use API
- Полная реализация: агент запроса погоды
- Параллельный вызов нескольких инструментов
- Лучшие практики для продакшена
- Бенчмарки и реальные замеры
- FAQ
- Итоги и план действий
Что такое Function Calling?
Function Calling (также Tool Use, вызов инструментов) — механизм взаимодействия LLM с внешними системами. Суть проста:
Вы описываете набор функций (инструментов) и говорите модели: «у тебя есть эти возможности». Когда модель решает, что нужен инструмент, она не отвечает напрямую, а возвращает структурированный запрос на вызов. Ваш код выполняет этот вызов, получает результат и передаёт его обратно модели — она формирует финальный ответ.
Ограничения обычной LLM: модель работает только со знаниями из обучающей выборки. Актуальные данные — погода, курсы, записи в базе — ей недоступны.
Что решает Function Calling:
- Получение данных в реальном времени (погода, курсы валют, котировки)
- Операции с внешними системами (SQL-запросы, вызовы API, отправка email)
- Извлечение структурированных данных из текста
- Многоэтапные рабочие процессы AI-агентов (модель сама планирует и выполняет цепочку действий)
Function Calling vs RAG: RAG подходит для поиска по статическим базам знаний (PDF, документация), Function Calling — для динамических данных и выполнения действий. В продакшене их часто комбинируют.
Формат OpenAI Function Calling API
В OpenAI инструменты передаются через параметр tools — каждый описывается JSON Schema:
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Получает текущую погоду в указанном городе. Вызывать при вопросах о погоде, температуре, осадках.",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "Название города, например: Москва, Санкт-Петербург, London"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "Единица температуры, по умолчанию celsius"
}
},
"required": ["city"]
},
"strict": True # Structured Outputs — модель обязана вернуть валидный JSON
}
}
]
Описание ключевых полей:
| Поле | Описание |
|---|---|
type: "function" | Пока поддерживается только тип function |
name | Имя функции, допустимы [a-zA-Z0-9_-], до 64 символов |
description | Самое важное поле — модель решает, вызывать ли инструмент, именно по описанию |
parameters | Стандартная JSON Schema, описывает структуру параметров |
strict: true | Включает Structured Outputs — устраняет ошибки формата параметров |
Формат ответа модели при вызове инструмента:
# Когда finish_reason == "tool_calls" — модель хочет вызвать инструмент
response = {
"choices": [{
"finish_reason": "tool_calls",
"message": {
"role": "assistant",
"content": None,
"tool_calls": [{
"id": "call_abc123",
"type": "function",
"function": {
"name": "get_weather",
"arguments": '{"city": "Москва", "unit": "celsius"}'
# Внимание: arguments — это JSON-строка, нужен json.loads()
}
}]
}
}]
}
Формат Claude Tool Use API
Формат инструментов в Claude похож на OpenAI, но с отличиями в именах полей:
tools = [
{
"name": "get_weather", # Без обёртки type
"description": "Получает текущую погоду в указанном городе",
"input_schema": { # Внимание: input_schema, а не parameters
"type": "object",
"properties": {
"city": {"type": "string", "description": "Название города"},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
},
"required": ["city"]
}
}
]
Сравнение ключевых отличий OpenAI и Claude:
| Аспект | OpenAI | Claude |
|---|---|---|
| Структура инструмента | {"type":"function","function":{...}} | Напрямую {"name":..., "input_schema":...} |
| Поле схемы | parameters | input_schema |
| Причина остановки | finish_reason: "tool_calls" | stop_reason: "tool_use" |
| ID результата | tool_call_id | tool_use_id |
| Серверные инструменты | Нет | Есть (например, web_search_20250305) |
Если вы используете OpenAI-совместимый шлюз (например, Ofox.ai), то даже при работе с Claude можно использовать формат tools от OpenAI — шлюз автоматически конвертирует запрос. Один код на все модели.
Полная реализация: агент запроса погоды
Ниже — полный, готовый к продакшену пример на Python. Используем API-шлюз Ofox.ai для вызова любой модели:
import json
import os
from openai import OpenAI
# Единый шлюз Ofox.ai — один ключ для GPT/Claude/DeepSeek и 50+ моделей
client = OpenAI(
api_key=os.environ.get("OFOX_API_KEY"),
base_url="https://api.ofox.ai/v1"
)
# Определение инструментов
TOOLS = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Получает текущую погоду в городе. Используется при вопросах о погоде, температуре, вероятности осадков. Не подходит для исторических данных или прогноза на неделю.",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "Название города на русском или английском: Москва, Saint Petersburg"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "Единица температуры, по умолчанию celsius"
}
},
"required": ["city"]
},
"strict": True
}
}
]
# Имитация инструмента (в реальном проекте — вызов настоящего API)
def get_weather(city: str, unit: str = "celsius") -> dict:
"""Вызов API погоды для получения актуальных данных"""
# В продакшене: requests.get(f"https://api.weather.com/v1/current?city={city}")
return {
"city": city,
"temperature": 22 if unit == "celsius" else 72,
"unit": unit,
"condition": "Ясно",
"humidity": "45%",
"wind": "Юго-восточный, 3 м/с"
}
def run_weather_agent(user_query: str, model: str = "gpt-4o-mini") -> str:
"""
Запуск агента погоды
Args:
user_query: вопрос пользователя на естественном языке
model: модель — подойдёт любая из каталога Ofox
Returns:
Финальный ответ модели
"""
messages = [
{"role": "system", "content": "Ты — помощник по погоде. Получай данные через инструменты, потом отвечай пользователю."},
{"role": "user", "content": user_query}
]
# Раунд 1: модель решает, нужен ли инструмент
response = client.chat.completions.create(
model=model,
messages=messages,
tools=TOOLS,
tool_choice="auto" # Модель решает сама
)
message = response.choices[0].message
# Если инструмент не нужен — возвращаем ответ сразу
if response.choices[0].finish_reason != "tool_calls":
return message.content
# Обработка вызова инструментов
messages.append(message) # Добавляем намерение модели в историю
for tool_call in message.tool_calls:
# Парсим параметры (arguments — JSON-строка)
args = json.loads(tool_call.function.arguments)
# Выполняем соответствующий инструмент
if tool_call.function.name == "get_weather":
result = get_weather(**args)
else:
result = {"error": f"Неизвестный инструмент: {tool_call.function.name}"}
# Результат — обратно в историю диалога
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(result, ensure_ascii=False)
})
# Раунд 2: модель генерирует финальный ответ на основе данных
final_response = client.chat.completions.create(
model=model,
messages=messages,
tools=TOOLS
)
return final_response.choices[0].message.content
# Тест
if __name__ == "__main__":
answer = run_weather_agent("Какая погода в Москве? Нужно ли брать зонт?")
print(answer)
# Пример вывода: В Москве сейчас ясно, +22°C, влажность 45%, юго-восточный ветер 3 м/с. Зонт не нужен — отличная погода для прогулки!
Ключевые моменты:
- Два вызова API: первый — модель «думает», какой инструмент вызвать; второй — получает результат и формирует ответ
tool_call_idдолжен совпадать, иначе модель запутаетсяarguments— это JSON-строка, не объект; нуженjson.loads()
Параллельный вызов нескольких инструментов
Современные LLM (GPT-4o, Claude Sonnet) умеют возвращать несколько вызовов инструментов за один ответ — это существенно снижает задержку:
# Регистрируем несколько инструментов
MULTI_TOOLS = [
{"type": "function", "function": {"name": "get_weather", ...}},
{"type": "function", "function": {"name": "search_news", ...}},
{"type": "function", "function": {"name": "get_stock_price", ...}}
]
# Обработка параллельных вызовов (модель может вернуть несколько tool_calls)
if message.tool_calls:
import concurrent.futures
def execute_tool(tool_call):
args = json.loads(tool_call.function.arguments)
if tool_call.function.name == "get_weather":
return tool_call.id, get_weather(**args)
elif tool_call.function.name == "search_news":
return tool_call.id, search_news(**args)
# ...
# Параллельное выполнение всех инструментов — минимальная задержка
with concurrent.futures.ThreadPoolExecutor() as executor:
results = list(executor.map(execute_tool, message.tool_calls))
for tool_call_id, result in results:
messages.append({
"role": "tool",
"tool_call_id": tool_call_id,
"content": json.dumps(result, ensure_ascii=False)
})
Выигрыш по времени: если три инструмента работают по 500 мс каждый, последовательный вызов — 1500 мс, параллельный — ~500 мс.
Лучшие практики для продакшена
1. Описание инструмента — самая важная инженерная задача
Точность вызова инструментов зависит не от модели, а от качества описания:
# ❌ Плохое описание
"description": "Погода"
# ✅ Хорошее описание: когда вызывать, когда НЕ вызывать, что возвращает
"description": """Получает актуальную погоду в городе (температура, влажность, ветер, состояние).
Когда использовать: текущая погода, нужен ли зонт, одеваться ли тепло.
Когда НЕ использовать: историческая погода, прогноз на 7 дней (для этого — get_weather_forecast).
Возвращает: температуру (celsius), влажность (%), ветер (направление и скорость), описание."""
2. Ограничение глубины рекурсии
Защита от бесконечных циклов вызова инструментов:
MAX_TOOL_ROUNDS = 3 # Максимум 3 раунда
for round_num in range(MAX_TOOL_ROUNDS):
response = client.chat.completions.create(...)
if response.choices[0].finish_reason != "tool_calls":
break # Модель завершила работу
# Обработка вызовов...
else:
# Достигнут лимит — просим модель подвести итог
messages.append({"role": "user", "content": "Дай финальный ответ на основе имеющихся данных."})
3. Обработка ошибок: даём модели шанс восстановиться
try:
result = execute_tool(tool_call)
except Exception as e:
# Ошибку передаём модели — она решит, что делать
result = {
"error": str(e),
"suggestion": "Попробуйте вызвать с другими параметрами"
}
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(result, ensure_ascii=False)
})
4. Управление Context Window
Инструменты потребляют много токенов. 58 инструментов — это ~55K токенов, что почти полностью забивает контекст маленьких моделей.
Решения:
- Динамическая загрузка: передавайте только релевантные инструменты (3-5 штук) исходя из намерения пользователя
- Обрезка результатов: лимитируйте размер ответа инструмента (например, 2000 символов)
- Сжатие истории: после N раундов — компрессия ранних сообщений
Больше приёмов работы с API — в документации Ofox.ai для разработчиков.
Бенчмарки и реальные замеры
Точность вызова инструментов (Berkeley BFCL V4)
| Модель | Один инструмент | Несколько инструментов | Параллельный вызов |
|---|---|---|---|
| GPT-4o | 92% | 87% | Да |
| Claude Sonnet 4.5 | 94% | 89% | Да |
| GPT-4o-mini | 85% | 79% | Да |
| DeepSeek-V3 | 83% | 76% | Да |
Источник: Berkeley Function Calling Leaderboard V4, результаты 2025-2026
Замеры задержки (через Ofox.ai)
| Сценарий | Последовательно | Параллельно | Ускорение |
|---|---|---|---|
| 3 инструмента по 300 мс | ~1100 мс | ~450 мс | 59% |
| 5 инструментов по 200 мс | ~1300 мс | ~380 мс | 71% |
Параллельный вызов даёт критическое преимущество при работе с несколькими инструментами.
FAQ
В: Function Calling или RAG — что выбрать?
Задачи разные. RAG (Retrieval-Augmented Generation) — для поиска по статическим базам знаний (документация, FAQ, регламенты). Function Calling — для динамических данных (актуальный курс, свежие записи в БД) и операций (отправка писем, запись в БД). Типичная production-система использует оба подхода: RAG для базы знаний, Function Calling для real-time данных и действий.
В: Инструмент вернул пустой результат или ошибку — что делать?
Передайте ошибку модели в виде структурированного JSON (см. пример выше). Модель решит: повторить вызов с другими параметрами, переключиться на другой инструмент или сообщить пользователю. Нельзя просто проглатывать ошибку — модель начнёт галлюцинировать.
В: Обязательно ли strict: true?
В продакшене — да. strict: true включает Structured Outputs от OpenAI: модель обязана вернуть параметры, соответствующие JSON Schema. Это убирает ~95% ошибок формата. Цена — дополнительные ~100 мс на компиляцию схемы при первом запросе, дальше работает из кеша.
В: Формат инструментов у Claude и OpenAI разный — как писать один код?
Через OpenAI-совместимый шлюз, например Ofox.ai. Пишете в формате OpenAI tools — шлюз конвертирует в input_schema для Claude автоматически. Переключение модели — одна строка model, остальной код без изменений.
В: Сколько инструментов можно передавать без деградации?
Выше 10 — точность падает, расход context window растёт нелинейно. Рекомендации для продакшена:
- Активных инструментов — не больше 10
- Динамически выбирайте релевантное подмножество (3-5) на основе запроса пользователя
- В сложных сценариях используйте технику Tool Search от Anthropic — снижает потребление токенов инструментами на 85%
В: Function Calling тарифицируется отдельно?
Нет. Описания инструментов, запросы на вызов и результаты — всё считается как обычные токены, без дополнительной платы. Но учитывайте: каждый инструмент занимает 100-500 токенов, при большом количестве это заметная статья расходов.
В: Как использовать Function Calling из России?
Напрямую API OpenAI и Anthropic из России недоступны из-за региональных ограничений. Решение — API-агрегатор: например, Ofox.ai поддерживает оплату криптовалютой и в рублях, доступ из России работает без VPN. Регистрация и получение ключа — 5 минут.
Итоги и план действий
Function Calling — ключевая технология для создания полезных AI-приложений. С ним LLM перестаёт быть просто «чат-ботом» и становится агентом, который работает с реальными системами и актуальными данными.
Что можно сделать прямо сейчас:
- Начните с простого: выберите один из ваших API (погода, CRM, БД), опишите его как инструмент и протестируйте по шаблону из этой статьи
- Отшлифуйте описания: итеративно улучшайте description — описывайте, когда вызывать и когда НЕ вызывать. Это даёт максимальный прирост точности при минимальных затратах
- Используйте единый шлюз: через Ofox.ai один код работает с GPT, Claude, DeepSeek — удобно для A/B-тестов и автоматического fallback
- Включите
strict: true: убирает ошибки формата параметров — must have для продакшена - Задайте лимит рекурсии: защита от бесконечных циклов вызовов
Больше примеров интеграции и документация SDK — на странице для разработчиков Ofox.ai.