Разработка ИИ-агентов · Модуль 1 · Урок 1.3

Tool calling: схемы инструментов и как модель выбирает инструмент

Что такое tool calling

Сама по себе модель умеет только генерировать текст — она не ходит в сеть и не считает на калькуляторе. Tool calling (вызов инструментов, он же function calling) — это механизм, который даёт модели «руки». Вы заранее описываете доступные инструменты, передаёте эти описания вместе с запросом — и модель, если сочтёт нужным, вместо обычного текста возвращает структурированный запрос на вызов: имя инструмента и аргументы в JSON.

Принципиально важно: модель не выполняет инструмент сама. Она лишь говорит: «вызови get_weather с аргументом city="Москва"». Выполняет — ваш Go-код. Затем вы возвращаете результат обратно модели сообщением с ролью tool. Этот обмен и есть основа агентного цикла.

Схема инструмента

Каждый инструмент описывается схемой: имя, описание (на естественном языке — модель читает его, чтобы понять, когда инструмент уместен) и параметры в формате JSON Schema (типы, обязательные поля, перечисления). Описание — это не комментарий для людей, а часть промпта: по нему модель решает, подходит ли инструмент. Расплывчатое описание → модель вызывает инструмент не вовремя или с мусорными аргументами.

Правила хороших схем: имя — глагол действия (search_orders, а не orders); описание явно говорит, что делает инструмент и когда его применять; параметры минимальны и строго типизированы; обязательные поля помечены в required. Подробнее проектирование инструментов разбираем в Модуле 2.

Как модель выбирает инструмент

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

Можно управлять выбором через параметр tool_choice: auto — модель решает сама (по умолчанию), required/принудительный вызов конкретного инструмента — когда нужно гарантировать действие. Имя параметра и допустимые значения версионно-зависимы — сверяйтесь с доками. Модель может запросить и несколько инструментов за один ход — ваш код должен уметь выполнить их все и вернуть все результаты.

Описание инструмента (схема) в OpenAI-совместимом формате
// Один инструмент: имя, описание (его читает модель) и JSON Schema параметров.
tools := []map[string]any{
    {
        "type": "function",
        "function": map[string]any{
            "name":        "get_weather",
            "description": "Возвращает текущую погоду в городе. Используй, когда спрашивают о погоде или температуре.",
            "parameters": map[string]any{
                "type": "object",
                "properties": map[string]any{
                    "city": map[string]any{
                        "type":        "string",
                        "description": "Название города, например \"Москва\".",
                    },
                },
                "required": []string{"city"},
            },
        },
    },
}

// tools передаётся в теле запроса рядом с messages:
//   body["tools"] = tools
//   body["tool_choice"] = "auto" // модель сама решает, вызывать ли инструмент
Разбор запроса на вызов инструмента из ответа модели
// В ответе модель может вернуть tool_calls вместо обычного content.
type toolCall struct {
    ID       string
    Name     string
    ArgsJSON string // аргументы приходят строкой с JSON
}

// Допустим, мы уже распарсили choice. Проверяем сигнал остановки:
if finishReason == "tool_calls" {
    for _, tc := range toolCalls {
        var args struct{ City string }
        _ = json.Unmarshal([]byte(tc.ArgsJSON), &args)

        result := getWeather(args.City) // выполняем инструмент в нашем коде

        // результат вернём модели сообщением с ролью "tool" (см. урок 1.4)
        _ = result
    }
}

Anti-patterns

Анти-паттернПочему плохоКак правильно
Расплывчатое описание инструментаМодель вызывает его не вовремя или с мусоромЧёткое описание: что делает и когда применять; глагол в имени
Ожидать, что модель сама выполнит инструментМодель только просит вызов; ничего не произойдётВыполняет код; результат возвращается ролью tool
Обрабатывать только один tool_call за ходМодель может запросить несколько — часть потеряетсяПроходить по всем tool_calls и вернуть все результаты
Слепо доверять аргументам от моделиНевалидный JSON/значения роняют выполнениеВалидировать и парсить аргументы, обрабатывать ошибки

Практическое задание

  • Опишите схему одного простого инструмента (например, get_time без параметров или add с двумя числами).
  • Передайте tools в запрос и задайте вопрос, который должен спровоцировать вызов; убедитесь, что finish_reason стал tool_calls.
  • Распарсите имя инструмента и аргументы из ответа; выведите их.
  • Сделайте описание намеренно расплывчатым и посмотрите, как меняется готовность модели вызвать инструмент.
  • Добавьте второй инструмент и проверьте, что модель выбирает подходящий по описанию.

Проверка знаний

Что именно делает модель при tool calling?

  • A Сама выполняет функцию и возвращает её результат
  • B Возвращает структурированный запрос на вызов: имя инструмента и аргументы, а выполняет его ваш код
  • C Игнорирует инструменты и всегда отвечает текстом
  • D Переписывает код инструмента под задачу

Почему описание инструмента так важно?

  • A Это просто комментарий для разработчиков
  • B Модель читает описание как часть промпта и по нему решает, когда и как вызвать инструмент
  • C Описание влияет только на скорость ответа
  • D Оно нужно лишь для автодокументации

На один ход модель вернула сразу два tool_calls: get_weather(city="Москва") и get_weather(city="Казань").

Как должен поступить код агента?

  • A Выполнить только первый вызов, остальное проигнорировать
  • B Выполнить оба вызова и вернуть оба результата отдельными tool-сообщениями
  • C Считать это ошибкой и прервать работу
  • D Объединить оба города в один вызов произвольно