← К блогу

Что такое Function Calling? Как OpenAI, Gemini и Claude вызывают API и внешние инструменты через JSON?

AI-агент · 2026.08.18 · ~12 мин чтения

Что такое Function Calling? Как OpenAI, Gemini и Claude вызывают API и внешние инструменты через JSON?

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

Быстрое решение: считайте Function Calling не исполнением API, а предложением структурированного вызова. Модель формирует JSON по описанию инструмента, ваше приложение проверяет данные, выполняет API-запрос и возвращает результат обратно модели. Для проекта на OpenAI, Google Gemini и Claude API сразу закладывайте адаптационный слой: общий бизнес-контракт — да, единый формат ответа от всех поставщиков — нет.

Эта статья для вас, если вы впервые строите инструментальный AI-сервис, объединяете несколько моделей или отвечаете за безопасность действий агента. Если вам нужен только один простой вызов без общих инструментов и смены поставщика, официального SDK обычно достаточно.

Function Calling, JSON и API: общий контур

Function Calling связывает четыре участника:

  1. Модель получает описание доступных инструментов.
  2. Ваше приложение передаёт модели пользовательский запрос и Schema инструмента.
  3. Модель возвращает структурированный вызов: имя инструмента и аргументы.
  4. Исполнитель проверяет аргументы, вызывает внешний API и формирует результат.
  5. Модель получает результат и создаёт финальный ответ пользователю.

Смысл механизма — разделить намерение и действие. Модель понимает, что нужно получить прогноз погоды, найти заказ или запустить сборку. Но она не должна автоматически получать сетевой доступ, секретный ключ или права на изменение данных.

Google прямо описывает Function Calling как взаимодействие приложения, модели и внешней функции: разработчик объявляет функцию, отправляет запрос с декларацией, извлекает имя и аргументы, выполняет код в своём приложении и передаёт результат обратно модели. (ai.google.dev)

Упрощённый внутренний контракт может выглядеть так:

json
{
  "tool_name": "get_order_status",
  "arguments": {
    "order_id": "A-1042"
  },
  "call_id": "internal-call-7"
}

Это не универсальный запрос OpenAI, Google Gemini или Claude API. Это ваш внутренний объект, который создаётся уже после разбора ответа конкретного поставщика.

JSON Schema нужна для описания допустимых аргументов:

json
{
  "type": "object",
  "properties": {
    "order_id": {
      "type": "string",
      "description": "Идентификатор заказа"
    }
  },
  "required": ["order_id"],
  "additionalProperties": false
}

Схема определяет структуру и ограничения данных. Но она не описывает все бизнес-правила. Например, Schema может потребовать строковое поле order_id, однако не проверит, принадлежит ли заказ текущему пользователю. JSON Schema также не содержит произвольного исполняемого кода, поэтому сложные семантические проверки всё равно выполняются в приложении. (json-schema.org)

Кто отвечает за каждый слой

Главная ошибка начинающих команд — считать инструмент частью промпта. В production-системе это отдельный программный контур с несколькими владельцами.

Слой Ответственный Что он делает Что нельзя перекладывать на модель
Модельный Разработчик AI-интеграции Описывает инструменты, имена, назначение и входную Schema Решение о правах доступа
Адаптационный Платформенная команда Преобразует ответы разных API во внутренние события Скрытие исходного ответа поставщика
Исполнительный Backend-разработчик Вызывает внешний API, управляет сетью, таймаутами и повторами Хранение секретов в промпте
Безопасность Security и бизнес-команда Делит действия на уровни риска, добавляет подтверждения и аудит Проверку владельца ресурса только по Schema
Тестовый QA и команда платформы Проверяет полный цикл вызова и ошибки Предположение, что успешная генерация JSON означает успешную операцию

Модельный слой: декларация инструмента

На этом уровне вы решаете, что именно модель может предложить вызвать. Хорошее описание содержит:

  • стабильное имя;
  • короткое назначение;
  • допустимые поля;
  • типы данных;
  • обязательные параметры;
  • перечисления для ограниченных значений;
  • описание единиц измерения и часового пояса;
  • ограничения на дополнительные поля.

Имя create_invoice сообщает меньше, чем create_invoice_for_verified_customer. Но чрезмерно длинные имена и инструкции увеличивают контекст и затрудняют поддержку. Описание должно объяснять назначение, а не превращаться в бизнес-политику на несколько страниц.

