Function Calling: Responses API와 Chat Completions 비교

Function Definition, Call ID, 결과 Message, Streaming Arguments, 권한, Idempotency와 Route 호환성을 비교합니다.

Responses와 Chat Completions는 모두 애플리케이션에 함수 실행을 요청할 수 있지만 Tool Loop를 표현하는 방식이 다릅니다. Chat Completions는 tools[].function 아래에 정의를 두고 message.tool_calls를 반환하며 role: "tool" Message로 결과를 받습니다. Responses는 flat function definition, typed function_call Output Item, call_id로 연결된 function_call_output을 사용합니다.

모델이 애플리케이션 함수를 직접 실행하는 것은 아닙니다. 애플리케이션 code가 제안된 arguments를 검증하고 권한을 확인한 뒤 정확히 실행하고, 결과를 모델에 반환하며, request retry 시 중복 side effect를 막아야 합니다.

Tool Loop의 네 단계

1. 허용된 함수와 Argument Schema를 선언한다
2. 모델이 제안한 하나 이상의 Function Call을 받는다
3. 애플리케이션에서 검증, 권한 확인, 실행을 수행한다
4. Call의 Correlation ID를 사용해 결과를 반환한다

네 번째 단계 이후에야 모델이 Tool Result에 근거한 답을 만들 수 있습니다. 다른 Tool이 필요하면 새 Call ID로 반복합니다. OpenAI Function Calling 가이드도 이를 multi-step exchange로 설명합니다.

Wire Contract 비교하기

항목 Responses API Chat Completions
Function Definition Flat tools[] item tools[].function 아래에 nested
모델이 제안한 Call Typed function_call item Assistant tool_calls[]
Correlation ID call_id id, 결과에는 tool_call_id
Function Name function_call.name tool_calls[].function.name
Arguments function_call.arguments JSON string tool_calls[].function.arguments JSON string
Tool Result function_call_output item role: "tool" Message
Streaming Typed argument delta events delta.tool_calls[] fragments
Final Text Output items / helper choices[0].message.content

Array position으로 Call을 연결하면 안 됩니다. Parallel call과 streamed chunk는 완료 순서가 달라질 수 있으므로 명시적 Call ID를 stable join key로 사용합니다.

Strict Function Schema 정의하기

읽기 전용 배송 조회 함수의 argument schema입니다.

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

strict: true는 지원 모델에 Schema 준수를 요청하지만 애플리케이션 parse와 validation은 여전히 필요합니다. pattern과 같은 기능은 provider마다 다를 수 있으므로 Structured Outputs와 같은 compatibility gate를 적용합니다.

Responses API로 Loop 구현하기

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,
});

모델 Output의 call.call_id와 결과의 call_id가 정확히 일치해야 합니다. Stateless exchange에서는 앞선 Output Item과 Function Result를 함께 반환합니다. 모든 OpenAI-compatible route가 Response State를 저장한다고 가정하지 마십시오.

Chat Completions로 Loop 구현하기

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)),
  });
}

Tool Call이 포함된 Assistant Message를 먼저 messages에 추가한 뒤 결과를 넣습니다. 원본 Message를 누락하거나 맞지 않는 tool_call_id를 반환하면 transcript가 유효하지 않습니다.

Streaming Arguments를 Fragment로 다루기

{"order는 invalid JSON이 아니라 incomplete JSON입니다. Call별 buffer를 만들고 delta를 올바른 buffer에 추가한 뒤 Arguments Done 또는 Completed Signal을 기다립니다. 완성된 string을 한 번만 parse하고 validation 후 실행합니다. Responses는 typed events를, Chat Completions는 choices[].delta.tool_calls[]를 사용합니다. 첫 fragment에서 Tool을 실행하면 안 됩니다. 자세한 경계는 AI API Streaming 가이드를 참고하십시오.

Tool 실행을 안전하고 Idempotent하게 만들기

  • 등록된 Function Name만 허용합니다.
  • 크기 제한 내에서 parse하고 완전한 Schema를 검증합니다.
  • 현재 User 또는 Workload가 resource를 사용할 권한이 있는지 확인합니다.
  • Read-only Tool과 side-effect Tool을 분리합니다.
  • 모델로 돌려보낼 결과에서 secrets를 제거합니다.
  • Deadline과 bounded downstream retry를 사용합니다.
  • 원문 대신 안전한 Operation Reference를 기록합니다.

Side effect가 있는 Tool은 stable application request와 Call ID에서 Idempotency Key를 만들고 결과를 먼저 저장해야 합니다. Network retry가 같은 Call을 replay하면 두 번째 환불, 메시지, deployment, DB mutation 대신 저장된 결과를 반환합니다.

모델이 생성한 Function Name과 Arguments는 untrusted input입니다. Schema가 유효해도 권한이나 소유권을 부여하지 않으며 transaction boundary를 대체하지 못합니다.

Multiple Call 처리 방식을 결정하기

예시는 parallel_tool_calls: false로 State Machine을 단순하게 유지합니다. Parallel Call을 켜면:

  • completion order가 아니라 Call ID로 결과를 연결합니다.
  • Response당 Call 수와 application concurrency를 제한합니다.
  • 하나의 실패가 다른 결과에 미치는 영향을 정의합니다.
  • 수락한 모든 Call에 결과 하나를 반환합니다.
  • 순서가 중요한 side effect는 serialize합니다.

독립 읽기에서는 latency를 줄일 수 있지만 authorization, ordering, retry, partial failure가 복잡해집니다.

Modelflare 호환성 경계 이해하기

Modelflare는 eligible OpenAI/Codex route에서 strict function definition을 보존하고 지원되는 Function Call shape를 Responses와 Chat Completions 사이에서 mapping합니다. 이 범위는 전체 Responses Tool Surface보다 의도적으로 좁습니다.

Application-defined Function Tool은 두 형식으로 표현할 수 있습니다. Provider가 실행하는 Search, Code Execution 등 Hosted Tool은 같은 개념이 아니며 Chat Completions로 자동 변환된다고 가정할 수 없습니다. 다른 OpenAI-compatible model family는 별도 검증 전까지 Raw Chat Completions Pass-through이며, tools, strict, parallel call, streaming arguments, tool_choice 지원은 upstream contract가 결정합니다.

테스트 필요한 증거
Read-only Call Function Name, parsed arguments, Call ID, result linkage, final text
Invalid Arguments Tool 미실행과 명시적 validation failure
Unknown Function Application allowlist 거절
No Tool Path 허위 Call 없는 정상 final text
Streaming Call 완전한 arguments와 올바른 Call ID
Repeated Request 한 번의 side effect 또는 cached result
Multiple Calls 완료 순서와 무관한 correlation
Route Fallback 동일 모델, protocol, Schema, result contract

안정적인 AI API 라우팅으로 route change를 명시적으로 관리하고 AI API Key 보안으로 workload와 permission을 분리하십시오.

Application Contract에 따라 형식 선택하기

Typed Output Items, Responses Event Model, State Continuation 또는 검증된 Responses 기능이 필요하면 Responses를 사용합니다. 안정된 Message Transcript를 이미 소유하고 provider Tool Contract가 검증되었다면 Chat Completions가 적합합니다. 더 넓은 비교는 Responses API와 Chat Completions를 참고하십시오.

두 형식의 구현 기준은 같습니다. 명시적 Tool Allowlist, strict argument schema, application-side validation, 실행 전 authorization, Call ID correlation, side-effect idempotency, 완전한 결과 반환이 필요합니다. Endpoint 이름이 아니라 이 control들이 workflow를 신뢰할 수 있게 만듭니다.