Tool Calling LLM: полное руководство по Function Calling для AI-агентов | AiManual
AiManual Logo Ai / Manual.
21 Июн 2026 Гайд

Tool Calling (Function Calling) в LLM: как AI-агенты решают, какое действие выполнить — полное руководство

Разбираем механизм tool calling: как LLM выбирает нужное действие, вызывает API и обрабатывает результат. Пошаговый план, примеры кода, частые ошибки.

Реклама
cliv2

Что общего между LLM и телефонным автоответчиком?

Помните старые добрые времена, когда ChatGPT мог только болтать? Вы просите: «Напомни мне встретиться с Петей завтра», а он отвечает: «Конечно, я напомнил!» — и ничего не происходит. Потому что он не умеет нажимать кнопки. Автоответчик тоже болтает, но календарь не откроет.

LLM без tool calling — это тот же автоответчик: умный и красивый, но бесполезный, когда нужно сделать реальное дело. Tool calling (или function calling) — механизм, который превращает болтуна в деятеля. Модель не пишет «Я отправил письмо», а вызывает функцию для отправки письма. И письмо действительно улетает.

Суть: LLM генерирует JSON с именем функции и аргументами, а внешний код выполняет эту функцию. Модель только решает, какую функцию вызвать и с какими параметрами.

Почему JSON круче обычного текста

Можно было бы просить модель писать команды на естественном языке: «отправь письмо Пете с темой „Привет“». Но это путь в никуда. Парсить естественный язык — ад. JSON же — структура, которую железно разберёт любой парсер.

Когда модель выбирает tool, она возвращает объект вроде:

{
  "function": "send_email",
  "arguments": {
    "to": "petr@example.com",
    "subject": "Привет",
    "body": "Созвонимся завтра?"
  }
}

Этот JSON — мост между «думающей» нейросетью и «делающим» кодом. Вызываешь функцию, передаёшь аргументы, получаешь результат, отправляешь его обратно модели — и она продолжает диалог уже с учётом реального результата.

Анатомия tool calling: от промпта до API

Разберём цикл на пальцах. Всё начинается с того, что вы описываете модели список доступных инструментов. Каждый инструмент — это функция с именем, описанием и схемой параметров в JSON Schema. Модель не выполняет код, она только генерирует вызов. Исполнение — ваша зона ответственности.

1 Определите функции

Допустим, мы пишем агента для путешествий. Ему нужны: get_weather(city, date) и book_hotel(hotel_name, checkin, checkout). Описываем их в формате OpenAI:

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Получить прогноз погоды в городе на дату",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "Название города"},
                    "date": {"type": "string", "format": "date"}
                },
                "required": ["city", "date"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "book_hotel",
            "description": "Забронировать отель",
            "parameters": {
                "type": "object",
                "properties": {
                    "hotel_name": {"type": "string"},
                    "checkin": {"type": "string", "format": "date"},
                    "checkout": {"type": "string", "format": "date"}
                },
                "required": ["hotel_name", "checkin", "checkout"]
            }
        }
    }
]

2 Запрос + инструменты = ответ с вызовом

Отправляем пользовательский запрос вместе со списком инструментов. Модель анализирует контекст и решает, нужно ли что-то вызвать. Если нужно — в ответе появляется поле tool_calls (в терминах OpenAI). Если нет — модель просто отвечает текстом.

response = client.chat.completions.create(
    model="gpt-5",  # или gpt-4o, последняя версия на июнь 2026
    messages=[
        {"role": "user", "content": "Какая погода в Лондоне завтра? Если дождливо, забронируй отель с крытым бассейном."}
    ],
    tools=tools
)

3 Вызовите функцию вручную

Вытаскиваем имя и аргументы, вызываем реальный API погоды:

import json

for tool_call in response.choices[0].message.tool_calls:
    func_name = tool_call.function.name
    args = json.loads(tool_call.function.arguments)
    if func_name == "get_weather":
        result = get_weather_api(args["city"], args["date"])

4 Верните результат модели

Добавляем результат в историю как сообщение с ролью tool. Теперь модель может решить, вызывать ли следующий инструмент (например, бронь отеля) или ответить пользователю.

messages.append({
    "role": "tool",
    "tool_call_id": tool_call.id,
    "content": json.dumps({"temperature": 15, "condition": "rain"})
})

# Повторный запрос
response2 = client.chat.completions.create(
    model="gpt-5",
    messages=messages,
    tools=tools
)
💡
Этот цикл — основа любого агента. Подробнее о том, как он ломается на реальных данных, читайте в статье Agent Loop.

Шаг за шагом: пишем агента с инструментами

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

Базовая структура

import openai
import json

client = openai.OpenAI()

def create_event(summary, start_time, end_time):
    # Здесь должен быть вызов Google Calendar API
    return {"status": "created", "event_id": "123"}

def send_email(to, subject, body):
    # Здесь — интеграция с SMTP
    return {"status": "sent"}

