Aller au contenu principal

Message Batches — des tâches asynchrones à -50 %

Intermédiaire
What you'll learn
  • Reconnaître les charges de travail où l'API Message Batches se rentabilise en une journée
  • Soumettre, interroger et récupérer les résultats d'un batch en flux — de bout en bout
  • Cumuler la remise batch avec la mise en cache des prompts sans casser ni l'une ni l'autre
  • Éviter les quatre fonctionnalités qui disqualifient silencieusement une requête du batching
  • Porter le même pattern vers OpenAI et Gemini — tous remisent le travail asynchrone de 50 %

La moitié de votre facture Anthropic n'a probablement pas besoin d'être synchrone. Les évaluations nocturnes, les rattrapages de données, les balayages de modération et la génération de contenu en masse ne se soucient pas de savoir si une réponse revient en 800 ms ou en 40 minutes — et Anthropic facture 50 % moins cher si vous acceptez ce compromis. L'API Message Batches est le moyen de le prendre.

Quand le batching se rentabilise​

Optez pour les batches quand toutes ces conditions sont vraies — un seul « non » et vous voudrez probablement l'API Messages classique à la place.

SignalLe batch convient quand…
LatenceVous pouvez attendre jusqu'à 24 heures. La plupart des batches terminent en moins d'une heure, mais le SLA est de 24.
VolumeVous avez au moins quelques centaines de requêtes à envoyer. L'API accepte jusqu'à 100 000 par batch.
InteractivitéPersonne ne regarde un indicateur de chargement. C'est du travail hors ligne.
Forme du résultatVous pouvez consommer un fichier de résultats JSONL — pas un flux de tokens en direct.

Les gains classiques :

  • Évaluations — noter 5 000 sorties de modèle contre une grille avant une mise en production.
  • Rattrapages — reclasser un jeu de données existant quand votre prompt change.
  • Génération en masse — descriptions produit, résumés, meta tags, traductions à l'échelle d'un catalogue.
  • Modération / étiquetage — balayer quotidiennement le contenu des utilisateurs de façon planifiée.
  • Données synthétiques — générer des paires d'entraînement pour un modèle plus petit en aval.

Les limites qui façonnent votre tâche​

LimiteValeur
Remise50 % sur les prix standard des tokens d'entrée et de sortie, sur tous les modèles pris en charge.
Taille du batch100 000 requêtes ou 256 Mo, selon ce qui est atteint en premier.
Délai de traitementLa plupart en moins d'une heure ; expiration stricte à 24 heures — tout ce qui n'est pas traité après 24 h renvoie expired.
Conservation des résultats29 jours après la création du batch, puis les résultats deviennent indisponibles (les métadonnées du batch restent).
Modèles pris en chargeTous les modèles Claude actifs — Fable 5, Mythos 5, Opus 5, Opus 4.x, Sonnet 5, Sonnet 4.x, Haiku 4.5.
PortéePar Workspace. Une clé du Workspace A ne peut pas voir les batches du Workspace B.
Plafond de dépenseLes batches peuvent légèrement dépasser le plafond de dépense configuré sur votre workspace à cause du traitement concurrent.

La boucle en trois étapes​

Chaque tâche par batch suit la même forme — créer, interroger, récupérer les résultats en flux.

Guided walkthrough1 of 3
  1. POST /v1/messages/batches avec un tableau requests. Chaque élément a un custom_id unique (votre clé de jointure vers vos données) plus un bloc params qui ressemble exactement à un appel Messages classique. L'API renvoie un id de batch et un processing_status à in_progress.

Créer un batch (cURL)​

Le batch minimal viable — deux appels Opus 5, chacun étiqueté pour que vous puissiez rejoindre les résultats à vos lignes sources.

POST /v1/messages/batches

curl https://api.anthropic.com/v1/messages/batches \
--header "x-api-key: $ANTHROPIC_API_KEY" \
--header "anthropic-version: 2023-06-01" \
--header "content-type: application/json" \
--data '{
  "requests": [
    {
      "custom_id": "row-00001",
      "params": {
        "model": "claude-opus-5",
        "max_tokens": 1024,
        "messages": [
          {"role": "user", "content": "Summarize: ..."}
        ]
      }
    },
    {
      "custom_id": "row-00002",
      "params": {
        "model": "claude-opus-5",
        "max_tokens": 1024,
        "messages": [
          {"role": "user", "content": "Summarize: ..."}
        ]
      }
    }
  ]
}'