OpenAI поддерживает подключение собственных функций через tools; в официальном описании также указано, что строгий режим Schema может заставлять модель следовать заданной схеме, но поддерживается не весь набор JSON Schema. Поэтому «валидно по стандарту JSON Schema» и «поддерживается конкретным API в строгом режиме» — разные утверждения. (platform.openai.com)

Function Calling действительно напрямую выполняет API?

Нет. Модель возвращает намерение и аргументы. Исполнение происходит в вашем коде или в контролируемом серверном инструменте. Если ваш backend после получения имени функции без проверки вызывает произвольный URL, проблема возникает не из-за Function Calling, а из-за неверной архитектуры исполнителя.

Адаптационный слой: единый контракт без потери данных

У OpenAI, Google Gemini и Claude API похожая идея, но разные формы событий.

Платформа Что объявляет разработчик Как выглядит вызов на концептуальном уровне Что важно сохранить
OpenAI Инструмент типа функции с именем, описанием и параметрами tool_calls или соответствующий элемент ответа API Идентификатор вызова, имя, аргументы и исходный ответ
Google Gemini Function declaration с именем, описанием и параметрами Блок вызова функции с именем и аргументами Имя функции, аргументы, история взаимодействия и части ответа
Claude API tools с name, description и input_schema Блок tool_use с id, name и input tool_use и связанный tool_result

В документации Anthropic клиентский цикл строится вокруг блоков tool_use и tool_result. Ответ модели сообщает о намерении вызвать инструмент, а приложение отправляет результат отдельным блоком, связав его через идентификатор вызова. Anthropic также отмечает, что инструментальные блоки встроены непосредственно в сообщения assistant и user, а не оформляются универсальной ролью tool. (docs.anthropic.com)

Google Gemini использует собственную структуру function declaration и function call. Документация Google отдельно описывает последовательные и параллельные вызовы, поэтому адаптер должен уметь принимать не только один вызов за ход, но и список независимых вызовов. (ai.google.dev)

Для адаптера полезно иметь два уровня данных:

text
raw_response
provider
model
request_id
conversation_state
normalized_events[]

В normalized_events[] можно хранить:

json
{
  "type": "tool_call",
  "provider": "google",
  "call_id": "provider-call-id",
  "name": "get_order_status",
  "arguments": {
    "order_id": "A-1042"
  }
}

Не удаляйте raw_response. Он нужен для:

  • расследования ошибок;
  • повторного воспроизведения;
  • проверки изменения формата;
  • сравнения версий SDK;
  • анализа отказов модели;
  • поддержки специфичных возможностей поставщика.

Если вы сразу преобразуете всё в упрощённый объект вроде function_name + arguments, вы можете потерять идентификатор, причину остановки, текстовые части, параллельные вызовы или служебные поля.

Почему Schema не заменяет проверку и авторизацию

JSON Schema защищает структуру входных данных. Она не подтверждает, что действие разрешено.

Предположим, инструмент принимает такой запрос:

json
{
  "type": "object",
  "properties": {
    "repository": { "type": "string" },
    "branch": { "type": "string" },
    "force": { "type": "boolean" }
  },
  "required": ["repository", "branch"],
  "additionalProperties": false
}

Даже если JSON полностью соответствует схеме, исполнитель должен отдельно проверить:

  • принадлежит ли репозиторий пользователю;
  • разрешена ли операция для его роли;
  • допустима ли ветка;
  • не выполняется ли операция вне рабочего окна;
  • имеет ли запрос уникальный ключ идемпотентности;
  • требуется ли ручное подтверждение;
  • не превышен ли лимит операций.

Разделяйте инструменты по риску:

  1. Только чтение — поиск заказа, получение статуса, чтение метрик.
  2. Изменение данных — обновление записи, отправка уведомления, создание задачи.
  3. Потенциально разрушительные — удаление, принудительная публикация, сброс окружения.
  4. Открытая сеть — произвольный HTTP-запрос, загрузка файла, обращение к непроверенному адресу.

Для первого типа обычно достаточно серверной авторизации и журналирования. Для третьего и четвёртого нужны явные ограничения, подтверждение пользователя, allowlist адресов и отдельные политики исполнения.

Важное ограничение: никогда не помещайте долгоживущие ключи, токены и пароли в системный промпт, историю сообщений или файлы, доступные модели. Модель должна видеть описание действия, а не секрет, с помощью которого оно выполняется.

Исполнительный слой: где происходит настоящий API-вызов

Исполнитель получает нормализованное событие и запускает заранее зарегистрированный обработчик. Не передавайте модели возможность выбрать любой Python-модуль, shell-команду или URL.

Надёжная регистрация выглядит концептуально так:

