Разработка ИИ-агентов · Модуль 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/принудительный вызов конкретного инструмента — когда нужно гарантировать действие. Имя параметра и допустимые значения версионно-зависимы — сверяйтесь с доками. Модель может запросить и несколько инструментов за один ход — ваш код должен уметь выполнить их все и вернуть все результаты.
// Один инструмент: имя, описание (его читает модель) и 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?
Верный ответ: B
B верно. Модель лишь формирует запрос на вызов (имя + аргументы); выполнение — на стороне вашей программы, а результат возвращается модели сообщением с ролью tool. A — частая иллюзия, но неверно.
Почему описание инструмента так важно?
Верный ответ: B
B верно. Описание — часть контекста, по которой модель принимает решение о вызове. Плохое описание → неуместные или ошибочные вызовы. A и D недооценивают его роль; на скорость (C) оно прямо не влияет.
На один ход модель вернула сразу два tool_calls: get_weather(city="Москва") и get_weather(city="Казань").
Как должен поступить код агента?
Верный ответ: B
B верно. Модель вправе запросить несколько инструментов за ход; нужно выполнить их все и вернуть все результаты, иначе диалог рассинхронизируется. A теряет данные, C и D ломают логику.