Le choix entre Responses API et Chat Completions est principalement une question de propriété de l'état de la conversation, et non de savoir quel endpoint semble le plus récent. Chat Completions oblige votre orchestrateur à renvoyer l'intégralité du tableau messages à chaque tour. Responses peut, quant à lui, poursuivre à partir d'un ID de réponse stocké. Nous avons consulté la documentation API publiée par TokenLab et l'API des modèles en direct le 03/10/2026, et la réponse dépend également des formats acceptés par votre modèle. Nous commençons donc par un tableau décisionnel.
| Besoin de l'agent | Choix | Pourquoi |
|---|---|---|
| Client de chat compatible OpenAI existant, portable sur de nombreux modèles | Chat Completions (/v1/chat/completions) |
Compatibilité de modèle la plus large, selon le guide des formats API (observé le 03/10/2026) |
| Poursuivre une conversation à partir d'une réponse stockée côté serveur | Responses (/v1/responses) |
previous_response_id et store sont des champs Responses |
| Éditions d'historique arbitraires, élagage ou masquage de messages entre les tours | Chat Completions | Vous possédez l'intégralité du tableau messages |
| Réponses en arrière-plan ou événements Responses | Responses | Documenté pour les modèles qui les prennent en charge |
| Connexion WebSocket persistante avec continuation | Responses | wss://api.tokenlab.sh/v1/responses |
| Sortie d'objet JSON portable | Chat Completions | response_format: {"type": "json_object"} |
Le modèle ne liste pas openai_responses |
Chat Completions, ou le format natif du modèle | Responses est réservé aux modèles qui le listent |
| Blocs de réflexion Claude, utilisation d'outils Claude, champs de cache de prompt | Anthropic Messages (/v1/messages) |
Chat Completions ne garantit pas ces champs |
contents Gemini, fichiers, contenu mis en cache, outils Gemini |
Gemini (/v1beta/models/:model:generateContent) |
Conservez les champs natifs Gemini sur la route Gemini |
Points clés à retenir
- Chat Completions repose sur un état géré par le client. Responses peut être référencé côté serveur via
previous_response_id. - Les appels d'outils passent de messages imbriqués
tool_callsavecrole: "tool"à des éléments typésfunction_calletfunction_call_output. - Le streaming passe de morceaux
choices[0].deltaà des événements nommés, et un client Responses doit également surveillerresponse.failedetresponse.incomplete. - La prise en charge des formats dépend du modèle. Au 03/10/2026, seul
gpt-5.6-terraparmi nos trois modèles d'exemple acceptaitopenai_responses. - Ne mélangez jamais les formats au sein d'une même conversation. Convertissez et validez l'historique stocké avant la requête suivante.
Responses API vs Chat Completions : la même tâche, deux requêtes
Prenons une tâche à tour unique : expliquer pourquoi le ciel est bleu en deux phrases. Voici comment elle se présente avec une requête Chat Completions, en utilisant la configuration client du guide des formats API (observé le 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)
Et voici la même tâche en tant que requête 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)
Les champs correspondent un à un pour ce cas simple. Le message système devient instructions au niveau supérieur. messages devient input, qui accepte une chaîne ou un tableau d'éléments. max_tokens devient max_output_tokens.
Les corps de réponse diffèrent davantage. Chat Completions renvoie choices[0].message et un finish_reason. Responses renvoie un tableau output d'éléments typés et un champ status. La référence Create Response (observée le 03/10/2026) liste queued, in_progress, completed, incomplete, failed et cancelled, et indique de vérifier status même lorsque la requête HTTP réussit. Les clés d'utilisation diffèrent également : prompt_tokens et completion_tokens d'un côté, input_tokens et output_tokens de l'autre. Les exemples de référence montrent respectivement 20/9/29 et 10/12/22. Ce sont des charges utiles d'exemple, pas des mesures.
Poursuivre une conversation
Imaginez un agent de support qui vient de répondre à une question et reçoit maintenant « Qu'en est-il de la commande n°4472 ? ». Avec Chat Completions, vous ajoutez le nouveau message utilisateur au tableau stocké et renvoyez tout. Avec Responses, vous passez l'id de la réponse précédente et n'envoyez que le nouveau tour :
{
"model": "gpt-5.6-terra",
"previous_response_id": "resp_abc123",
"input": "What about order #4472?"
}
store est défini par défaut sur true, donc la réponse précédente est conservée pour une récupération ultérieure, sauf si vous le désactivez. Votre application doit toujours persister l'id renvoyé de manière durable entre les sauts. Si vous avez besoin d'un élagage personnalisé ou d'un masquage de message, le format sans état est le plus approprié.
Une estimation approximative montre pourquoi le renvoi sans état est important à l'échelle de l'agent. Supposons un historique de 10 000 tokens renvoyé à chacun des 20 appels. Cela représente 200 000 tokens d'entrée. Au prix d'entrée de gpt-5.6-terra de 0,60 $ par million de tokens, cela revient à 200 000 × 0,60 / 1 000 000 = 0,12 $ (estimation ; nombres de tokens supposés, sans mise en cache). Le prix provient de l'API du modèle en direct, observée le 03/10/2026, avec une tarification mise à jour le 02/10/2026 à 16:53:30.068Z.
Deux mises en garde s'appliquent. Les documents que nous avons lus ne précisent pas si le contexte conservé par le serveur est facturé comme des tokens d'entrée, alors comparez l'usage sur votre propre trafic. De plus, les requêtes dépassant 272 000 tokens d'entrée sont facturées au double pour l'entrée et 1,5 fois pour la sortie pour la requête complète : 1,20 $ et 5,40 $ par million au lieu de 0,60 $ et 3,60 $. Les longs historiques sans état peuvent franchir cette limite.
Appel d'outils : forme de la requête et de la réponse
Les deux formats suivent la boucle du guide Structured Outputs & Tool Calling (observé le 03/10/2026). Envoyez les outils, lisez l'appel, exécutez-le dans votre propre backend, renvoyez le résultat dans le même format, et répétez jusqu'à ce qu'une réponse finale arrive. Les formes diffèrent.
Chat Completions. Les outils sont déclarés comme {"type": "function", "function": {...}}. Le modèle répond avec tool_calls sur choices[0].message, et finish_reason est tool_calls. Pour continuer, vous renvoyez tout le tableau, y compris le message de l'assistant avec ses tool_calls et un message role: "tool" portant tool_call_id. Les valeurs ci-dessous sont illustratives ; lookup_customer est le nom d'outil utilisé dans le guide :
{
"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. Le modèle répond avec des éléments function_call à l'intérieur de output, chacun portant un call_id, un name et des arguments. Vous renvoyez le résultat en tant qu'élément d'entrée function_call_output et pointez vers la réponse précédente :
{
"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\"}"
}
]
}
Vous ne reconstruisez jamais le message d'outil intermédiaire de l'assistant. parallel_tool_calls existe dans les deux formats. Dans la référence Create Response, il est défini par défaut sur true. La référence Chat le liste sans valeur par défaut et indique qu'il s'applique « lorsqu'il est pris en charge par le modèle sélectionné ».
Nous avons trouvé une lacune. Les pages que nous avons lues décrivent les tools et tool_choice de Responses uniquement en termes généraux. Avant de porter vos schémas d'outils, lisez la forme de définition d'outil dans la référence Create Response et testez-la sur votre modèle cible. Suivez également ces règles du guide :
- TokenLab ne convertit pas les outils intégrés entre les formats.
- Validez les arguments de l'outil avant tout effet secondaire.
- Rendez l'exécution de l'outil idempotente, car une nouvelle tentative du client peut répéter le même appel.
- Appliquez vos propres contrôles de permission.
Streaming : événements qu'un client doit gérer
Chat Completions diffuse des morceaux SSE. Votre client lit choices[0].delta.content, enregistre finish_reason et ignore les morceaux sans choices. Avec stream_options={"include_usage": True}, l'utilisation arrive dans un tel morceau. Le guide Streaming (observé le 03/10/2026) traite stop comme terminé, length comme une limite de tokens, et tool_calls comme une demande d'exécution d'outils.
Responses diffuse des événements nommés. Le consommateur du guide gère ceux-ci :
response.output_text.deltapour le texte à ajouterresponse.completedpour le marqueur de succèsresponse.failed,response.incompleteeterrorcomme problèmes terminaux
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")
Trois règles client découlent du guide :
- Une fois le premier événement arrivé, un flux interrompu est incomplet et n'est pas redémarré automatiquement. Conservez la sortie partielle si cela aide, mais ne la marquez pas comme complète. Une requête répétée peut différer et coûter à nouveau.
- Utilisez le SDK pour analyser le SSE, car un morceau réseau n'est pas nécessairement un événement complet.
- Annulez le flux amont lorsque l'utilisateur s'arrête ou se déconnecte, et conservez la clé sur votre serveur.
Responses propose également un WebSocket à wss://api.tokenlab.sh/v1/responses. Les réponses y sont toujours diffusées, background et response.cancel ne sont pas pris en charge, chaque connexion exécute une réponse active à la fois, et une connexion dure jusqu'à 60 minutes. Les événements portent un sequence_number limité à la réponse. Les événements de flux nommés error sont des objets plats, tandis que les échecs de connexion et de protocole utilisent un objet error imbriqué, gérez donc les deux formes.
Vérifiez les formats acceptés par un modèle avant d'envoyer
Lisez tokenlab.accepted_request_formats depuis la page du modèle ou depuis GET /v1/models/{model}, comme décrit dans la référence Get a Model (observée le 03/10/2026) :
curl "https://api.tokenlab.sh/v1/models/gpt-5.6-terra"
La réponse inclut un objet tokenlab avec accepted_request_formats, pricing, les limites et lifecycle. Les valeurs correspondent aux endpoints comme le décrit le guide des erreurs : openai_chat_completions vers /v1/chat/completions, openai_responses vers /v1/responses, anthropic_messages vers /v1/messages, et gemini_generate_content vers /v1beta/models/{model}:generateContent. Un format accepté confirme uniquement l'endpoint. Les outils et champs individuels peuvent toujours varier selon le modèle.
Nous avons vérifié les trois modèles référencés dans cet article par rapport à l'API du modèle en direct le 03/10/2026 :
| Modèle | Formats acceptés | Max tokens entrée / sortie | Prix par 1M entrée / sortie (USD) | Source |
|---|---|---|---|---|
gpt-5.6-terra |
openai_chat_completions, openai_responses |
1 050 000 / 128 000 | 0,60 / 3,60 (entrées jusqu'à 272K) | API en direct |
claude-sonnet-5 |
anthropic_messages, openai_chat_completions |
1 000 000 / 128 000 | 0,90 / 4,50 | API en direct |
gemini-3.5-flash |
gemini_generate_content, openai_chat_completions |
1 048 576 / 65 536 | 0,75 / 4,50 | API en direct |
Tous les trois étaient au stade de cycle de vie actif sans modèle de remplacement, et la tarification a été mise à jour le 02/10/2026 à 16:53:30.068Z. Donc, seul gpt-5.6-terra accepte une requête Responses aujourd'hui. Les deux autres fonctionnent via Chat Completions ou leurs routes natives. Revérifiez avant de déployer, car le cycle de vie et les prix peuvent changer.
La gestion des erreurs compte également ici. Un modèle mal orthographié lors d'un appel de création renvoie 400 model_not_found et peut inclure did_you_mean. Demander GET /v1/models/{model} à propos d'un ID inconnu renvoie 404 model_not_found. Une erreur 503 all_channels_failed avec retryable: false signifie que répéter la requête n'aidera pas. Ne changez pas de modèle automatiquement à moins que votre produit n'ait la permission de le faire.
Liste de contrôle de migration : Responses API vs Chat Completions
Utilisez cet ordre lorsque vous déplacez un agent de Chat Completions vers Responses.
- Confirmez que le modèle liste
openai_responses. S'il ne le fait pas, arrêtez-vous ici. Rester sur Chat Completions est le chemin pris en charge. - Choisissez une limite de basculement. Commencez de nouvelles conversations sur Responses. Ne changez pas de fil de discussion en direct, car les formats représentent l'état et les appels d'outils différemment.
- Convertissez l'historique stocké délibérément. Si vous devez migrer d'anciens fils de discussion, convertissez-les et validez-les dans votre application avant la requête suivante.
- Renommez les champs principaux.
messagesdevientinput, les messages système ou développeur deviennentinstructions, etmax_tokensoumax_completion_tokensdevientmax_output_tokens. - Réécrivez la boucle d'outils. Remplacez l'analyse
choices[0].message.tool_callspar des élémentsfunction_call, et remplacez les messagesrole: "tool"par des élémentsfunction_call_outputindexés parcall_id. - Persistez les IDs de réponse. Stockez chaque
idafin de pouvoir passerprevious_response_id. Décidez destoreet de la rétention dès le départ, et vérifiez combien de temps TokenLab conserve les réponses stockées, car les pages que nous avons lues ne le disent pas. - Réécrivez le consommateur de flux. Gérez
response.output_text.delta,response.completed,response.failed,response.incompleteeterror. Traitez un flux fermé sansresponse.completedcomme un échec. - Vérifiez
status. Un succès HTTP peut toujours comporterincompleteoufailed. - Auditez les paramètres qui pourraient ne pas être transférés. La page Create Response liste
temperature,top_p,tools,parallel_tool_calls,reasoningettext. Elle ne liste pasn,logprobs,logit_bias,frequency_penalty,presence_penalty,seed,top_k,stop,useroustream_options. Vérifiez chacun sur votre modèle avant de vous y fier. TokenLab peut transmettre des champs inconnus, mais cela ne signifie pas que le modèle les accepte. - Mappez la sortie JSON. Chat utilise
response_format. Responses utilise l'objettext, et la prise en charge detext.formatdépend du modèle. - Planifiez autour des endpoints manquants. Les endpoints Cancel, input-items et input-tokens ne sont pas actuellement disponibles. La suppression d'une réponse stockée n'annule pas la génération.
- Testez la relecture avec les nouvelles tentatives désactivées. Gardez
max_retries=0et décidez dans votre propre code quand une nouvelle tentative est sûre. Les générations ayant expiré ne doivent pas être rejouées automatiquement.
FAQ
Puis-je envoyer une requête Responses à Claude Sonnet 5 ou Gemini 3.5 Flash ?
Pas selon l'API du modèle en direct le 03/10/2026. claude-sonnet-5 liste anthropic_messages et openai_chat_completions. gemini-3.5-flash liste gemini_generate_content et openai_chat_completions. Utilisez Chat Completions ou la route native, et vérifiez à nouveau accepted_request_formats avant de déployer.
Est-ce que j'arrête de payer pour les tours précédents lorsque j'utilise previous_response_id ?
Les pages que nous avons lues ne le disent pas. Elles documentent que le serveur peut continuer à partir d'une réponse stockée, mais pas comment le contexte restauré est facturé. Exécutez quelques appels multi-tours et comparez les champs usage par rapport à votre base de référence sans état avant de prévoir des économies.
Puis-je changer de format au milieu d'une conversation ?
Non. Les guides de TokenLab indiquent de conserver un format par conversation, car chaque format représente l'état et les appels d'outils différemment. Si vous devez migrer l'historique stocké, convertissez-le et validez-le dans votre application avant d'envoyer la requête suivante.
Comment annuler une requête Responses en cours ?
Un endpoint d'annulation n'est pas disponible actuellement. La suppression d'une réponse stockée n'annule pas la génération, et les réponses WebSocket ne prennent pas en charge response.cancel. Pour les flux, fermez le flux amont depuis votre serveur lorsque l'utilisateur s'arrête ou se déconnecte.
Avant de changer d'endpoint, ouvrez le catalogue de modèles TokenLab et confirmez accepted_request_formats pour le modèle exact que votre agent appelle.
Sources
Prix observé le 2026-10-03
- TokenLab Docs: API formatsObservé le 2026-10-03
- TokenLab Docs: Create ResponseObservé le 2026-10-03
- TokenLab Docs: Create Chat CompletionObservé le 2026-10-03
- TokenLab Docs: Structured Outputs & Tool CallingObservé le 2026-10-03
- TokenLab Docs: StreamingObservé le 2026-10-03
- TokenLab Docs: Errors agents can act onObservé le 2026-10-03
- TokenLab Docs: Migration GuidesObservé le 2026-10-03
- TokenLab Docs: Get a ModelObservé le 2026-10-03