python
TOOLS = {
    "get_order_status": get_order_status,
    "create_ticket": create_ticket,
}

После этого исполнитель:

  1. проверяет, что имя есть в allowlist;
  2. парсит аргументы как JSON;
  3. валидирует их по Schema;
  4. проверяет пользователя и ресурс;
  5. подставляет секреты из менеджера конфигурации;
  6. выполняет запрос с таймаутом;
  7. нормализует результат;
  8. записывает аудит;
  9. возвращает модели только необходимые данные.

Обработчик должен различать техническую и бизнес-ошибку. Например:

json
{
  "ok": false,
  "error": {
    "kind": "authorization_denied",
    "retryable": false,
    "message": "Операция запрещена для текущей роли"
  }
}

Не возвращайте модели полный stack trace, заголовки авторизации или внутренние адреса сервисов. Для пользователя достаточно понятного сообщения, а подробности остаются в защищённом журнале.

Что делать при ошибочном JSON и неполном цикле

Как обработать ошибочные параметры от модели?

Не пытайтесь молча исправлять критичные значения. Сначала сохраните исходный вызов, затем проверьте синтаксис, Schema и бизнес-правила.

Разделите ошибки на четыре группы:

  • JSON не разбирается;
  • поле отсутствует;
  • тип или значение не соответствует Schema;
  • значение формально допустимо, но запрещено бизнес-правилами.

Для первой и второй группы можно отправить модели короткую ошибку с просьбой сформировать новый вызов. Для опасной операции лучше остановить цикл и запросить подтверждение пользователя. Для нарушения прав доступа повторная генерация не поможет — это отказ исполнителя.

Одинаковы ли JSON-форматы вызова у трёх платформ?

Нет. Одинаковым может быть только ваш внутренний контракт. У поставщиков отличаются:

  • имя поля с аргументами;
  • расположение вызова в ответе;
  • идентификатор;
  • формат возврата результата;
  • управление параллельными вызовами;
  • способ выбора инструмента;
  • представление остановки генерации;
  • требования к истории сообщений.

Поэтому не стоит создавать «единый запрос» и отправлять его напрямую во все API. Создайте общий объект намерения, а затем отдельные сериализаторы:

text
InternalToolCall
  ├── OpenAIRequest
  ├── GeminiRequest
  └── ClaudeRequest

Такая схема немного увеличивает код, но уменьшает риск скрытых несовместимостей.

Пять шагов для первой реализации

1. Выберите одну операцию только для чтения

Начните с get_order_status, search_customer или read_build_status. Не начинайте с удаления, оплаты или публикации.

2. Зафиксируйте Schema до подключения модели

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

3. Напишите исполнитель без AI

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

4. Подключите один официальный SDK

На первом этапе не смешивайте адаптацию и бизнес-логику. Убедитесь, что вы понимаете исходный ответ выбранного поставщика.

5. Добавьте нормализованный внутренний event

Только после рабочего одиночного сценария переводите событие в общий формат. Исходный ответ сохраняйте рядом.

6. Повторите тот же сценарий на второй и третьей платформе

Используйте одну бизнес-задачу, одинаковую Schema и одинаковые тестовые данные. При этом отдельно фиксируйте модель, SDK, API-вход и дату проверки.

7. Проверьте ошибки полного цикла

Проверьте отсутствие параметра, неверный тип, параллельные вызовы, недоступность API, пустой результат, потерю истории и ошибочный финальный ответ.

Для систем, где AI пишет код, запускает сборки или работает с Apple-автоматизацией, полезно отдельно описать границу между моделью и средой исполнения. Материал о правилах AI coding workflow и Skills поможет разделить инструкции, инструменты и проверяемые действия.

Условия выбора: прямой SDK или адаптационный слой

Используйте следующий развилочный список:

  • Если у вас одна модель, один продукт и до нескольких стабильных инструментов, то начинайте с официального SDK.
  • Если вы планируете менять поставщика, то создайте внутренний контракт до появления второго провайдера.
  • Если несколько команд используют одни и те же инструменты, то вынесите исполнители в отдельный сервис с авторизацией и аудитом.
  • Если важны параллельные вызовы, то заранее определите правила дедупликации, лимиты и порядок возврата результатов.
  • Если действие меняет данные или расходует ресурсы, то добавьте проверку владельца, подтверждение и идемпотентность.
  • Если инструмент должен запускать macOS-команды, Xcode-сборки или Apple-автоматизацию, то отделите модельный API от удалённого Mac-узла.
  • Если нужен только временный тестовый исполнитель, то не покупайте постоянную рабочую станцию до проверки нагрузки и требований к доступу.

