COMRAD404 / HOWTO

Как использовать Function Calling в OpenAI API

Пошаговая инструкция по Function Calling в OpenAI API: как описать tool со strict JSON Schema, запустить цикл Responses API, вернуть function_call_output и проверить итоговый response.output_text.

Понадобится

25–40 минут
  • Доступ к OpenAI API и к модели с поддержкой Functions в Responses API
  • Приложение, которое уже умеет отправлять запросы в OpenAI API
  • Одна пользовательская функция, исполняемая на стороне вашего приложения
  • Понимание базового цикла request/response в API
  • Готовность перепроверять Models и Changelog перед продакшеном

После выполнения этой инструкции вы настроите базовый цикл Function Calling в OpenAI API по текущему официальному пути: через Responses API, выполнение функции на стороне вашего приложения и возврат результата через function_call_output с тем же call_id. В конце вы получите финальный ответ модели в response.output_text и сможете проверить, что инструмент действительно был вызван.

  • Время: 25–40 минут
  • Сложность: средний
  • Стоимость: зависит от модели и числа токенов. На странице Models по состоянию на 2026-08-17 были указаны цены за 1 MTok input/output: gpt-5.6-luna — $0.20/$1.20, gpt-5.6-terra — $2/$12, gpt-5.6-sol — $5/$30. Перед продакшеном перепроверьте живую страницу Models.
  • Что потребуется: доступ к OpenAI API, приложение, которое умеет вызывать Responses API, и одна функция, которую вы исполняете на своей стороне.
  • Актуальная версия: документация OpenAI API по состоянию на 2026-08-17. Для новых реализаций текущий путь Function Calling — Responses API; Chat Completions остаётся документированным как legacy-путь для существующих интеграций.

Если базового вызова API у вас ещё нет, сначала соберите минимальную интеграцию по инструкции Как интегрировать OpenAI API в приложение (Python/JS). Если нужен быстрый контекст по термину, посмотрите объяснение API.

Практический вердикт. Если вы строите новый tool-use сценарий, ориентируйтесь на Responses API и на цикл «модель запросила функцию → приложение выполнило → приложение вернуло function_call_output → модель завершила ответ». Редакционное ограничение: ниже показан базовый сценарий с пользовательской функцией. Built-in tools, региональные режимы и SDK-хелперы стоит дополнительно сверять с живой документацией и changelog перед запуском в продакшен.

Текущая модель и выбор модели для примера

Официальная страница моделей по состоянию на 2026-08-17 перечисляет gpt-5.6-sol, gpt-5.6-terra и gpt-5.6-luna как доступные через Responses API и Client SDKs с поддержкой Functions. Для примера в этой инструкции используется gpt-5.6-terra как нейтральный вариант, но сам паттерн одинаков для любой поддерживаемой модели.

Модель Поддержка Functions Цена input за 1 MTok Цена output за 1 MTok
gpt-5.6-luna Да, по странице Models $0.20 $1.20
gpt-5.6-terra Да, по странице Models $2 $12
gpt-5.6-sol Да, по странице Models $5 $30

Эти цифры и доступность могут меняться быстро. Для рабочих расчётов и закупки лимитов используйте только актуальную страницу Models.

