À la fin de ce guide, vous serez en mesure d'appeler l'API de lot d'OpenAI (Batch API) pour exécuter des milliers de requêtes de modèle sous forme de tâche asynchrone unique et de récupérer tous les résultats avec une réduction de 50 %. Vous emballerez vos invites dans un fichier JSONL, soumettrez un lot, interrogerez son état jusqu'à sa finalisation, téléchargerez le résultat, puis testerez chaque étape dans Apidog avant de l'intégrer en production. Si votre travail est plus interactif, le chemin synchrone est plus approprié, et vous pouvez plutôt tester l'API ChatGPT avec Apidog.
Qu'est-ce que l'API de lot et quand l'utiliser
L'API de lot est un point d'accès asynchrone pour de grands volumes d'appels de modèles qui peuvent tolérer un délai. Au lieu d'une requête HTTP par invite, vous regroupez de nombreuses requêtes dans un seul fichier JSONL, le soumettez comme une seule tâche et interrogez son état jusqu'à sa complétion. OpenAI exécute la tâche pendant les heures creuses et renvoie tous les résultats dans un fichier de sortie.
Vous obtenez deux avantages concrets. Premièrement, une réduction forfaitaire de 50 % sur les jetons d'entrée et de sortie par rapport à l'API synchrone. Deuxièmement, un débit plus élevé, car les tâches par lots utilisent un pool de limites de taux distinct et n'entrent pas en concurrence avec votre trafic en direct. Le compromis est la latence. OpenAI s'engage à terminer dans les 24 heures ; de nombreuses tâches se terminent plus tôt, mais vous ne pouvez pas compter sur cela.
Utilisez le traitement par lots lorsque le travail est hors ligne et de grande ampleur :
- Classer ou étiqueter un arriéré d'enregistrements
- Générer des embeddings pour un corpus entier
- Génération de contenu en vrac (descriptions de produits, résumés, traductions)
- Exécuter des suites d'évaluation ou des comparaisons de modèles sur un ensemble de données
Évitez-le pour tout ce qu'un utilisateur attend. Les interfaces de chat, l'autocomplétion et les agents en direct nécessitent les points d'accès synchrones. Si vous générez de nombreuses configurations de modèles ou d'agents à la fois, le traitement par lots s'accorde bien avec cette charge de travail ; consultez notre guide sur la génération de plus de 100 configurations d'agents avec le traitement par lots.
Ce dont vous avez besoin avant de commencer
Le flux complet s'étend sur deux points d'accès, /v1/files et /v1/batches, et quatre étapes. Voici la structure avant d'examiner les appels.
| Étape | Point d'accès | Ce qui se passe |
|---|---|---|
| 1. Télécharger | POST /v1/files |
Envoyez votre fichier .jsonl avec purpose: "batch", obtenez un ID de fichier |
| 2. Créer | POST /v1/batches |
Soumettez l'ID du fichier avec un point d'accès et une fenêtre de complétion |
| 3. Interroger | GET /v1/batches/{id} |
Vérifiez le status jusqu'à ce qu'il indique completed |
| 4. Récupérer | GET /v1/files/{id}/content |
Téléchargez les résultats via output_file_id |
Pour suivre, vous avez besoin d'une clé API OpenAI exportée sous le nom OPENAI_API_KEY, d'un fichier JSONL de requêtes et d'un outil pour déclencher et inspecter les appels. Chaque étape renvoie un objet sur lequel vous pouvez faire des assertions, ce qui rend l'ensemble du cycle de vie simple à tester.
Étape 1 : construire et télécharger le fichier JSONL
Votre entrée est un fichier JSONL où chaque ligne est une requête autonome. Chaque ligne nécessite quatre champs : un custom_id que vous choisissez (afin de pouvoir faire correspondre les résultats aux entrées), la method (POST), l'url (le point d'accès cible comme /v1/chat/completions) et un body contenant les paramètres de requête réels.
{"custom_id": "req-1", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-4.1-mini", "messages": [{"role": "user", "content": "Classify the sentiment of: 'shipping was slow but the product is great'"}]}}
{"custom_id": "req-2", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-4.1-mini", "messages": [{"role": "user", "content": "Classify the sentiment of: 'returned it the same day'"}]}}
Le custom_id doit être unique dans le fichier. Les résultats reviennent sans ordre garanti, c'est pourquoi cet ID est la façon dont vous reconnectez chaque réponse à sa ligne source. Un seul lot peut contenir jusqu'à 50 000 requêtes et le fichier peut atteindre 200 Mo.
Téléchargez-le vers l'API Files avec l'objectif batch :
curl https://api.openai.com/v1/files \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-F purpose="batch" \
-F file="@requests.jsonl"
La réponse contient un id de fichier (quelque chose comme file-abc123). C'est votre input_file_id pour l'étape suivante.
Étape 2 : créer le lot
Créez maintenant la tâche. Vous transmettez l'input_file_id, l'endpoint que vous ciblez et la completion_window. Actuellement, completion_window accepte une seule valeur, "24h".
curl https://api.openai.com/v1/batches \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input_file_id": "file-abc123",
"endpoint": "/v1/chat/completions",
"completion_window": "24h",
"metadata": {"job": "sentiment-backfill"}
}'
Le champ endpoint doit correspondre à l'url utilisée dans vos lignes JSONL. Les cibles prises en charge incluent /v1/chat/completions, /v1/responses, /v1/embeddings, /v1/completions et /v1/moderations, entre autres. L'objet metadata optionnel contient jusqu'à 16 paires clé-valeur, ce qui est pratique pour étiqueter les tâches que vous voudrez filtrer plus tard.
L'appel renvoie un objet de lot. Les champs qui vous intéresseront le plus sont les suivants :
{
"id": "batch_abc123",
"object": "batch",
"endpoint": "/v1/chat/completions",
"input_file_id": "file-abc123",
"completion_window": "24h",
"status": "validating",
"output_file_id": null,
"error_file_id": null,
"request_counts": { "total": 0, "completed": 0, "failed": 0 },
"created_at": 1733452800,
"metadata": { "job": "sentiment-backfill" }
}
Étape 3 : interroger l'état du lot
Un nouveau lot commence par l'état validating. De là, il passe par un ensemble d'états documentés. Interrogez GET /v1/batches/{batch_id} et lisez le champ status.
| État | Signification |
|---|---|
validating |
Le fichier d'entrée est vérifié avant le début de l'exécution |
in_progress |
Les requêtes sont en cours de traitement |
finalizing |
L'exécution est terminée et le fichier de sortie est en préparation |
completed |
Terminé ; les résultats sont prêts à être téléchargés |
failed |
La validation a échoué ; rien n'a été exécuté |
expired |
La fenêtre de 24 heures s'est fermée avant que toutes les requêtes ne soient terminées |
cancelling / cancelled |
Vous avez demandé une annulation |
L'objet request_counts (total, completed, failed) vous donne une progression en temps réel tant que l'état est in_progress. Il n'y a pas de webhook à attendre ici, donc l'interrogation à un intervalle raisonnable (toutes les quelques minutes, pas chaque seconde) est le bon modèle. Vous pouvez également annuler une tâche en cours avec POST /v1/batches/{batch_id}/cancel si vous l'avez soumise par erreur.
Étape 4 : récupérer la sortie
Lorsque le status indique completed, l'objet lot contient un output_file_id. Téléchargez le contenu de ce fichier via l'API Files :
curl https://api.openai.com/v1/files/file-output456/content \
-H "Authorization: Bearer $OPENAI_API_KEY" > results.jsonl
La sortie est à nouveau au format JSONL, une ligne par requête. Chaque ligne reprend le custom_id que vous avez défini, plus un objet response contenant le code d'état et le corps. Toutes les requêtes ayant échoué apparaissent dans le fichier référencé par error_file_id, alors vérifiez les deux. Faites correspondre les résultats aux entrées sur le custom_id, et non sur l'ordre des lignes.
Tenez compte des compromis entre coût et fenêtre de temps
Le calcul est simple : vous économisez 50 % sur les jetons et vous acceptez un délai de traitement pouvant aller jusqu'à 24 heures. Pour un remplissage ponctuel ou une tâche nocturne, c'est un choix facile. Pour une fonctionnalité critique de votre produit, ce n'en est pas un.
Quelques notes pratiques :
- La réduction s'applique aux jetons d'entrée et de sortie, sur tous les modèles pris en charge.
- La fenêtre de 24 heures est un plafond, pas un objectif. Prévoyez le pire des cas ; si une tâche atteint l'état
expired, les requêtes terminées sont toujours facturées et renvoyées, et les autres ne le sont pas. - Les tâches par lots utilisent une limite de jetons en file d'attente distincte, de sorte qu'un grand lot n'empiétera pas sur les limites de taux dont dépend votre trafic en direct. Si vous atteignez déjà les plafonds, notre guide sur les limites de taux de l'API GPT et comment les tester couvre le côté synchrone.
- Les jetons à moitié prix s'accumulent tout de même en volume. Suivez les dépenses par tâche en utilisant l'étiquette
metadataafin de pouvoir attribuer les coûts ultérieurement ; voici un guide d'attribution des coûts pour les dépenses OpenAI.
Comment le tester dans Apidog
L'API de lot est plus sujette aux erreurs qu'un simple appel de chat, car les modes de défaillance sont répartis entre les fichiers, le formatage JSONL et une boucle d'interrogation. Une ligne mal formée dans un fichier de 50 000 requêtes fait échouer tout le téléchargement, et vous ne le saurez qu'une fois la validation effectuée. Tester les points d'accès du cycle de vie avant de les automatiser vous évite ce va-et-vient.
Apidog est une plateforme API où vous pouvez exécuter chaque étape comme une requête, les chaîner et faire des assertions sur les réponses. Elle teste et simule les points d'accès ; ce n'est pas un SDK OpenAI. Une configuration réaliste ressemble à ceci :
- Validez d'abord la forme du JSONL. Avant de télécharger quoi que ce soit, confirmez que chaque ligne contient
custom_id,method,urletbody, et quebody.modelet les messages sont présents. Détecter un champ manquant localement est moins coûteux qu'un lot échoué. - Exécutez le téléversement multipart. Envoyez
POST /v1/filesavecpurpose=batchet votre fichier, puis capturez l'idrenvoyé dans une variable d'environnement. - Créez le lot et faites des assertions sur l'objet. Déclenchez
POST /v1/batches, puis affirmez que lestatusestvalidatinget que l'endpointcorrespond à ce que vous avez envoyé. Les assertions visuelles d'Apidog vous permettent de vérifier ces champs sans écrire de scripts. - Interrogez et récupérez. Appelez
GET /v1/batches/{id}en boucle, faites une assertion lorsque lestatusdevientcompleted, puis extrayez l'output_file_idet téléchargez les résultats. - Exercez les chemins d'annulation et d'erreur. Soumettez un fichier délibérément corrompu et confirmez que vous obtenez un statut
failed, et testezPOST /v1/batches/{id}/cancelafin que votre gestion des erreurs soit réelle, et non supposée.
Comme le fichier de sortie arrive plus tard, vous pouvez également configurer une API simulée qui renvoie un échantillon d'objet de lot terminé et un fichier de résultats pré-enregistré. Cela vous permet de construire et de tester votre logique de récupération et d'analyse sans attendre une véritable tâche de 24 heures, et sans brûler de jetons pendant le développement. Lorsque votre équipe travaille d'abord sur les spécifications, vous pouvez également générer une collection de tests directement à partir d'une spécification OpenAPI et maintenir les points d'accès par lots sous couverture de régression en CI.
Foire aux questions
Combien de temps une tâche par lots prend-elle réellement ?
OpenAI s'engage à terminer un lot dans les 24 heures. En pratique, de nombreuses tâches se terminent plus rapidement, mais la garantie est le plafond de 24 heures, alors construisez votre système en conséquence. Si la fenêtre se ferme avec du travail inachevé, le lot passe à l'état expired et seules les requêtes terminées sont renvoyées et facturées.
Quelle est la véritable réduction, et est-elle cumulable ?
L'API de lot offre une réduction forfaitaire de 50 % par rapport aux points d'accès synchrones, sur les jetons d'entrée et de sortie. C'est le plus grand levier de coût unique qu'OpenAI offre pour les charges de travail hors ligne. Si vous essayez d'attribuer ces dépenses à des fonctionnalités ou des tâches, le guide d'attribution des coûts montre comment le découper.
Quels points d'accès puis-je exécuter dans un lot ?
Vous définissez la cible à la fois dans l'url JSONL et dans le champ endpoint du lot, et ils doivent correspondre. Les cibles prises en charge incluent /v1/chat/completions, /v1/responses, /v1/embeddings, /v1/completions et /v1/moderations, ainsi que les points d'accès pour les images et les vidéos. Vérifiez la documentation actuelle pour la liste complète, car OpenAI l'enrichit au fil du temps.
Pourquoi mes résultats sont-ils désordonnés ?
Ils ne sont pas ordonnés, par conception. La sortie JSONL ne préserve pas l'ordre des lignes d'entrée, c'est précisément pourquoi chaque requête nécessite un custom_id unique. Faites correspondre les résultats aux entrées en utilisant cet ID. Si deux lignes partagent un custom_id, vous ne pouvez pas distinguer leurs réponses de manière fiable.
Conclusion
Vous avez maintenant le flux complet : emballez vos invites dans un fichier JSONL, téléchargez-le, créez le lot, interrogez l'état et récupérez la sortie, le tout à la moitié du coût des jetons dans une fenêtre de 24 heures. Chaque étape renvoie un objet que vous pouvez vérifier, donc une fois que la forme JSONL et la boucle d'interrogation sont correctes, le reste est mécanique.
Avant de l'automatiser, exécutez le cycle de vie à la main. Téléchargez Apidog pour valider votre fichier de requêtes, exercer les points d'accès de téléchargement, de création, d'interrogation et d'annulation, et faire des assertions sur les champs de l'objet lot afin qu'une ligne mal formée ne vous coûte jamais un aller-retour de 24 heures.
