Function calling — механизм, при котором модель не выполняет действие сама, а возвращает структурированное намерение его выполнить: имя функции и параметры. Решение о запуске принимает ваш код. Это ключевая деталь для понимания рисков: модель не имеет доступа к системам, у неё есть только право попросить, а проверки и полномочия остаются на стороне приложения.
Как это работает по шагам
- Вместе с запросом модели передаётся список доступных инструментов: имя каждого, описание и схема параметров.
- Модель решает, что для ответа нужен инструмент, и возвращает не текст, а структуру вида «вызвать `create_lead` с такими параметрами».
- Ваш код проверяет параметры, права и лимиты, после чего вызывает реальную функцию.
- Результат возвращается модели как новое сообщение.
- Модель либо формулирует ответ, либо запрашивает следующий инструмент.
Шаг 3 — единственное место, где что-то реально происходит. Всё, что модель может сделать неправильно, останавливается здесь.
Отсюда практический вывод: надёжность агента определяется качеством проверок, а не качеством промпта. Инструкция «не создавай сделки на сумму больше миллиона» — пожелание вероятностной системе. Проверка суммы в коде — гарантия.
Проектирование инструментов
Узкие лучше универсальных
Соблазн дать агенту один мощный инструмент — «выполнить запрос к CRM» или «выполнить SQL» — понятен: меньше работы, больше гибкости. Это же и самая опасная конструкция: любая ошибка модели превращается в произвольное действие с данными.
Узкие инструменты ограничивают ущерб конструктивно. `create_lead(name, phone, source)` не может удалить таблицу, что бы модель ни решила.
| Универсальный инструмент | Набор узких | |
|---|---|---|
| Скорость разработки | быстрее | медленнее |
| Гибкость | высокая | ограничена задуманным |
| Ограничение ущерба | почти нет | конструктивное |
| Валидация | трудна | простая, по каждому полю |
| Разбор ошибок | сложный | видно, какой инструмент подвёл |
Разумный компромисс: узкие инструменты на всё, что меняет данные, и более свободные — на чтение.
Описание — это то, что видит модель
Модель выбирает инструмент по названию и описанию, поэтому они пишутся для неё, а не для разработчика. Работают короткие формулировки, явно называющие условия применения: «Создать заявку. Использовать, когда клиент подтвердил интерес и известен телефон». Плохо работают описания вида «работа с заявками» — модель не понимает, когда именно вызывать.
Частая ошибка — два похожих инструмента с невнятными описаниями. Модель начинает путать их, и поведение агента становится непредсказуемым.
Схема параметров как первая линия защиты
Типы, обязательность, допустимые значения, границы чисел — всё это описывается в схеме. Часть неверных вызовов отсекается ещё до вашего кода, потому что модель ориентируется на схему при формировании параметров.
Но полагаться только на неё нельзя: проверять параметры в коде нужно всё равно. Модель способна вернуть значение, формально подходящее по типу и бессмысленное по сути.
Обработка ошибок
Ошибка инструмента — не сбой, а нормальная часть работы агента. Важно, что именно возвращается модели.
Возвращать текст, из которого понятно, что делать дальше. «Клиент не найден по указанному телефону» полезнее, чем «Error 404»: во втором случае модель обычно повторяет тот же вызов.
Различать ошибки, которые можно исправить, и окончательные. Неверный формат телефона — исправимо, модель переспросит. Отсутствие прав — окончательно, повторять бессмысленно, и это надо сказать явно.
Не возвращать модели технические подробности. Стек вызовов, строки подключения, внутренние идентификаторы не нужны для принятия решения и могут попасть в ответ пользователю.
Что идёт не так на практике
- Модель вызывает инструмент не вовремя — обычно из-за размытого описания или пересечения с соседним.
- Выдумывает параметры. Если обязательного поля нет в данных, модель может подставить правдоподобное значение вместо того, чтобы переспросить. Лечится валидацией и явным указанием в описании: «если телефон неизвестен, запросить у пользователя, не выдумывать».
- Зацикливается на неудачном вызове — повторяет один и тот же инструмент после ошибки. См. «Зацикливание ИИ-агента».
- Слишком много инструментов. Когда их десятки, качество выбора падает. Помогает группировка по этапам задачи и передача только релевантного набора.
- Раздутое описание инструментов. Список передаётся с каждым запросом и оплачивается как контекст — избыточные описания напрямую увеличивают счёт.
Function calling и MCP
Function calling — механизм на уровне одной модели и одного приложения: инструменты описываются в коде и передаются вместе с запросом.
MCP решает следующую задачу — как переиспользовать одни и те же инструменты между разными приложениями и моделями, не переписывая интеграцию каждый раз. По сути это стандартизованная обёртка над тем же принципом. Разбор — в статье «MCP: протокол для ИИ-агентов».
Для одного агента с несколькими инструментами MCP избыточен. Он окупается, когда инструментов много и ими пользуется несколько решений.
Разбор: одна задача по шагам
Проследим, что происходит при обработке письма «Здравствуйте, хотим заказать монтаж на объекте в Химках, звоните на +7 900 000-00-00, Пётр».
Шаг 1. Модели передаются: инструкция, описания трёх инструментов (`find_client`, `create_lead`, `assign_manager`) и текст письма.
Модель возвращает не ответ, а намерение:
```
вызвать find_client { phone: "+79000000000" }
```
Шаг 2. Ваш код проверяет: телефон соответствует формату, инструмент разрешён, лимит вызовов не превышен. Только после этого обращается к CRM. Клиент не найден.
Модели возвращается не «404», а осмысленный текст:
```
Клиент с таким телефоном не найден. Можно создать заявку с новым контактом.
```
Разница принципиальна. На «404» модель с высокой вероятностью повторит тот же вызов — начнётся цикл. Формулировка с подсказкой направляет её к следующему шагу.
Шаг 3. Модель возвращает:
```
вызвать create_lead { name: "Пётр", phone: "+79000000000",
service: "монтаж", address: "Химки" }
```
Шаг 4. Проверка обнаруживает проблему: в CRM поле «источник» обязательно, а модель его не передала. Здесь два пути — неправильный и правильный.
*Неправильный:* подставить значение по умолчанию молча. Данные будут заполнены недостоверно, и никто об этом не узнает.
*Правильный:* вернуть модели ошибку с указанием, чего не хватает, и допустимых значений. Модель либо выберет подходящее из письма, либо укажет «не определён» — и это честный результат.
Шаг 5. Заявка создана, возвращается её идентификатор. Модель вызывает `assign_manager`, получает подтверждение и формулирует итоговый ответ.
Что показывает разбор:
- реально происходит всё на шагах проверки, а не в модели;
- текст ошибки определяет поведение агента сильнее, чем инструкция в промпте;
- обязательные поля, которых нет в исходных данных, — главный источник выдуманных значений;
- каждый шаг — отдельное обращение с накопленным контекстом, отсюда стоимость.
Частые вопросы
Модель сама выполняет функции?
Нет. Модель возвращает структуру с именем функции и параметрами — это только намерение. Вызывает функцию ваш код, и он же проверяет параметры, права и лимиты. Модель не имеет прямого доступа к вашим системам, поэтому все ограничения работают надёжно, а не как пожелание.
Чем function calling отличается от обычного API?
Это не альтернатива API, а способ дать модели право его вызывать. Обычный API вызывает программист по заранее написанному коду; при function calling модель выбирает, какой инструмент нужен для текущей задачи, а вызов всё равно выполняет ваш код через тот же API.
Сколько инструментов можно дать агенту?
Технически десятки, практически — чем меньше, тем точнее выбор. При большом числе инструментов модель начинает путать похожие и ошибаться в выборе. Помогает разделение по этапам задачи: на каждом шаге передаётся только релевантный набор. Заодно это снижает расход контекста, который оплачивается с каждым запросом.
Что делать, если модель выдумывает параметры?
Проверять в коде и явно писать в описании инструмента, как поступать при нехватке данных: «если телефон неизвестен, запросить у пользователя, не подставлять произвольный». Схема параметров отсекает часть случаев, но полагаться только на неё нельзя — модель способна вернуть значение, верное по типу и бессмысленное по сути.
Нужен ли MCP, если уже есть function calling?
Для одного агента с несколькими инструментами — нет, это лишний слой. MCP окупается, когда одни и те же инструменты нужны нескольким приложениям или моделям: он позволяет описать интеграцию один раз вместо переписывания под каждое решение.
Что дальше
Как стандартизовать инструменты между решениями — «MCP». Что агенту разрешать и как это проверять — «Ограничение действий». Как это выглядит на практике при работе с CRM — «Подключение ИИ-агента к CRM». Как проверить поведение до запуска — «Тестирование ИИ-агента».
Проектирование инструментов и проверок — часть работ по разработке и внедрению ИИ-агента.