В многоагентных системах общий контракт также упрощает переход к протоколам инструментов. Сначала определите, какие данные и действия нужны вашему приложению, а затем решайте, нужен ли MCP или достаточно обычного Function Calling. Сравнение современного AI-стека и роли агентов можно дополнительно посмотреть в обзоре AI Agent-технологий.

Чек-лист перед запуском в production

Отметьте каждый пункт:

  • [ ] Каждая функция имеет владельца и назначение.
  • [ ] Инструменты разделены на чтение, изменение, разрушительные и сетевые.
  • [ ] В Schema перечислены обязательные поля.
  • [ ] Лишние поля отклоняются или явно обрабатываются.
  • [ ] Исполнитель использует allowlist имён.
  • [ ] Секреты хранятся вне промптов и истории.
  • [ ] Есть отдельная авторизация на каждый ресурс.
  • [ ] Настроены таймауты и ограниченные повторы.
  • [ ] Для повторяемых операций используется идемпотентность.
  • [ ] Сохраняются исходные ответы поставщика.
  • [ ] В журнале есть идентификатор вызова.
  • [ ] Ошибки модели и ошибки инструмента различаются.
  • [ ] Проверены параллельные вызовы.
  • [ ] Проверена потеря или неполнота истории.
  • [ ] Финальный текст модели не считается доказательством успешного действия.
  • [ ] Для OpenAI, Google Gemini и Claude API записаны версии моделей и SDK.

Тестировать лучше не только happy path. Например, модель может вернуть корректный JSON с несуществующим идентификатором заказа. Schema пропустит его, но backend обязан вернуть контролируемую ошибку. Другой случай — два одинаковых вызова из-за повтора ответа. Без идемпотентности вы можете дважды создать тикет или отправить два уведомления.

Для проектов с Claude API отдельно проверяйте правильное связывание tool_use_id и tool_result. Документация Anthropic указывает, что результат должен быть возвращён в ожидаемой структуре и в правильной последовательности сообщений. (docs.anthropic.com)

JSON Schema полезна и как общий язык между командами. Она документирует поля, помогает валидировать данные и улучшает совместимость между системами, но не заменяет семантическую проверку. Официальные материалы JSON Schema отдельно подчёркивают разницу между структурными ограничениями и правилами, которые требуют логики приложения. (json-schema.org)

Когда для инструментов нужен удалённый Mac-узел

Если агент работает только с HTTP-сервисами, исполнителю достаточно серверного окружения. Но требования меняются, когда инструмент должен:

  • запускать Xcode;
  • собирать iOS-приложение;
  • выполнять macOS-команды;
  • управлять симулятором;
  • использовать AppleScript или системную автоматизацию;
  • работать с локальным Keychain и сертификатами;
  • поддерживать длительный CI/CD-сценарий.

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

Для быстрой проверки такого сценария можно рассмотреть удалённый Mac для Xcode и CI/CD. Но аренда не всегда оптимальна: при постоянной высокой нагрузке, строгой необходимости в физических интерфейсах или длительном жизненном цикле проекта собственное оборудование может быть предсказуемее.

Если сейчас вы запускаете такие инструменты на Windows или Linux через нестабильные обходные схемы, возникают реальные ограничения: несовместимость macOS-зависимостей, ручная настройка окружения и сложнее воспроизводимые сборки. Hashvps имеет смысл рассматривать как временный или тестовый исполнительный слой, когда вам нужно проверить агентный pipeline, а не немедленно строить постоянный парк машин. При этом модель всё равно не получает прямую власть над узлом: команда проходит через ваш executor, политику и журнал аудита.

Function Calling отвечает только на вопрос «какое действие предложила модель». Вопросы «можно ли его выполнить», «в каком окружении», «с какими полномочиями» и «как доказать результат» решаются вашим backend, службой безопасности и владельцем инфраструктуры. Именно поэтому для одного простого приложения достаточно прямого SDK, а для много-модельной платформы разумнее заранее внедрить адаптационный слой и отдельные execution nodes — включая удалённый Mac, если в цепочке есть macOS, Xcode или Apple-автоматизация.

Подготовьте надёжную среду для Function Calling с Hashvps

Арендуйте удалённый Mac в Hashvps для разработки и тестирования интеграций с API и внешними инструментами.
Разворачивайте изолированные рабочие окружения для приложений, которые формируют и проверяют JSON-запросы.

На главную

Hashvps · Mac Cloud

Выделенный Mac Cloud

Выделенные вычисления + эксклюзивный IP.

На главную
Акция