Function Calling: Responses API и Chat Completions

Сравнение определений функций, Call ID, результатов, streaming arguments, авторизации, идемпотентности и совместимости маршрутов.

Responses и Chat Completions могут попросить приложение выполнить функцию, но представляют Tool Loop по-разному. Chat Completions определяет функции в tools[].function, возвращает message.tool_calls и принимает результаты как сообщения role: "tool". Responses использует плоские определения, типизированные function_call Output Items и function_call_output, связанные через call_id.

Модель не выполняет функцию. Код приложения должен проверить аргументы, авторизовать операцию, безопасно выполнить её, вернуть результат и предотвратить повторные Side Effects при Retry.

Четыре шага Tool Loop

1. Объявить разрешённую функцию и Schema аргументов
2. Получить один или несколько Function Calls от модели
3. Проверить, авторизовать и выполнить каждый Call в приложении
4. Вернуть каждый результат с Correlation ID вызова

Только после шага четыре модель может сформировать ответ на основе результата. Следующий Tool запускает новую итерацию с новой Call ID. OpenAI Function Calling Guide также описывает многошаговый обмен.

Сравнить Wire Contracts

Аспект Responses API Chat Completions
Определение Плоский элемент tools[] Поля в tools[].function
Предложенный Call function_call Output Item Assistant tool_calls[]
Корреляция call_id id, результат как tool_call_id
Имя function_call.name tool_calls[].function.name
Аргументы JSON-строка function_call.arguments JSON-строка tool_calls[].function.arguments
Результат function_call_output Сообщение role: "tool"
Streaming Типизированные Argument Events Фрагменты delta.tool_calls[]
Финальный текст Output Items / Helper choices[0].message.content

Нельзя связывать Calls по позиции в Array. Параллельные вызовы и chunks могут завершиться в другом порядке. Явная Call ID — стабильный Join Key.

Определить строгую Function Schema

{
  "type": "object",
  "properties": {
    "order_id": { "type": "string", "pattern": "^ORDER-[0-9]{4}$" }
  },
  "required": ["order_id"],
  "additionalProperties": false
}

strict: true просит модель соблюдать Schema, но приложение всё равно парсит и валидирует аргументы. Поддержка pattern различается, поэтому применяется тот же compatibility gate, что и для Structured Outputs.

Реализовать Loop через Responses API

const tools = [{
  type: "function",
  name: "get_delivery_status",
  description: "Return the current delivery status for one order.",
  parameters: {
    type: "object",
    properties: { order_id: { type: "string", pattern: "^ORDER-[0-9]{4}$" } },
    required: ["order_id"], additionalProperties: false,
  },
  strict: true,
}];

const first = await client.responses.create({
  model, input: "Where is ORDER-1001?", tools, parallel_tool_calls: false,
});
const calls = first.output.filter(item => item.type === "function_call");
const outputs = calls.map(call => ({
  type: "function_call_output",
  call_id: call.call_id,
  output: JSON.stringify(executeTool(call.name, call.arguments)),
}));
const final = await client.responses.create({
  model, input: [...first.output, ...outputs], tools, parallel_tool_calls: false,
});

call.call_id и call_id результата должны совпадать. В stateless-варианте предыдущие Output Items возвращаются вместе с результатами. Нельзя предполагать, что любой OpenAI-compatible маршрут хранит Response State.

Реализовать Loop через Chat Completions

const tools = [{
  type: "function",
  function: {
    name: "get_delivery_status",
    description: "Return the current delivery status for one order.",
    parameters: {
      type: "object",
      properties: { order_id: { type: "string", pattern: "^ORDER-[0-9]{4}$" } },
      required: ["order_id"], additionalProperties: false,
    },
    strict: true,
  },
}];

const first = await client.chat.completions.create({ model, messages, tools });
const assistant = first.choices[0].message;
messages.push(assistant);
for (const call of assistant.tool_calls ?? []) {
  messages.push({
    role: "tool",
    tool_call_id: call.id,
    content: JSON.stringify(executeTool(call.function.name, call.function.arguments)),
  });
}

Assistant Message с Calls добавляется в messages до результатов. Его отсутствие или неправильный tool_call_id создаёт некорректную историю.

Считать Streaming Arguments фрагментами

{"order — неполный, а не невалидный JSON. Для каждой Call ID нужен отдельный Buffer: добавлять Delta, дождаться Arguments Done или Completed, один раз распарсить полный String и выполнить после валидации. Responses использует Typed Events, Chat Completions — choices[].delta.tool_calls[]. Нельзя запускать функцию на первом фрагменте. См. AI API Streaming Guide.

Сделать выполнение безопасным и идемпотентным

  • разрешать только зарегистрированные Function Names;
  • ограничивать размер и проверять полную Schema;
  • авторизовать User или Workload для ресурса;
  • разделять Read-only Tools и Side Effects;
  • удалять Secrets из результата;
  • использовать Deadline и ограниченные Downstream Retries;
  • сохранять безопасную Operation Reference.

Для Side Effect создаётся Idempotency Key из стабильного Application Request и Call ID. Результат сохраняется до ответа модели. Replay возвращает сохранённый результат вместо второго refund, сообщения, deployment или изменения БД.

Function Name и Arguments модели — untrusted input. Валидная Schema не выдаёт прав и не заменяет транзакцию.

Определить правила для нескольких Calls

parallel_tool_calls: false упрощает State Machine. При параллельном режиме связывайте результаты по Call ID, ограничивайте Calls и Concurrency, определяйте влияние ошибки, возвращайте результат для каждого принятого вызова и сериализуйте зависимые Side Effects. Параллельность ускоряет независимое чтение, но усложняет authorization, retry и partial failure.

Понимать границу совместимости Modelflare

Modelflare сохраняет Strict Function Definitions и преобразует поддерживаемые формы между Responses и Chat Completions на допустимых OpenAI/Codex-маршрутах. Mapping намеренно уже полной Responses Tool Surface.

Application-defined Functions представлены в обоих форматах. Hosted Tools поставщика — Search, Code Execution и другие — не эквивалентны и не должны считаться автоматически конвертируемыми. Другие семейства OpenAI-compatible остаются Raw Chat Completions Pass-through до проверки; upstream определяет поддержку tools, strict, Parallel Calls, Streaming Arguments и tool_choice.

Тест Необходимая информация
Read-only Call Имя, аргументы, Call ID, связь результата, финальный текст
Невалидные аргументы Явная ошибка без выполнения
Неизвестная функция Отказ по Allowlist
Tool не нужен Обычный текст без выдуманного Call
Streaming Полные аргументы и корректная ID
Повторный Request Один Side Effect или сохранённый результат
Несколько Calls Корреляция независимо от порядка
Route Fallback Те же модель, протокол, Schema и контракт

Reliable AI API Routing помогает сделать смену маршрута явной, AI API Key Security — разделить Workloads и права.

Выбрать формат по контракту приложения

Responses подходит для Typed Output Items, Responses Event Model, State Continuation и проверенных Responses-функций. Chat Completions подходит при стабильном Message Transcript и проверенном Tool Contract поставщика. См. Responses API и Chat Completions.

Стандарт одинаков: явный Tool Allowlist, Strict Argument Schema, валидация в приложении, authorization до выполнения, корреляция по Call ID, идемпотентность Side Effects и полный результат для модели. Надёжность дают эти контроли, а не название endpoint.