Пошагово: как использовать Function Calling в OpenAI API

  1. Зафиксируйте Responses API как основной путь и выберите модель.

    Для новых реализаций ориентируйтесь на Responses API. Именно его официальное руководство описывает как текущий цикл Function Calling: модель запрашивает функцию, вы исполняете её в приложении, затем возвращаете результат через function_call_output и продолжаете ход с previous_response_id.

    Ожидаемый результат: вы строите интеграцию не вокруг legacy-паттерна Chat Completions, а вокруг Responses API.

  2. Опишите функцию как tool со строгой схемой.

    Если вам нужны аргументы, строго соответствующие схеме, используйте Structured Outputs и задайте strict: true. По текущим правилам каждый параметр должен быть перечислен в required, а для объекта нужно указать additionalProperties: false.

    const tools = [
      {
        type: 'function',
        name: 'lookup_order_status',
        description: 'Возвращает статус заказа по идентификатору',
        strict: true,
        parameters: {
          type: 'object',
          properties: {
            order_id: {
              type: 'string',
              description: 'Идентификатор заказа'
            }
          },
          required: ['order_id'],
          additionalProperties: false
        }
      }
    ];

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

  3. Отправьте первый запрос с tools в Responses API.

    На первом ходе передайте пользовательский запрос, массив tools и режим tool_choice. Для стартового сценария используйте tool_choice: 'auto'. Если вам нужно последовательное поведение, сразу задайте parallel_tool_calls: false.

    let response = await client.responses.create({
      model: 'gpt-5.6-terra',
      input: 'Проверь статус заказа A-1024 и ответь по-русски.',
      tools,
      tool_choice: 'auto',
      parallel_tool_calls: false
    });

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

  4. Исполните запрошенную функцию в своём приложении.

    Function Calling не означает, что модель сама ходит в вашу систему. Она только формирует запрос к функции, а само действие выполняете вы. В минимальном примере достаточно маршрутизатора по имени функции.

    async function runTool(name, args) {
      if (name === 'lookup_order_status') {
        return {
          order_id: args.order_id,
          status: 'shipped'
        };
      }
    
      throw new Error(`Unknown tool: ${name}`);
    }

    Если модель вернула несколько вызовов, обработайте каждый. Официальное руководство отдельно отмечает, что на поддерживаемых GPT-5+ моделях возможны параллельные вызовы; если это ломает ваш сценарий, оставляйте parallel_tool_calls: false.

    Ожидаемый результат: вы получили объект результата, который готовы отправить модели обратно.

  5. Верните результат функции через function_call_output с тем же call_id.

    Критичный момент в текущем паттерне — не просто отдать результат в текстовом виде, а отправить элемент function_call_output, связанный с исходным вызовом через тот же call_id. Следующий ход продолжайте через previous_response_id.

    response = await client.responses.create({
      model: 'gpt-5.6-terra',
      previous_response_id: response.id,
      input: [
        {
          type: 'function_call_output',
          call_id: call.call_id,
          output: JSON.stringify(result)
        }
      ]
    });

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

  6. Повторяйте цикл, пока модель не перестанет запрашивать функции.

    Ниже — минимальный шаблон рабочего цикла по паттерну официальной документации и Node SDK-руководства. Он полезен как опорный каркас даже если затем вы перепишете его под свой фреймворк.

    const tools = [
      {
        type: 'function',
        name: 'lookup_order_status',
        description: 'Возвращает статус заказа по идентификатору',
        strict: true,
        parameters: {
          type: 'object',
          properties: {
            order_id: { type: 'string', description: 'Идентификатор заказа' }
          },
          required: ['order_id'],
          additionalProperties: false
        }
      }
    ];
    
    async function runTool(name, args) {
      if (name === 'lookup_order_status') {
        return {
          order_id: args.order_id,
          status: 'shipped'
        };
      }
    
      throw new Error(`Unknown tool: ${name}`);
    }
    
    let response = await client.responses.create({
      model: 'gpt-5.6-terra',
      input: 'Проверь статус заказа A-1024 и ответь по-русски.',
      tools,
      tool_choice: 'auto',
      parallel_tool_calls: false
    });
    
    while (true) {
      const functionCalls = response.output.filter(item => item.type === 'function_call');
    
      if (!functionCalls.length) {
        break;
      }
    
      const input = [];
    
      for (const call of functionCalls) {
        const args = JSON.parse(call.arguments);
        const result = await runTool(call.name, args);
    
        input.push({
          type: 'function_call_output',
          call_id: call.call_id,
          output: JSON.stringify(result)
        });
      }
    
      response = await client.responses.create({
        model: 'gpt-5.6-terra',
        previous_response_id: response.id,
        input
      });
    }
    
    console.log(response.output_text);

    Ожидаемый результат: цикл завершается без дополнительных function calls, а в response.output_text появляется финальный ответ модели.

  7. Зафиксируйте режим управления вызовами для продакшена.

    Не оставляйте поведение на уровне «как получится». В текущих документах tool_choice можно задавать как auto, required, принудительно указывать одну конкретную функцию или ограничивать модель выбранным набором инструментов. Это удобно, когда вы переводите сценарий из эксперимента в предсказуемый рабочий поток.

    Ожидаемый результат: вы понимаете, должна ли модель сама решать, вызывать инструмент или нет, и нужен ли вам последовательный режим вместо параллельного.

Как проверить, что всё работает

  • Запустите пример с запросом, который почти наверняка потребует функцию: Проверь статус заказа A-1024 и ответь по-русски.
  • Убедитесь, что промежуточный ответ модели породил хотя бы один запрос функции, а ваше приложение реально вызвало runTool(...).
  • Проверьте, что вы отправили назад элемент function_call_output с тем же call_id, который пришёл от модели.
  • Убедитесь, что продолжение шло через previous_response_id, а не через новый изолированный запрос.
  • Проверьте финальный response.output_text. Официальная Node SDK-документация показывает именно этот практический способ проверки завершённого цикла.

Если финальный текст появился, но инструмент ни разу не вызывался, это тоже проверяемый результат: значит, модель решила не использовать функцию. В таком случае ужесточите инструкцию в prompt или используйте другой режим tool_choice.

Частые ошибки и исправления

  • Ошибка: модель возвращает валидный JSON, но аргументы не соответствуют вашей схеме. Исправление: не полагайтесь только на JSON mode. Для schema-locked аргументов включите strict: true, перечислите все поля в required и добавьте additionalProperties: false.
  • Ошибка: вы выполнили функцию, но модель не продолжает ответ. Исправление: верните результат как function_call_output с тем же call_id и продолжите ход через previous_response_id.
  • Ошибка: ваш backend ожидает строгую последовательность, а модель создаёт несколько вызовов. Исправление: на поддерживаемых GPT-5+ моделях отключите параллельное поведение через parallel_tool_calls: false.
  • Ошибка: вы ориентируетесь на старые примеры Chat Completions и получаете расхождения с текущей документацией. Исправление: для новых проектов используйте Responses API, а Chat Completions держите только как legacy-путь для существующей интеграции.
  • Ошибка: автоматизация ломается из-за региональных ограничений. Исправление: перепроверьте project-level data residency, eligibility/approval и учитывайте, что в EU для /v1/responses есть оговорка: нельзя использовать background=True.

