Function Calling: Responses API vs Chat Completions
Comparação de Function Definitions, Call IDs, resultados, argumentos em streaming, autorização, idempotência e compatibilidade de rotas.
Responses e Chat Completions podem pedir que uma aplicação execute uma função, mas representam o tool loop de formas diferentes. Chat Completions define funções em tools[].function, retorna message.tool_calls e recebe resultados como mensagens role: "tool". Responses usa definições planas, output items function_call e resultados function_call_output ligados por call_id.
O modelo não executa a função. O código da aplicação deve validar argumentos, autorizar a operação, executá-la, retornar o resultado e impedir efeitos colaterais duplicados quando houver retry.
O tool loop tem quatro etapas
1. Declarar uma função permitida e seu Schema de argumentos
2. Receber uma ou mais chamadas propostas pelo modelo
3. Validar, autorizar e executar na aplicação
4. Retornar cada resultado com a correlation ID da chamada
Somente após a quarta etapa o modelo pode responder com base no resultado. Outra ferramenta inicia uma nova rodada com novo Call ID. O guia OpenAI Function Calling descreve esse intercâmbio em múltiplos passos.
Compare os wire contracts
| Aspecto | Responses API | Chat Completions |
|---|---|---|
| Definição | Item plano em tools[] |
Campos em tools[].function |
| Chamada proposta | Output item function_call |
Assistant tool_calls[] |
| Correlação | call_id |
id, devolvido como tool_call_id |
| Nome | function_call.name |
tool_calls[].function.name |
| Argumentos | String em function_call.arguments |
String em tool_calls[].function.arguments |
| Resultado | function_call_output |
Mensagem role: "tool" |
| Streaming | Eventos tipados | Fragmentos delta.tool_calls[] |
| Texto final | Output items / helper | choices[0].message.content |
Não correlacione por posição no Array. Calls paralelas e chunks podem terminar em outra ordem. A ID explícita é a chave estável.
Defina um Function Schema estrito
{
"type": "object",
"properties": {
"order_id": { "type": "string", "pattern": "^ORDER-[0-9]{4}$" }
},
"required": ["order_id"],
"additionalProperties": false
}
strict: true pede conformidade ao modelo, mas parsing e validação continuam na aplicação. O suporte a pattern varia, então use o mesmo gate de Structured Outputs.
Implemente com 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 e o call_id do resultado devem ser idênticos. Em modo stateless, devolva os output items anteriores com os resultados. Não presuma armazenamento de Response State em qualquer rota OpenAI-compatible.
Implemente com 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)),
});
}
A Assistant Message com os Calls precisa vir antes dos resultados. Omiti-la ou usar tool_call_id incorreto cria transcript inválido.
Trate argumentos de streaming como fragmentos
{"order é JSON incompleto, não inválido. Mantenha um buffer por Call, anexe deltas, espere Arguments Done ou Completed, faça parse uma vez e execute apenas após validar. Responses usa eventos tipados; Chat Completions usa choices[].delta.tool_calls[]. Nunca execute no primeiro fragmento. Veja o guia AI API Streaming.
Torne a execução segura e idempotente
- aceite somente Function Names registrados;
- limite tamanho e valide o Schema completo;
- autorize User ou Workload para o recurso;
- separe leitura de efeitos colaterais;
- remova secrets do resultado;
- use deadline e retries downstream limitados;
- registre uma referência segura.
Para efeitos colaterais, derive uma idempotency key da solicitação estável e do Call ID. Persista o resultado antes de retornar. Um replay devolve o resultado salvo em vez de disparar outro refund, mensagem, deployment ou mutation.
Function Name e Arguments do modelo são untrusted input. Schema válido não concede autorização nem substitui transação.
Decida como tratar múltiplas chamadas
parallel_tool_calls: false simplifica a State Machine. Com paralelismo, correlacione por Call ID, limite Calls e concurrency, defina impacto de falhas, retorne um resultado por Call e serialize efeitos cuja ordem importe. Paralelismo acelera leituras independentes, mas complica autorização, retry e falha parcial.
Entenda o limite de compatibilidade do Modelflare
Modelflare preserva definições strict e mapeia formas suportadas entre Responses e Chat Completions em rotas OpenAI/Codex elegíveis. O mapping é propositalmente menor que toda a superfície de Tools do Responses.
Functions da aplicação podem ser representadas nos dois formatos. Hosted Tools executadas pelo provedor, como busca ou execução de código, não são equivalentes. Outras famílias OpenAI-compatible ficam como Raw Chat Completions Pass-through até verificação; upstream decide tools, strict, Calls paralelas, streaming arguments e tool_choice.
| Teste | Evidência necessária |
|---|---|
| Call de leitura | Nome, argumentos, Call ID, vínculo do resultado e texto final |
| Argumentos inválidos | Falha explícita sem execução |
| Função desconhecida | Rejeição pela allowlist |
| Sem Tool | Texto normal sem Call inventada |
| Streaming | Argumentos reconstruídos e ID correta |
| Request repetido | Um efeito ou resultado salvo |
| Várias Calls | Correlação independente da ordem |
| Route fallback | Mesmo modelo, protocolo, Schema e contrato |
Use Reliable AI API Routing para mudanças explícitas e AI API Key Security para separar workloads e permissões.
Escolha o formato pelo contrato da aplicação
Use Responses para Typed Output Items, Event Model, State Continuation e recursos verificados. Use Chat Completions quando a aplicação já possui transcript estável e o contrato de Tools do provider foi testado. Veja Responses API vs Chat Completions.
O padrão é igual: Tool Allowlist explícita, Argument Schema strict, validação na aplicação, autorização antes da execução, correlação por Call ID, idempotência dos efeitos e resultado completo para o modelo. Esses controles, não o nome do endpoint, tornam o workflow confiável.