Batch, compression de prompts et budget par requête
L'API Batch : moitié prix, mais pas tout de suite
L'API Batch de Gemini traite un lot de requêtes de façon asynchrone : vous soumettez, vous revenez chercher le résultat plus tard (l'objectif annoncé est 24 h, souvent beaucoup moins). En échange, le prix est divisé par deux (flash-lite : 0,15 par million de tokens d'entrée, relevé le 2026-10-15).
flowchart LR
subgraph TR["Temps réel"]
U["Client au chat"] --> A["generate_content : < 2 s, plein tarif"]
end
subgraph BA["Différé"]
N["Tâche de nuit : résumer 10 000 tickets"] --> J["batches.create : -50 %"]
J --> W["attente : minutes à heures"]
W --> RES["résultats"]
end
| Charge | Temps réel | Batch |
|---|---|---|
| Réponse au client dans le chat | oui | non |
| Classer les tickets de la veille | possible | oui |
| Générer des réponses types pour la FAQ | possible | oui |
| Évaluer un nouveau prompt sur 500 questions | possible | oui |
| Pré-remplir un cache sémantique | possible | oui |
job = client.batches.create(model=R.SMALL_MODEL, src=reqs, config={"display_name": "lab-perf-batch"})
while job.state.name not in ("JOB_STATE_SUCCEEDED", "JOB_STATE_FAILED", "JOB_STATE_CANCELLED",
"JOB_STATE_EXPIRED") and time.time() - t0 < 900:
time.sleep(20)
job = client.batches.get(name=job.name)
for r in job.dest.inlined_responses:
print(r.response.text)La compression de prompt : mesurer avant de couper
Chaque token d'entrée est payé à chaque requête. Deux familles de compression :
| Technique | Exemple | Risque |
|---|---|---|
| Compaction sans perte | retirer puces, titres, espaces | quasi nul |
| Sélection de contexte | n'envoyer que la section utile de la FAQ (via embeddings, c'est du RAG) | rater la section qui contenait la réponse |
| Compression apprise (LLMLingua et apparentés) | un petit modèle supprime les tokens peu informatifs | perte de sens, à évaluer |
variants = {
"FAQ complète (markdown)": R.SYSTEM,
"FAQ complète compactée": base + "\n" + compact(R.KB),
"Section « Livraison » seule": base + "\n" + sections(R.KB)["Livraison"],
}
for name, text in variants.items():
n = client.models.count_tokens(model=R.SMALL_MODEL, contents=text).total_tokensLa compaction de la FAQ fait gagner 4 % de tokens, la sélection de la seule section utile 74 %. Pourquoi ne pas toujours sélectionner ?
La sélection est un compromis qualité/coût : il faut l'évaluer sur le jeu de questions. Et un contexte qui change à chaque requête ne forme plus un préfixe stable, ce qui annule le cache de contexte. Elle réduit plutôt le TTFT.
Un budget par requête
Un budget par requête borne ce qu'une seule question peut coûter : max_output_tokens, nombre d'étapes d'un agent, et dans notre routeur, le droit d'escalader.
# Coût estimé du grand modèle : mêmes tokens, sortie doublée par prudence.
big_estimate = cost_usd(BIG_MODEL, small.prompt_tokens, small.cached_tokens, 2 * small.output_tokens)
if small.confidence < self.conf_min and small.cost + big_estimate <= self.max_cost:
big = await ask(self.client, BIG_MODEL, question)Avec MAX_COST_USD=0.01, une question de FAQ (environ 0,0004 en flash) passe largement. Le budget mord sur les cas anormaux : un prompt gonflé par un document de 200 000 tokens collé par l'utilisateur ne déclenchera pas, en plus, un appel au grand modèle.
Pourquoi le routeur estime-t-il le coût du grand modèle AVANT de l'appeler, au lieu de le mesurer après ?
La mesure après coup sert à la comptabilité et au suivi ; seule une estimation préalable permet de refuser une dépense. L'API renvoie bien l'usage du grand modèle, mais trop tard pour décider.
Exercice
Les 16 questions du banc coûtent 0,00683 $ en flash-lite temps réel. Estimez le coût du même lot en Batch, puis dites pour quelles questions de Lumen & Co le Batch serait acceptable.
Voir la solution
Le Batch divise par deux les prix d'entrée et de sortie : environ 0,0034 $ pour le lot (16 503 × 0,15 + 753 × 1,25, divisé par un million).
Acceptable : aucune des questions du chat (un client attend). En revanche, on peut utiliser le Batch pour pré-calculer les réponses aux 50 questions les plus fréquentes chaque nuit, à moitié prix, et les charger dans le cache sémantique : le jour, ces questions coûtent 0 en LLM. C'est le même modèle, moins cher, et plus rapide pour l'utilisateur.
Résultat obtenu
Exécutions réelles du 2026-10-15 :
$ python extras.py tokens
FAQ complète (markdown) 1014 tokens
FAQ complète compactée 972 tokens
Section « Livraison » seule 266 tokens
$ python extras.py batch
état=JOB_STATE_SUCCEEDED après 143 s
-> Oui, nous livrons en Belgique pour un montant de 12,00 €, avec un délai de 5 à 8 jours ouvrés (cette livraison n'est jam
-> Les ampoules LED sont garanties 3 ans, sur présentation de la facture.Le lot de 2 requêtes a été traité en 2 min 23 s : acceptable pour une tâche de nuit, rédhibitoire pour un chat.
Je sais faire
- Choisir entre temps réel et Batch selon l'urgence
- Soumettre un lot et récupérer ses résultats
- Mesurer un gain de compression avec
count_tokensavant de couper - Borner le coût d'une requête avant d'engager la dépense