Безопасность и ограничения

  • Функции исполняете вы в приложении, а не модель. Это даёт контроль, но и оставляет на вашей стороне ответственность за допуск к данным, проверку аргументов и побочные эффекты.
  • Structured Outputs использует строгий поднабор JSON Schema. Для объектов сейчас требуется перечислить все поля в required и добавить additionalProperties: false.
  • JSON mode гарантирует валидный JSON, но не гарантирует соответствие вашей схеме. Если вам нужна жёсткая схема аргументов функции, используйте Structured Outputs и strict: true.
  • Региональные настройки хранения и обработки данных работают на уровне проекта и требуют eligibility/approval. Для автоматизаций в EU отдельно проверьте ограничение на background=True у /v1/responses.
  • Цены, модели и SDK-хелперы могут меняться быстрее, чем базовый паттерн цикла. Перед продакшеном сверяйте страницу Models и Changelog.

Практическое ограничение инструкции: здесь не разбираются built-in tools, агентные надстройки и все возможные SDK convenience helpers. Если вам нужен только надёжный пользовательский Function Calling, приведённого цикла достаточно; если строите сложную оркестрацию, проверяйте живые примеры в документации и репозитории SDK.

Что делать дальше

Источники

Вопросы и ответы

Можно ли использовать Chat Completions вместо Responses API?

Да, этот путь всё ещё документирован для legacy-интеграций. Но текущий официальный how-to для Function Calling центрируется на Responses API, поэтому для новых реализаций лучше ориентироваться именно на него.

Достаточно ли JSON mode для аргументов функции?

Нет, если вам нужно строгое соответствие схеме. JSON mode гарантирует валидный JSON, но не соблюдение вашей схемы. Для schema-locked аргументов используйте Structured Outputs и strict: true.

Можно ли заставить модель обязательно вызвать инструмент?

Да. В текущих документах tool_choice можно ставить в auto, required, принудительно задавать одну конкретную функцию или ограничивать модель выбранным набором инструментов.

Как отключить параллельные вызовы функций?

На поддерживаемых GPT-5+ моделях, где доступны built-in tools, возможны параллельные вызовы. Если вам нужно строго последовательное поведение, задайте parallel_tool_calls: false.

Есть ли региональные ограничения для автоматизаций?

Да. Data residency настраивается на уровне проекта и требует eligibility/approval. В документации отдельно отмечено, что в EU для /v1/responses нельзя использовать background=True.

Шаги

HOW-TO
  1. Зафиксировать Responses API и выбрать модель

    | Используйте Responses API как текущий основной путь Function Calling и выберите поддерживаемую модель, например gpt-5.6-terra.

  2. Описать функцию как tool со strict JSON Schema

    | Создайте схему функции с strict: true, перечислите все поля в required и добавьте additionalProperties: false.

  3. Отправить первый запрос с tools

    | Передайте input, tools, tool_choice и при необходимости parallel_tool_calls: false в client.responses.create().

  4. Исполнить функцию в приложении

    | Обработайте запрос модели к функции на своей стороне и получите результат для возврата.

  5. Вернуть function_call_output

    | Отправьте результат функции обратно как элемент function_call_output с тем же call_id и previous_response_id.

  6. Повторять цикл до финального ответа

    | Продолжайте обработку, пока модель не перестанет запрашивать функции, затем прочитайте response.output_text.

  7. Зафиксировать режим orchestration для продакшена

    | Выберите подходящий tool_choice и при необходимости отключите параллельные вызовы через parallel_tool_calls: false.

Источники

SOURCES

Вопросы и ответы

FAQ
Можно ли использовать Chat Completions вместо Responses API?

Да, Chat Completions остаётся документированным для legacy-интеграций, но текущий официальный how-to по Function Calling центрируется на Responses API.

Достаточно ли JSON mode для аргументов функции?

Нет, если вам нужно строгое соответствие схеме. JSON mode гарантирует валидный JSON, но не соблюдение схемы. Для schema-locked аргументов используйте Structured Outputs и strict: true.

Можно ли заставить модель обязательно вызвать инструмент?

Да. tool_choice можно задавать как auto, required, принудительно указывать одну функцию или ограничивать модель выбранным набором инструментов.

Как отключить параллельные вызовы функций?

На поддерживаемых GPT-5+ моделях, где доступны built-in tools, возможны параллельные вызовы. Если нужен строгий последовательный режим, задайте parallel_tool_calls: false.

Есть ли региональные ограничения для автоматизаций?

Да. Data residency работает на уровне проекта и требует eligibility/approval. В документации отдельно отмечено, что в EU для /v1/responses нельзя использовать background=True.

Читайте также

LINKS