custom_id doit correspondre à ^[a-zA-Z0-9_-]{1,64}$ et être unique au sein du batch. Traitez-le comme votre clé étrangère — la plupart des gens le fixent à l'id de leur ligne ou à un hash de l'entrée pour que les résultats se recollent proprement.

Interroger le statut (Python)​

Attendre la fin du batch

import time, anthropic

client = anthropic.Anthropic()
batch_id = "msgbatch_..."

while True:
  batch = client.messages.batches.retrieve(batch_id)
  if batch.processing_status == "ended":
      break
  print(batch.request_counts)  # live progress
  time.sleep(60)

Lire les résultats en flux et traiter chaque type​

Chaque requête retombe dans l'une de quatre catégories. Vous n'êtes facturé que pour succeeded — les erreurs, annulations et expirations sont gratuites.

Type de résultatCe que ça signifieAction
succeededUn Message est revenu.Fusionner sur custom_id.
erroredRequête invalide ou erreur serveur transitoire.Corriger et resoumettre pour invalid_request_error ; réessayer directement pour les erreurs serveur.
canceledVous avez annulé le batch avant que celle-ci ne s'exécute.Resoumettre si toujours nécessaire.
expiredLa fenêtre de 24 heures s'est écoulée avant l'exécution de cette requête.Resoumettre — signe habituel que le batch était trop gros ou que la plateforme était chargée.

Lire les résultats en flux (Python)

for r in client.messages.batches.results(batch_id):
  match r.result.type:
      case "succeeded":
          save(r.custom_id, r.result.message)
      case "errored":
          if r.result.error.error.type == "invalid_request_error":
              log_bad_row(r.custom_id, r.result.error)
          else:
              retry_queue.append(r.custom_id)
      case "expired":
          retry_queue.append(r.custom_id)

NE téléchargez PAS tout le fichier de résultats avec un naïf requests.get(...).text — pour les gros batches, cela épuisera la RAM. Les helpers du SDK itèrent déjà ligne par ligne ; l'équivalent cURL consiste à envoyer la réponse dans jq -c plutôt que de la matérialiser.

Effet cumulé : empiler le batching et la mise en cache des prompts​

La remise se cumule avec la mise en cache des prompts, et c'est là que l'économie devient absurde. Un cache hit coûte 10 % du prix d'entrée ; le batching divise ensuite ce montant par deux. Sur une grosse évaluation où chaque requête partage le même prompt système et la même grille de 20 000 tokens, la ligne d'entrée tombe à 5 % du tarif affiché — une réduction d'un facteur 20.

Deux choses à savoir :

  1. Utilisez la durée de cache d'une heure. Le TTL par défaut de 5 minutes expirera typiquement avant qu'un gros batch ne l'ait traversé. La documentation d'Anthropic recommande elle-même le cache d'une heure spécifiquement pour le batching.
  2. max_tokens: 0 (préchauffage du cache) n'est pas autorisé dans un batch — une entrée éphémère écrite pendant le traitement du batch expirerait avant l'exécution de la requête suivante, donc la plateforme la rejette d'emblée.

La bonne forme : préchauffez le cache avec un unique appel Messages classique, attendez son écriture, puis lancez le batch qui réutilise ce préfixe de cache pendant l'heure qui suit.

Ce que vous pouvez mettre dans un batch — et ce que vous ne pouvez pas​

