A escolha entre Responses API e Chat Completions é, em grande parte, uma questão de quem detém o estado da conversa, e não de qual endpoint parece mais novo. O Chat Completions faz com que seu orquestrador reenvie todo o array messages a cada turno. O Responses pode continuar a partir de um ID de resposta armazenado. Lemos a documentação da API publicada pela TokenLab e a API de modelos em tempo real em 03/10/2026, e a resposta também depende de quais formatos seu modelo aceita. Portanto, começamos com uma tabela de decisão.
| Requisito do Agente | Escolha | Por que |
|---|---|---|
| Cliente de chat compatível com OpenAI existente, portátil entre muitos modelos | Chat Completions (/v1/chat/completions) |
Maior compatibilidade de modelos, conforme o guia de formatos de API (observado em 03/10/2026) |
| Continuar uma conversa a partir de uma resposta armazenada no servidor | Responses (/v1/responses) |
previous_response_id e store são campos do Responses |
| Edições arbitrárias de histórico, poda ou mascaramento de mensagens entre turnos | Chat Completions | Você detém o array messages completo |
| Respostas em segundo plano ou eventos de Responses | Responses | Documentado para modelos que os suportam |
| Conexão WebSocket persistente com continuação | Responses | wss://api.tokenlab.sh/v1/responses |
| Saída de objeto JSON portátil | Chat Completions | response_format: {"type": "json_object"} |
O modelo não lista openai_responses |
Chat Completions, ou o formato nativo do modelo | Responses é apenas para modelos que o listam |
| Blocos de pensamento do Claude, uso de ferramentas do Claude, campos de prompt-cache | Anthropic Messages (/v1/messages) |
Chat Completions não garante esses campos |
contents do Gemini, arquivos, conteúdo em cache, ferramentas do Gemini |
Gemini (/v1beta/models/:model:generateContent) |
Mantenha os campos nativos do Gemini na rota do Gemini |
Principais conclusões
- Chat Completions é um estado gerenciado pelo cliente. Responses pode ser referenciado pelo servidor através de
previous_response_id. - Chamadas de ferramenta mudam de mensagens aninhadas
tool_callsmaisrole: "tool"para itens tipadosfunction_callefunction_call_output. - O streaming muda de chunks
choices[0].deltapara eventos nomeados, e um cliente Responses também deve monitorarresponse.failederesponse.incomplete. - O suporte a formato é por modelo. Em 03/10/2026, apenas o
gpt-5.6-terrados nossos três modelos de exemplo aceitavaopenai_responses. - Nunca misture formatos dentro de uma mesma conversa. Converta e valide o histórico armazenado antes da próxima requisição.
Responses API vs Chat Completions: a mesma tarefa, duas requisições
Considere uma tarefa de turno único: explique por que o céu é azul em duas frases. Aqui está como uma requisição Chat Completions, usando a configuração de cliente do guia de formatos de API (observado em 03/10/2026):
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["TOKENLAB_API_KEY"],
base_url="https://api.tokenlab.sh/v1",
)
response = client.chat.completions.create(
model="gpt-5.6-terra",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Explain why the sky is blue in two sentences."},
],
max_tokens=1000,
)
print(response.choices[0].message.content)
E aqui está a mesma tarefa como uma requisição Responses:
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["TOKENLAB_API_KEY"],
base_url="https://api.tokenlab.sh/v1",
)
response = client.responses.create(
model="gpt-5.6-terra",
instructions="You are a helpful assistant.",
input="Explain why the sky is blue in two sentences.",
max_output_tokens=1000,
)
print(response.output_text)
Os campos mapeiam um para um neste caso simples. A mensagem de sistema torna-se instructions de nível superior. messages torna-se input, que aceita uma string ou um array de itens. max_tokens torna-se max_output_tokens.
Os corpos das respostas diferem mais. Chat Completions retorna choices[0].message e um finish_reason. Responses retorna um array output de itens tipados e um campo status. A referência de Create Response (observada em 03/10/2026) lista queued, in_progress, completed, incomplete, failed e cancelled, e orienta a verificar o status mesmo quando a requisição HTTP é bem-sucedida. As chaves de uso também diferem: prompt_tokens e completion_tokens de um lado, input_tokens e output_tokens do outro. Os exemplos de referência mostram 20/9/29 e 10/12/22 respectivamente. Esses são payloads de exemplo, não medições.
Continuando uma conversa
Imagine um agente de suporte que acabou de responder a uma pergunta e agora recebe "E quanto ao pedido #4472?" Com Chat Completions, você anexa a nova mensagem do usuário ao array armazenado e reenvia tudo. Com Responses, você passa o id da resposta anterior e envia apenas o novo turno:
{
"model": "gpt-5.6-terra",
"previous_response_id": "resp_abc123",
"input": "What about order #4472?"
}
store tem como padrão true, então a resposta anterior é mantida para recuperação posterior, a menos que você a desative. Sua aplicação ainda precisa persistir o id retornado de forma durável entre os saltos. Se você precisar de poda personalizada ou mascaramento de mensagens, o formato sem estado (stateless) é a opção mais direta.
Uma estimativa aproximada mostra por que o reenvio sem estado importa na escala de agentes. Suponha um histórico de 10.000 tokens reenviado em cada uma das 20 chamadas. Isso são 200.000 tokens de entrada. Ao preço de entrada do gpt-5.6-terra de US$ 0,60 por 1 milhão de tokens, isso resulta em 200.000 × 0,60 / 1.000.000 = US$ 0,12 (estimativa; contagens de tokens assumidas, sem cache). O preço vem da API de modelos em tempo real, observada em 03/10/2026, com preços atualizados em 02/10/2026T16:53:30.068Z.
Duas ressalvas se aplicam. A documentação que lemos não diz se o contexto mantido pelo servidor é cobrado como tokens de entrada, então compare o usage no seu próprio tráfego. E requisições acima de 272 mil tokens de entrada são precificadas a 2x a entrada e 1,5x a saída para a requisição completa: US$ 1,20 e US$ 5,40 por 1 milhão, em vez de US$ 0,60 e US$ 3,60. Históricos longos sem estado podem cruzar essa linha.
Chamada de ferramenta: formato de requisição e resposta
Ambos os formatos seguem o loop no guia de Structured Outputs & Tool Calling (observado em 03/10/2026). Envie ferramentas, leia a chamada, execute-a em seu próprio backend, retorne o resultado no mesmo formato e repita até que uma resposta final chegue. Os formatos diferem.
Chat Completions. Ferramentas são declaradas como {"type": "function", "function": {...}}. O modelo responde com tool_calls em choices[0].message, e finish_reason é tool_calls. Para continuar, você reenvia o array completo, incluindo a mensagem do assistente com seus tool_calls e uma mensagem role: "tool" contendo tool_call_id. Os valores abaixo são ilustrativos; lookup_customer é o nome da ferramenta usado no guia:
{
"model": "gpt-5.6-terra",
"messages": [
{"role": "user", "content": "Look up ana@example.com"},
{
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_xyz789",
"type": "function",
"function": {"name": "lookup_customer", "arguments": "{\"email\": \"ana@example.com\"}"}
}
]
},
{"role": "tool", "tool_call_id": "call_xyz789", "content": "{\"status\": \"active\"}"}
]
}
Responses. O modelo responde com itens function_call dentro de output, cada um contendo um call_id, name e arguments. Você retorna o resultado como um item de entrada function_call_output e aponta para a resposta anterior:
{
"model": "gpt-5.6-terra",
"previous_response_id": "resp_abc123",
"input": [
{
"type": "function_call_output",
"call_id": "call_xyz789",
"output": "{\"status\": \"shipped\", \"tracking_number\": \"1Z999\"}"
}
]
}
Você nunca reconstrói a mensagem de ferramenta intermediária do assistente. parallel_tool_calls existe em ambos os formatos. Na referência de Create Response, o padrão é true. A referência de Chat o lista sem um padrão e diz que se aplica "quando suportado pelo modelo selecionado".
Encontramos uma lacuna. As páginas que lemos descrevem tools e tool_choice do Responses apenas em termos gerais. Antes de portar esquemas de ferramentas, leia o formato de definição de ferramenta na referência de Create Response e teste-o no seu modelo alvo. Siga também estas regras do guia:
- A TokenLab não converte ferramentas integradas entre formatos.
- Valide os argumentos da ferramenta antes de qualquer efeito colateral.
- Torne a execução da ferramenta idempotente, pois uma nova tentativa do cliente pode repetir a mesma chamada.
- Aplique suas próprias verificações de permissão.
Streaming: eventos que um cliente deve manipular
Chat Completions transmite chunks SSE. Seu cliente lê choices[0].delta.content, registra finish_reason e pula chunks sem choices. Com stream_options={"include_usage": True}, o uso chega em tal chunk. O guia de Streaming (observado em 03/10/2026) trata stop como completo, length como um limite de tokens e tool_calls como uma solicitação para executar ferramentas.
Responses transmite eventos nomeados. O consumidor do guia manipula estes:
response.output_text.deltapara texto a ser anexadoresponse.completedpara o marcador de sucessoresponse.failed,response.incompleteeerrorcomo problemas terminais
import os
from openai import OpenAI
with OpenAI(
api_key=os.environ["TOKENLAB_API_KEY"],
base_url="https://api.tokenlab.sh/v1",
timeout=30.0,
max_retries=0,
) as client:
completed = False
with client.responses.create(
model="gpt-5.6-terra",
input="Write a short poem.",
stream=True,
) as stream:
for event in stream:
if event.type == "response.output_text.delta":
print(event.delta, end="", flush=True)
elif event.type == "response.completed":
completed = True
elif event.type in {"response.failed", "response.incomplete", "error"}:
raise RuntimeError(f"Stream ended with {event.type}")
if not completed:
raise RuntimeError("Stream closed before response.completed")
Três regras de cliente seguem do guia:
- Após a chegada do primeiro evento, um stream interrompido está incompleto e não é reiniciado automaticamente. Mantenha a saída parcial se ajudar, mas não a marque como completa. Uma requisição repetida pode diferir e custar novamente.
- Use o SDK para analisar SSE, pois um chunk de rede não é necessariamente um evento completo.
- Cancele o stream upstream quando o usuário parar ou se desconectar, e mantenha a chave em seu servidor.
Responses também oferece um WebSocket em wss://api.tokenlab.sh/v1/responses. As respostas lá são sempre transmitidas, background e response.cancel não são suportados, cada conexão executa uma resposta ativa por vez, e uma conexão dura até 60 minutos. Os eventos carregam um sequence_number com escopo de resposta. Eventos de stream chamados error são objetos planos, enquanto falhas de conexão e protocolo usam um objeto error aninhado, então manipule ambos os formatos.
Verifique quais formatos um modelo aceita antes de enviar
Leia tokenlab.accepted_request_formats na página do modelo ou em GET /v1/models/{model}, conforme descrito na referência de Get a Model (observada em 03/10/2026):
curl "https://api.tokenlab.sh/v1/models/gpt-5.6-terra"
A resposta inclui um objeto tokenlab com accepted_request_formats, pricing, limites e lifecycle. Os valores mapeiam para endpoints conforme o guia de erros descreve: openai_chat_completions para /v1/chat/completions, openai_responses para /v1/responses, anthropic_messages para /v1/messages e gemini_generate_content para /v1beta/models/{model}:generateContent. Um formato aceito confirma apenas o endpoint. Ferramentas e campos individuais ainda podem variar de acordo com o modelo.
Verificamos os três modelos que este artigo referencia em relação à API de modelos em tempo real em 03/10/2026:
| Modelo | Formatos aceitos | Tokens máx. de entrada / saída | Preço por 1M ent / sai (USD) | Fonte |
|---|---|---|---|---|
gpt-5.6-terra |
openai_chat_completions, openai_responses |
1.050.000 / 128.000 | 0,60 / 3,60 (entradas até 272K) | API em tempo real |
claude-sonnet-5 |
anthropic_messages, openai_chat_completions |
1.000.000 / 128.000 | 0,90 / 4,50 | API em tempo real |
gemini-3.5-flash |
gemini_generate_content, openai_chat_completions |
1.048.576 / 65.536 | 0,75 / 4,50 | API em tempo real |
Todos os três estavam no estágio de ciclo de vida ativo sem modelo de substituição, e os preços foram atualizados em 02/10/2026T16:53:30.068Z. Portanto, apenas o gpt-5.6-terra aceita uma requisição Responses hoje. Os outros dois funcionam através de Chat Completions ou suas rotas nativas. Verifique novamente antes de lançar, já que o ciclo de vida e os preços podem mudar.
O tratamento de erros também importa aqui. Um modelo com erro de digitação em uma chamada de criação retorna 400 model_not_found e pode incluir did_you_mean. Perguntar GET /v1/models/{model} sobre um ID desconhecido retorna 404 model_not_found. Um 503 all_channels_failed com retryable: false significa que repetir a requisição não ajudará. Não troque de modelos automaticamente, a menos que seu produto tenha permissão para fazê-lo.
Checklist de migração: Responses API vs Chat Completions
Use esta ordem ao mover um agente de Chat Completions para Responses.
- Confirme se o modelo lista
openai_responses. Se não listar, pare aqui. Permanecer no Chat Completions é o caminho suportado. - Escolha um limite de transição. Inicie novas conversas no Responses. Não troque um thread ativo no meio do caminho, porque os formatos representam estado e chamadas de ferramenta de forma diferente.
- Converta o histórico armazenado deliberadamente. Se você precisar migrar threads antigos, converta-os e valide-os em sua aplicação antes da próxima requisição.
- Renomeie os campos principais.
messagestorna-seinput, mensagens de sistema ou de desenvolvedor tornam-seinstructions, emax_tokensoumax_completion_tokenstorna-semax_output_tokens. - Reescreva o loop de ferramentas. Substitua a análise de
choices[0].message.tool_callspor itensfunction_calle substitua mensagensrole: "tool"por itensfunction_call_outputindexados porcall_id. - Persista IDs de resposta. Armazene cada
idpara que você possa passarprevious_response_id. Decida sobrestoree retenção de antemão, e verifique por quanto tempo a TokenLab mantém as respostas armazenadas, pois as páginas que lemos não dizem. - Reescreva o consumidor de stream. Manipule
response.output_text.delta,response.completed,response.failed,response.incompleteeerror. Trate um stream fechado semresponse.completedcomo uma falha. - Verifique o
status. Um sucesso HTTP ainda pode carregarincompleteoufailed. - Audite parâmetros que podem não ser transferidos. A página de Create Response lista
temperature,top_p,tools,parallel_tool_calls,reasoningetext. Ela não listan,logprobs,logit_bias,frequency_penalty,presence_penalty,seed,top_k,stop,useroustream_options. Verifique cada um em seu modelo antes de confiar nele. A TokenLab pode passar campos desconhecidos, mas isso não significa que o modelo os aceita. - Mapeie a saída JSON. Chat usa
response_format. Responses usa o objetotext, e o suporte atext.formatdepende do modelo. - Planeje em torno de endpoints ausentes. Endpoints de cancelamento, itens de entrada e tokens de entrada não estão disponíveis atualmente. Excluir uma resposta armazenada não cancela a geração.
- Teste de repetição com retries desativados. Mantenha
max_retries=0e decida em seu próprio código quando uma nova tentativa é segura. Gerações com timeout não devem ser repetidas automaticamente.
FAQ
Posso enviar uma requisição Responses para o Claude Sonnet 5 ou Gemini 3.5 Flash?
Não, de acordo com a API de modelos em tempo real em 03/10/2026. claude-sonnet-5 lista anthropic_messages e openai_chat_completions. gemini-3.5-flash lista gemini_generate_content e openai_chat_completions. Use Chat Completions ou a rota nativa, e verifique accepted_request_formats novamente antes de lançar.
Paro de pagar por turnos anteriores quando uso previous_response_id?
As páginas que lemos não dizem. Elas documentam que o servidor pode continuar a partir de uma resposta armazenada, mas não como o contexto restaurado é cobrado. Execute algumas chamadas de múltiplos turnos e compare os campos usage com sua linha de base sem estado antes de planejar economias.
Posso alternar formatos no meio de uma conversa?
Não. Os guias da TokenLab dizem para manter um formato por conversa, porque cada formato representa estado e chamadas de ferramenta de forma diferente. Se você precisar migrar o histórico armazenado, converta-o e valide-o em sua aplicação antes de enviar a próxima requisição.
Como cancelo uma requisição Responses em execução?
Um endpoint de cancelamento não está disponível atualmente. Excluir uma resposta armazenada não cancela a geração, e as respostas WebSocket não suportam response.cancel. Para streams, feche o stream upstream a partir do seu servidor quando o usuário parar ou se desconectar.
Antes de alterar os endpoints, abra o catálogo de modelos da TokenLab e confirme accepted_request_formats para o modelo exato que seu agente chama.
Fontes
Preço observado em 2026-10-03
- TokenLab Docs: API formatsObservado em 2026-10-03
- TokenLab Docs: Create ResponseObservado em 2026-10-03
- TokenLab Docs: Create Chat CompletionObservado em 2026-10-03
- TokenLab Docs: Structured Outputs & Tool CallingObservado em 2026-10-03
- TokenLab Docs: StreamingObservado em 2026-10-03
- TokenLab Docs: Errors agents can act onObservado em 2026-10-03
- TokenLab Docs: Migration GuidesObservado em 2026-10-03
- TokenLab Docs: Get a ModelObservado em 2026-10-03