tools = [
    {
        "type": "function",
        "function": {
            "name": "create_event",
            "description": "Создать событие в календаре",
            "parameters": {
                "type": "object",
                "properties": {
                    "summary": {"type": "string"},
                    "start_time": {"type": "string"},
                    "end_time": {"type": "string"}
                },
                "required": ["summary", "start_time", "end_time"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "send_email",
            "description": "Отправить email",
            "parameters": {
                "type": "object",
                "properties": {
                    "to": {"type": "string"},
                    "subject": {"type": "string"},
                    "body": {"type": "string"}
                },
                "required": ["to", "subject", "body"]
            }
        }
    }
]

messages = [{"role": "system", "content": "Ты — ассистент, который работает с календарём и почтой. Вызывай функции, когда нужно."}]

while True:
    user_input = input("Вы: ")
    messages.append({"role": "user", "content": user_input})

    response = client.chat.completions.create(
        model="gpt-5",
        messages=messages,
        tools=tools
    )

    msg = response.choices[0].message
    messages.append(msg)

    if msg.tool_calls:
        for tc in msg.tool_calls:
            func_name = tc.function.name
            args = json.loads(tc.function.arguments)
            if func_name == "create_event":
                result = create_event(**args)
            elif func_name == "send_email":
                result = send_email(**args)
            else:
                result = {"error": "unknown function"}
            messages.append({
                "role": "tool",
                "tool_call_id": tc.id,
                "content": json.dumps(result)
            })
        # Повторный запрос для генерации ответа
        response = client.chat.completions.create(
            model="gpt-5",
            messages=messages,
            tools=tools
        )
        msg = response.choices[0].message
        messages.append(msg)
    print(f"Ассистент: {msg.content}")

Важно: если не обработать параллельные tool calls (модель может запросить несколько функций сразу), вы рискуете потерять часть запросов. OpenAI поддерживает до 10 инструментов в одном ответе — обрабатывайте их в цикле.

В реальном проекте не забывайте про лимиты токенов. Контекст быстро растёт: каждое сообщение с результатом функции может быть большим. Техники сжатия — в статье Как не сжечь токены.

Грабли, на которые наступают все (даже я)

Tool calling выглядит магией, пока не упрёшься в реальность. Вот самые частые ошибки.

1. Модель вызывает не ту функцию

Причина — плохое описание. Если две функции похожи, модель путается. Решение — максимально конкретные описания. Например, не «получить информацию», а «получить текущую температуру и влажность для города». Используйте чёткие имена параметров.

2. Галлюцинации в аргументах

Модель может выдумать дату, email или ID. Валидируйте аргументы перед вызовом. Не доверяйте — проверяйте. Если дата невалидна — верните ошибку в результатах tool и дайте модели шанс исправиться.

3. Забыли передать результаты обратно

Без результата модели неоткуда узнать, выполнилась ли функция. Она будет гадать или повторять вызов. Добавляйте role: tool с content — это обязательный шаг.

4. Слишком много инструментов

Когда в списке 50 функций, модель начинает путаться и тратить токены на лишние «думы». Группируйте похожие функции, используйте суб-агентов для разных доменов. О том, как правильно декомпозировать, читайте в этом материале.

Часто задаваемые вопросы

Что такое tool calling простыми словами?

Это когда LLM не отвечает текстом, а возвращает JSON-инструкцию для вызова конкретной функции. Вы эту функцию выполняете и результат отдаёте модели. Так агент получает способность взаимодействовать с внешним миром.

Чем отличается tool calling от простого промпта?

В промпте вы просите модель написать «вызови функцию X» в ответе — но это лишь текст. Tool calling даёт структурированный, гарантированно парсимый вывод, который модель обучена генерировать. Шанс ошибки парсинга — ниже.

Можно ли сделать tool calling для open-source моделей?

Да, многие модели (Llama 3, Mistral, Qwen) поддерживают function calling, но качество ниже, чем у проприетарных. Для критичных сценариев лучше использовать GPT-5 или Claude 4 Sonnet.

Как защититься от инъекций в аргументы?

Не доверяйте аргументам, которые пришли от модели. Валидируйте типы, форматы, проверяйте границы. Ограничьте права функций — пусть модель не может вызвать удаление базы данных.

Взгляд в будущее: агенты, которые не болтают, а делают

К 2026 году tool calling стал стандартом де-факто. Все ведущие провайдеры — OpenAI, Anthropic, Google — встроили его на уровне API. Но эволюция не остановится. Модели учатся планировать последовательность вызовов заранее, а не «на ходу». Техника Dialogue Tree Search уже позволяет модели «проигрывать» ветки решений и выбирать оптимальную.

Следующий шаг — агенты, которые сами создают новые инструменты (функции) на лету. Представьте: вы говорите «Мне нужно отслеживать цену биткоина каждый час», и LLM пишет код для нового API-коллера, регистрирует его в своём инструментарии и начинает использовать. Без участия разработчика.

🔮
Неочевидный совет: не пытайтесь запихнуть все инструменты в один LLM-запрос. Вместо этого используйте субъектный подход — пусть у каждого инструмента будет свой «мини-агент»-обработчик. Так вы решите проблему масштабирования и повысите надёжность.

Tool calling — это не фича, это фундамент. Если ваш AI-агент до сих пор только болтает, вы теряете 90% его потенциала. Идите и дайте ему инструменты. Начните с малого: два-три вызова, простой цикл, и вы увидите, как «разговорчивый болван» превращается в полезного сотрудника.

Подписаться на канал