Oui, batchable : la vision, tous les outils serveur (recherche web, web fetch, exécution de code, connecteurs MCP, advisor, recherche d'outils), les messages système, le multi-tour, la réflexion étendue, la plupart des fonctionnalités bêta. Si ça marche dans l'API Messages classique, ça marche presque certainement dans un batch.

Non, rejeté à la validation :

ParamètrePourquoi c'est bloqué
stream: trueLes résultats reviennent sous forme de fichier, pas de flux en direct.
speed (mode Fast)Le mode Fast règle la latence synchrone — sans objet en asynchrone.
store / previous_thread_event_id (Threads)Les Threads sont à état ; les batches non.
cache_hint / context_hintLes indices de routage n'affectent que l'ordonnancement synchrone.
max_tokens: 0Écrirait une entrée de cache qui expire avant que vous ne l'utilisiez.
research_preview_2026_02: "active"Le mode research preview n'est pas sur le chemin batch.

La validation s'exécute de façon asynchrone, donc une requête malformée ne remonte qu'à la fin de tout le batch. Avant de soumettre 50 000 requêtes, envoyez-en une via l'API Messages simple pour vérifier que la forme valide.

Le même pattern chez tous les fournisseurs​

Les tarifs batch ont convergé. Les trois grands fournisseurs frontière proposent désormais la même forme affichée — 50 % de remise, SLA ~24 h, JSONL en entrée et en sortie — ce qui en fait un pattern réellement portable plutôt qu'une astuce propre à Claude.

FournisseurRemiseSLASoumissionRéférences croisées
Anthropic — Message Batches50 % sur entrée+sortieLa plupart < 1 h, expiration stricte 24 hCorps JSON (requests[]), max 100k / 256 MoDocumentation
OpenAI — Batch API50 % sur entrée+sortieLa plupart 1–6 h, SLA 24 hUpload de fichier JSONL, jusqu'à 50k requêtes par batchDocumentation
Google — Gemini Batch API50 % sur entrée+sortieLa plupart < SLA 24 hTâche batch en ligne ou adossée à GCS ; mise en cache du contexte prise en chargeDocumentation

L'architecture transférable : un petit « job runner » qui lit une table source, découpe les lignes en batches de 10 000, soumet par fournisseur, interroge, et fusionne les résultats par votre custom_id. Seuls les appels de soumission / interrogation / résultats diffèrent — le reste de votre pipeline est agnostique du fournisseur. Voir Traduction de prompts entre IA pour la même idée appliquée au prompt lui-même.

Erreurs fréquentes​

  • Batcher du trafic interactif. Un utilisateur est sur la page — même une attente de 60 secondes est un produit cassé. Les batches sont pour le travail hors ligne et planifié.
  • Batcher des tâches minuscules. 20 requêtes ne valent pas la boucle d'interrogation et le plafond de 24 heures. En dessous de quelques centaines de requêtes, utilisez simplement l'API Messages classique avec de la concurrence.
  • Bloquer sur tout le batch alors que vous pourriez lire en flux. Télécharger l'intégralité du fichier JSONL en mémoire marche pour 50 lignes et provoque un OOM pour 50 000. Itérez.
  • Ignorer les résultats expired. Ils sont gratuits, mais c'est du travail inachevé. Suivez-les et remettez-les en file — sinon votre pipeline perd silencieusement des lignes pendant les périodes de forte demande.
  • Supposer que la validation est synchrone. Une mauvaise requête dans une ligne n'échoue pas immédiatement ; elle revient à la fin avec les autres. Testez d'abord une ligne via l'API Messages simple.
  • Perdre la clé de jointure. Les batches terminent dans le désordre et le fichier de résultats n'est pas trié selon l'ordre d'entrée. Si vous ne définissez pas un custom_id significatif, vous ne pouvez pas fusionner de façon fiable les résultats avec vos données sources.
  • Oublier la conservation de 29 jours. Passé ce délai, results_url ne renvoie plus rien. Téléchargez et persistez les résultats dans votre propre stockage dans le cadre du pipeline.
L'essentiel
Appuyez sur Entrée ou Espace pour retourner la carte. Utilisez les flèches gauche et droite pour naviguer entre les cartes.Terme affiché.
1 / 8

Vérifiez vos acquis

0/4
  1. Quelle charge de travail convient MAL à l'API Batches ?
  2. Vous avez batché 10 000 requêtes. 9 200 ont réussi, 500 ont échoué, 200 ont été annulées, 100 ont expiré. Combien en payez-vous ?
  3. Vous voulez réutiliser un énorme prompt système sur un batch de 40 000 requêtes. Quel TTL de cache utiliser ?
  4. Le fichier de résultats de votre batch pour une grosse tâche pèse 400 Mo. Quelle est la bonne manière de le consommer ?
Key takeaways
  • Le batching est le plus gros levier sur la dépense Anthropic pour les charges hors ligne — 50 % de remise, aucune réécriture de prompt nécessaire.
  • Le compromis porte sur la latence et l'interactivité, pas sur la qualité. Même modèle, même forme de sortie, mêmes fonctionnalités.
  • Cumulez-le avec la mise en cache des prompts et le TTL d'une heure pour la vraie économie — 5 % du tarif d'entrée affiché est atteignable sur des charges à préfixe partagé.
  • Définissez toujours un custom_id significatif ; lisez toujours le fichier de résultats en flux ; remettez toujours en file les lignes expirées.
  • Le pattern se porte : OpenAI et Gemini remisent tous deux le travail asynchrone de 50 % avec un SLA de ~24 h — construisez un seul job runner, routez entre fournisseurs.

Pour aller plus loin​