Tool calling - это момент, когда ИИ-агент перестает быть просто чат-ботом и получает возможность действовать: искать в базе знаний, создавать лид в CRM, ставить задачу, проверять статус заказа, отправлять письмо или запускать расчет. Но инструмент - это не “пусть модель сама делает что хочет”. Инструмент должен быть описан схемой, проверен backend-ом, ограничен правами и записан в журнал действий.
Короткая версия: опишите tool как маленькую безопасную функцию с JSON Schema, дайте модели только список доступных tools, проверяйте аргументы на backend, выполняйте действие, возвращайте результат модели и логируйте каждый вызов.
Что мы собираем
Соберем понятную схему tool calling для ИИ-агента. Она подойдет для OpenAI, Claude, LangGraph, Flowise, n8n или собственного backend.
- Агент получает вопрос пользователя.
- Модель решает, нужен ли tool.
- Модель возвращает имя tool и аргументы.
- Backend валидирует аргументы и права.
- Backend выполняет функцию.
- Результат возвращается модели.
- Модель формирует ответ пользователю.
- Все действия попадают в audit log.
Шаг 1. Разделите “ответить” и “сделать”
Не каждый вопрос требует инструмента. Если пользователь спрашивает “что такое RAG?”, агент может ответить текстом. Если пользователь просит “создай лид”, “проверь заказ”, “найди документ”, тогда нужен tool.
- Ответить: объяснение, резюме, сравнение, инструкция.
- Найти данные: поиск по базе знаний, CRM, заказам, документам.
- Изменить данные: создать лид, обновить сделку, поставить задачу.
- Выполнить внешнее действие: отправить письмо, вызвать webhook, создать событие.
Чем сильнее tool меняет внешний мир, тем жестче должны быть правила и подтверждения.
Шаг 2. Начните с одного безопасного tool
Не подключайте сразу CRM, календарь, email, файлы и платежи. Начните с tool, который не ломает данные: например, search_knowledge_base или get_order_status.
Хороший первый tool:
search_knowledge_base(query, product, language)
Плохой первый tool:
delete_customer_data(customer_id)
Когда первый tool стабильно работает, добавляйте следующий. Так проще понять, где агент ошибается: в выборе инструмента, аргументах или backend-логике.
Шаг 3. Опишите tool понятным именем
Имя и описание tool помогают модели выбрать правильное действие. Название должно быть глагольным и конкретным.
- search_knowledge_base - искать в базе знаний.
- create_crm_lead - создать лид в CRM.
- add_ticket_comment - добавить комментарий к тикету.
- get_order_status - получить статус заказа.
- schedule_consultation - создать заявку на консультацию.
Не называйте tool абстрактно: process, handler, action, do_work. Модель хуже поймет, когда его использовать.
Шаг 4. Задайте JSON Schema аргументов
Tool должен принимать строго описанные аргументы. Чем точнее схема, тем меньше хаоса.
{
"type": "function",
"name": "create_crm_lead",
"description": "Создает лид в CRM после явного согласия пользователя оставить заявку.",
"parameters": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Имя клиента"
},
"phone": {
"type": "string",
"description": "Телефон в международном формате"
},
"need": {
"type": "string",
"description": "Краткое описание потребности клиента"
}
},
"required": ["phone", "need"],
"additionalProperties": false
}
}
Даже если модель поддерживает строгие схемы, backend все равно должен валидировать данные: формат телефона, длину текста, допустимые значения, права пользователя.
Шаг 5. Напишите правила вызова tool
Описание tool говорит, что он делает. Системный промпт должен объяснить, когда его можно вызывать.
create_crm_lead вызывай только если:
- пользователь явно хочет оставить заявку;
- есть телефон или email;
- есть краткое описание потребности.
Если контакта нет, сначала задай уточняющий вопрос.
Если пользователь просто спрашивает цену, не создавай лид без согласия.
Это особенно важно для инструментов, которые создают записи, отправляют сообщения или меняют статусы.
Шаг 6. Сделайте backend-обертку
Модель не должна напрямую ходить в CRM, базу данных или файловую систему. Она предлагает вызов tool, а backend решает, можно ли его выполнить.
final class CreateCrmLeadTool
{
public function __invoke(array $args, UserContext $context): array
{
$this->validate($args);
$this->authorize($context, 'create_crm_lead');
$lead = $this->crm->createLead([
'phone' => $args['phone'],
'need' => $args['need'],
'name' => $args['name'] ?? null,
'source' => $context->source,
]);
return [
'ok' => true,
'lead_id' => $lead->id,
];
}
}
Backend-обертка - это место для валидации, прав, лимитов, idempotency, логов и обработки ошибок.
Шаг 7. Верните модели короткий результат
Tool result не должен быть огромной внутренней простыней. Верните модели только то, что нужно для ответа пользователю или следующего шага.
{
"ok": true,
"lead_id": 12345,
"message": "Лид создан и передан менеджеру"
}
Если tool вернул ошибку, не просите модель угадывать. Верните понятный код и безопасное сообщение.
{
"ok": false,
"error_code": "missing_phone",
"message": "Для создания заявки нужен телефон или email"
}
Шаг 8. Добавьте idempotency
Если запрос повторится, агент не должен создать три одинаковых лида или три раза отправить письмо. Для actions с внешним эффектом используйте idempotency key.
idempotency_key = user_id + action_type + normalized_phone + date
Храните ключ вместе с результатом. Если такой action уже был выполнен, возвращайте прежний результат вместо повторного выполнения.
Idempotency особенно важна для CRM, платежей, email, календаря, файлов и webhooks.
Шаг 9. Добавьте human approval
Не все tools можно выполнять автоматически. Создать черновик - безопасно. Отправить клиенту письмо, поменять сумму сделки или удалить данные - рискованно.
Автоматически:
- search_knowledge_base
- get_order_status
- create_ticket_draft
Только после подтверждения:
- send_email
- change_deal_stage
- issue_refund
- delete_customer_data
Human approval лучше делать архитектурно: backend возвращает pending_action, человек подтверждает, затем backend выполняет tool.
Шаг 10. Логируйте каждый вызов
Tool calling без audit log опасен. Если агент сделал что-то не то, нужно понять кто попросил, что модель решила, какие аргументы передала и что вернул внешний сервис.
- run_id;
- user_id или session_id;
- tool name;
- arguments до и после валидации;
- результат tool;
- ошибка, если была;
- время выполнения;
- подтверждение человека, если было;
- версия промпта и модели.
Секреты, токены, пароли и лишние персональные данные в лог писать нельзя.
Шаг 11. Проверьте неправильные вызовы
Тестировать нужно не только успешный сценарий. Самые полезные тесты - те, где агент не должен вызывать tool.
- Пользователь спрашивает цену, но не оставляет заявку: create_crm_lead не вызывается.
- Пользователь просит удалить чужие данные: отказ.
- Нет телефона: агент задает уточняющий вопрос.
- Tool вернул ошибку: агент объясняет следующий шаг.
- Prompt injection просит вызвать скрытый tool: отказ.
- Повторный запрос не создает дубль благодаря idempotency.
Добавьте эти сценарии в eval dataset, чтобы новая версия промпта или модели не сломала поведение.
Шаг 12. Не раскрывайте внутренние tools пользователю
Пользователю не нужно видеть технические названия tool, payload и внутренние ошибки API. Он должен видеть результат человеческим языком.
Плохо:
Tool create_crm_lead returned {"ok":true,"lead_id":123}
Лучше:
Заявку создал. Менеджер свяжется с вами по указанному телефону. Номер заявки: 123.
Для оператора или администратора можно показывать технические детали в отдельной панели или логах.
Мини-чеклист
- У tool конкретное имя и понятное описание.
- Аргументы описаны через JSON Schema.
- Backend валидирует аргументы независимо от модели.
- Права и лимиты проверяются до выполнения.
- Рискованные tools требуют подтверждения.
- Для внешних действий есть idempotency.
- Tool result короткий и безопасный.
- Каждый вызов попадает в audit log.
- Ошибки tool обрабатываются без галлюцинаций.
- Есть evals на неправильные вызовы и prompt injection.
Частые вопросы
Tool calling и function calling - это одно и то же?
В быту часто да. Function calling обычно означает, что модель возвращает имя функции и структурированные аргументы. Tool calling шире: tool может быть функцией, поиском, внешним API, RAG, браузером, кодом или встроенным инструментом платформы.
Можно ли доверять аргументам, которые вернула модель?
Нет. Модель помогает сформировать аргументы, но backend обязан валидировать формат, права, лимиты и бизнес-правила. Особенно если tool меняет данные или отправляет запрос во внешний сервис.
Нужно ли делать tool для каждого действия?
Не обязательно. Делайте tools маленькими, но не слишком дробными. Хороший tool соответствует понятному бизнес-действию: найти документ, создать лид, добавить комментарий, проверить статус.
Что делать, если агент часто выбирает не тот tool?
Уточните названия и описания tools, добавьте правила вызова в системный промпт, уберите похожие инструменты или сделайте router. Затем проверьте поведение на eval dataset.
Где выполнять tool: в модели или на backend?
Внешнее действие должен выполнять backend. Модель выбирает tool и аргументы, а приложение проверяет и выполняет действие. Так проще контролировать безопасность, права, логи и ошибки.