Septième article de la série « Production Engineering, Evals & Security avec Claude ».
Une application Claude peut être fiable et produire de bonnes réponses tout en restant impropre à la production pour deux raisons très simples :
elle coûte trop cher ou elle est trop lente.
Le module Production Engineering, Evals & Security insiste donc sur une règle fondamentale : on ne peut pas gérer un budget que l’on ne mesure pas. Il recommande d’instrumenter chaque appel afin de suivre au minimum les tokens, la latence et le taux d’erreur, puis d’optimiser le composant réellement responsable au lieu de deviner à partir de la facture finale.
Les principaux leviers sont :
model selection
prompt & context size
number of tool calls
streaming
batch processing
prompt caching
agent architecture
L’objectif n’est pas d’utiliser toutes ces optimisations.
L’objectif est de choisir le bon levier pour le bon problème.
1. Mesurer avant d’optimiser
Prenons deux requêtes.
Requête A
Input tokens: 1 200
Output tokens: 300
Latency: 700 ms
Tool calls: 0
Requête B
Input tokens: 18 000
Output tokens: 400
Latency: 3 800 ms
Tool calls: 4
Dire simplement :
« Claude coûte trop cher »
n’aide pas beaucoup.
Dans la deuxième requête, plusieurs causes sont immédiatement visibles :
large context
+
multiple tool calls
+
higher latency
Le module recommande donc d’instrumenter chaque appel, et non uniquement la facture mensuelle.
Une télémétrie minimale pourrait enregistrer :
{
"model": "...",
"input_tokens": 18240,
"output_tokens": 412,
"latency_ms": 3817,
"tool_calls": 4,
"status": "success"
}
Puis agréger ces données par :
feature
model
endpoint
customer
workflow
Les métriques essentielles
Le document met particulièrement en avant :
input tokens
output tokens
latency
error rate
Pour un agent, il devient également utile de suivre :
number of model calls
number of tool calls
number of subagents
Pourquoi ?
Parce qu’un workflow agentique peut transformer une seule requête utilisateur en :
1 request
→ 8 model calls
→ 12 tool calls
→ 4 subagents
Le coût visible par l’utilisateur est celui d’une requête.
Le coût réel est celui de toute l’exécution.
Le budget doit être défini avant l’architecture
Le module rattache cette question au design document.
Avant de construire le système, il recommande de définir :
per-request budget
monthly cost ceiling
latency target
minimum reliability
Par exemple :
P95 latency < 2 s
Cost/request < X
Success rate >= Y
Les nombres dépendent évidemment de l’application.
Le principe important est qu’ils doivent être définis avant de choisir une architecture complexe.
Sinon, on construit d’abord puis on découvre après coup :
« Notre orchestrator-worker est trois fois trop cher. »
Identifier le bon levier
Le cours regroupe les principaux leviers de coût et de latence autour de quelques causes mesurables.
| Cause | Levier possible |
|---|---|
| Modèle surdimensionné | Changer de modèle ou router |
| Prompt très long | Réduire le contexte |
| Préfixe répété | prompt caching |
| Trop d’appels tools | Simplifier le workflow |
| Utilisateur attend la réponse | streaming |
| Gros traitement non urgent | Message Batches API |
| Beaucoup de subagents | Revoir l’architecture |
Une bonne optimisation commence donc par :
measure
→ identify bottleneck
→ choose lever
→ re-evaluate
et non :
add caching everywhere
Prompt caching : éviter de retraiter le même préfixe
Avant de produire une réponse, Claude doit traiter les tokens qui composent l’input.
Si plusieurs requêtes commencent par le même contenu volumineux :
long system prompt
+
large tool definitions
+
stable reference material
ce travail peut être répété inutilement.
Le prompt caching permet de réutiliser le traitement associé à un préfixe stable.
Le document décrit le fonctionnement comme :
first request
→ cache write
later identical prefix
→ cache read
La documentation Anthropic actuelle confirme que le cache couvre le préfixe composé des tools, du system et des messages, jusqu’au point de cache concerné.
Exemple
Supposons une application qui envoie à chaque requête :
System prompt: 4 000 tokens
Tool schemas: 6 000 tokens
User request: 200 tokens
Sans cache :
request 1 → process 10 200 input tokens
request 2 → process 10 200
request 3 → process 10 200
...
Si les 10 000 premiers tokens sont stables :
request 1
→ cache creation
request 2
→ cache hit + new user message
request 3
→ cache hit + new user message
Le bénéfice augmente avec le nombre de réutilisations.
Qu’est-ce qu’un bon candidat au cache ?
Le cours cite notamment :
long system prompt
large stable tool schema
Pourquoi ?
Parce qu’ils réunissent trois propriétés :
long
+
stable
+
frequently reused
Un exemple typique :
tools schema = 8 000 tokens
qui est identique pour des centaines de requêtes.
Exact prefix match : le point crucial
Le cache fonctionne sur un préfixe identique.
Le module insiste sur ce détail : une modification avant le breakpoint peut provoquer un cache miss.
Par exemple :
Request A:
"You are a support assistant."
Request B:
"You are a helpful support assistant."
Même si ces prompts sont presque équivalents sémantiquement, ils ne constituent plus le même préfixe.
Donc :
stable bytes/tokens
→ cache hit possible
changed prefix
→ recomputation
Pour bénéficier du cache, il faut donc éviter de placer des données dynamiques avant la partie stable que l’on souhaite réutiliser.
TTL : combien de temps le cache reste-t-il utilisable ?
Le support fourni indique :
default TTL = 5 minutes
optional TTL = 1 hour
J’ai vérifié ce point dans la documentation Anthropic actuelle : le TTL par défaut reste bien 5 minutes, renouvelé lorsqu’une entrée est utilisée, et une durée 1 heure est également disponible avec un coût supplémentaire.
Conceptuellement :
same prefix reused every 30 seconds
→ good candidate
same prefix reused every 3 hours
→ default 5-minute cache not useful
Économie du cache : writes vs reads
Le document donne la logique économique suivante :
cache write
→ more expensive than normal input
cache read
→ much cheaper
Il indique comme multiplicateurs standard :
5 min write = 1.25× input price
1 h write = 2× input price
cache read = 0.1× input price
La documentation Anthropic actuelle confirme ces multiplicateurs standards, avec toutefois des exceptions selon certains modèles actuels.
C’est pourquoi :
many reads
+
few writes
→ caching pays
mais :
write
+
never reuse
→ caching can cost more
Exemple économique simplifié
Supposons 10 000 tokens de préfixe.
Sans cache, pour quatre requêtes :
10 000 × 4
=
40 000 input-token equivalents
Avec cache 5 minutes, en prenant les multiplicateurs standards :
write:
10 000 × 1.25
=
12 500
3 reads:
10 000 × 0.1 × 3
=
3 000
total:
15 500
On passe conceptuellement de :
40 000
à :
15 500
unités de coût d’input équivalentes.
Ce calcul est illustratif ; la facturation réelle dépend du modèle et de la tarification en vigueur.
Le piège du contenu dynamique
Supposons que vous mettiez dans votre system prompt :
Current stock price: ...
Current weather: ...
Current inventory: ...
Ces valeurs changent à chaque requête.
Vous créez alors potentiellement :
cache miss
cache miss
cache miss
Le cache est beaucoup plus adapté à :
stable instructions
stable tool definitions
stable reference documents
Le problème de la staleness
Le module souligne un deuxième risque : ce que vous réutilisez doit encore être correct.
Pour :
system prompt
tool schema
le problème est généralement limité, car ces éléments sont volontairement stables.
Pour :
live pricing
permissions
inventory
security policy updated minutes ago
il faut examiner beaucoup plus attentivement la cohérence temporelle.
Le cache est une optimisation.
Il ne doit pas transformer :
fresh data
en :
stale data
Mise en cache automatique ou breakpoints explicites
Le support décrit deux stratégies :
automatic caching
et :
explicit breakpoints
La documentation actuelle confirme ces deux modes. La mise en cache automatique se configure avec un cache_control au niveau supérieur ; avec des breakpoints explicites, on place cache_control sur des blocs spécifiques.
Le principe d’un breakpoint explicite :
[stable tools]
[stable system]
[stable reference] ← cache breakpoint [user-specific data]
La partie avant le breakpoint peut être réutilisée.
La partie dynamique reste traitée normalement.
Streaming : réduire la latence perçue
Le streaming ne réduit pas nécessairement le coût total de la génération.
Son intérêt principal est différent :
Faire apparaître la réponse au fur et à mesure au lieu d’attendre qu’elle soit entièrement générée.
Architecture non-streaming :
request
↓
wait...
wait...
wait...
↓
full answer
Avec streaming :
request
↓
first tokens
↓
more tokens
↓
more tokens
↓
complete answer
Pour une application interactive, le time-to-first-token peut donc compter davantage que le temps total.
Le support classe ainsi :
user-facing request
→ streaming
Streaming ne signifie pas « réponse terminée »
C’est un point fondamental lorsque Claude utilise des tools.
Un tool_use peut être streamé progressivement.
Les arguments arrivent sous forme de fragments :
input_json_delta
Le document donne l’idée suivante :
delta 1
+
delta 2
+
delta 3
+
...
→ complete JSON
La documentation actuelle confirme que les input_json_delta contiennent des fragments JSON partiels qui doivent être accumulés avant de reconstituer l’objet final.
Exemple
Claude souhaite produire :
{
"location": "Montpellier",
"unit": "celsius"
}
Le stream peut arriver sous une forme conceptuelle proche de :
{"loc
puis :
ation":"Mont
puis :
pellier","unit":"celsius"}
Exécuter le tool après le premier fragment serait évidemment incorrect.
Pattern correct avec tool streaming
Le support propose ce modèle mental :
tool_blocks = {}
for event in stream:
if event.type == "content_block_start":
# initialize accumulator
...
elif event.type == "content_block_delta":
if event.delta.type == "input_json_delta":
# append partial JSON
...
# once the block is complete:
tool_input = json.loads(accumulated_json)
execute_tool(tool_input)
La règle à retenir :
Ne jamais déclencher une action à partir d’un
tool_useincomplet.
Que faire si le stream casse ?
Le support indique qu’un stream interrompu en cours de réponse doit être traité comme un échec transitoire : il faut retenter la requête complète plutôt que transmettre une sortie partielle au composant suivant.
Le danger serait :
partial model output
↓
parser
↓
tool
↓
side effect
alors que le message n’était pas terminé.
Il faut maintenir une séparation nette entre :
partial data
et :
completed result safe to consume
Streaming et tool use : le piège d’examen
Supposons que vous receviez :
input_json_delta
contenant :
{"amount":
Que devez-vous faire ?
Pas :
execute tool
Mais :
accumulate
→ wait for block completion
→ parse
→ validate
→ execute
C’est un point très probable dans une question de scénario.
Message Batches API : échanger de la latence contre du coût
Toutes les requêtes n’ont pas besoin d’une réponse immédiate.
Exemples :
overnight classification
data backfill
large eval run
scheduled report
bulk extraction
Pour ces workloads, la Message Batches API permet de soumettre de nombreuses requêtes de manière asynchrone.
Le compromis est clair :
less immediate
+
cheaper
Quand utiliser Batch ?
Le support donne comme règle :
non-urgent
+
high volume
→ batch
Par exemple :
10 000 documents à classifier cette nuit
Le traitement peut être lancé sans utilisateur en attente.
Batch est alors particulièrement adapté.
Quand ne pas utiliser Batch ?
Pour :
user asks question
→ expects answer now
Batch est le mauvais outil.
C’est exactement l’inverse du streaming.
interactive request
→ streaming
offline asynchronous workload
→ batch
Le support formule explicitement ce contraste.
Réduction de coût actuelle
Le cours mentionne une réduction d’environ 50 %, tout en demandant de vérifier la valeur actuelle.
La documentation Anthropic actuelle confirme qu’en septembre 2026 la Message Batches API facture l’utilisation à 50 % du tarif standard de l’API.
Comme il s’agit d’une donnée tarifaire, elle doit être revérifiée au moment de la mise en production.
Batch et prompt caching peuvent se cumuler
Le support attire l’attention sur une optimisation particulièrement intéressante :
batch
+
prompt caching
Supposons une tâche nocturne :
100 000 documents
avec le même :
long system prompt
+
tool schema
pour chaque document.
Vous pouvez bénéficier simultanément de :
batch discount
et :
cached repeated prefix
La documentation Anthropic actuelle confirme que les multiplicateurs de prompt caching peuvent se cumuler avec la remise Batch.
Exemple de choix d’architecture
Cas 1 — chatbot interactif
Exigence :
user should see answer immediately
Choix :
stream=True
Le levier vise la latence perçue.
Cas 2 — classification nocturne
Exigence :
1 million records
no user waiting
minimize cost
Choix :
Message Batches API
Cas 3 — assistant utilisant un énorme tool schema
Exigence :
same 12 000-token prefix
repeated frequently
Choix :
prompt caching
Cas 4 — simple lookup dans une base stable
Exigence :
one fact
Choix :
smaller model
+
fetch once
plutôt que plusieurs agents et plusieurs rounds.
Plusieurs leviers peuvent être combinés
Une architecture n’est pas limitée à une optimisation.
Par exemple :
scheduled bulk classification
+
stable long system prompt
peut devenir :
small model
+
Message Batches API
+
prompt caching
C’est précisément une configuration proposée dans l’exercice du module.
À l’inverse :
interactive chat
peut utiliser :
appropriate model
+
prompt caching
+
streaming
si le contexte stable est réutilisé fréquemment.
Le piège : optimiser la latence avec Batch
Question :
Un utilisateur attend une réponse à l’écran. Quelle optimisation choisir ?
Pas :
Message Batches API
car elle est asynchrone.
Le support attend :
streaming
Le piège inverse : utiliser Streaming pour réduire le coût d’un traitement offline
Le streaming change surtout la manière dont les résultats arrivent.
Il ne constitue pas le levier principal pour réduire le coût d’un traitement de masse non urgent.
Dans ce cas :
Message Batches API
est l’outil adapté.
Observabilité et optimisation forment une boucle
L’approche complète est :
Instrument
↓
Measure
↓
Find bottleneck
↓
Choose one lever
↓
Change architecture
↓
Run evals
↓
Measure again
Il faut absolument conserver l’étape :
Run evals
car une optimisation de coût peut diminuer la qualité.
Exemple :
smaller model
→ -40% cost
→ -15% eval score
Ce n’est peut-être pas une optimisation acceptable.
Le reliability floor
Le document introduit un principe très important :
Réduire le coût sans passer sous le niveau minimum de fiabilité.
Le budget n’est donc pas :
minimize cost at all costs
mais :
minimize cost
subject to:
quality >= required level
reliability >= required level
latency <= target
Cela transforme l’optimisation en véritable problème d’ingénierie.
Et les agents ?
Le coût peut exploser très vite lorsque le travail est distribué entre plusieurs agents.
Chaque subagent possède :
its own calls
its own tokens
its own context
Le document rapporte notamment un cas de recherche Anthropic où un système multi-agent consommait environ 15 fois les tokens d’une interaction chat normale. Il précise cependant que ce coût n’est justifié que lorsque la tâche se décompose réellement en parties parallèles indépendantes.
Nous approfondirons cette architecture dans l’article suivant.
Tableau de décision rapide
| Besoin | Levier principal |
|---|---|
| Réduire le coût d’un workload simple | Modèle plus petit si l’eval tient |
| Réduire un contexte répété | Prompt caching |
| Améliorer la réponse perçue par l’utilisateur | Streaming |
| Gros traitement non urgent | Message Batches API |
| Réduire des appels inutiles | Simplifier tools/retrieval |
| Workload mixte | Routing |
| Travail réellement parallèle | Orchestrator-worker |
| Travail séquentiel dépendant | Single agent |
Ce qu’il faut retenir pour la certification
1. On mesure avant d’optimiser
Sur chaque appel :
input tokens
output tokens
latency
error rate
2. Prompt caching
Bon lorsque :
long
+
stable
+
frequently repeated prefix
À retenir :
exact prefix match
et non similarité sémantique.
Le cours et la documentation actuelle indiquent :
5-minute default TTL
1-hour option
3. Streaming
Bon lorsque :
user is waiting
Il améliore principalement la latence perçue.
Avec tool_use :
accumulate input_json_delta
→ wait for completion
→ parse
→ execute
4. Message Batches API
Bon lorsque :
high volume
+
non-urgent
La documentation actuelle confirme une réduction de 50 % par rapport aux tarifs API standards.
5. Batch et cache peuvent se combiner
batch discount
+
cached repeated prefix
peut être particulièrement efficace pour des jobs périodiques volumineux.
Pièges d’examen
Scénario : un utilisateur attend une réponse dans l’interface et vous souhaitez qu’elle paraisse plus immédiate.
→ Streaming.
Scénario : vous devez traiter 500 000 documents cette nuit et personne n’attend les réponses en temps réel.
→ Message Batches API.
Scénario : chaque requête réutilise un system prompt de 8 000 tokens et le même tool schema.
→ Prompt caching.
Scénario : le system prompt change à chaque requête.
→ Le cache risque d’avoir un mauvais hit rate.
Scénario : vous recevez un input_json_delta partiel pour un tool.
→ Ne pas exécuter le tool. Accumuler les fragments jusqu’à obtenir l’input complet.
Scénario : un job Batch réutilise un très long préfixe identique.
→ Batch + prompt caching peuvent être combinés.
Scénario : la facture augmente brutalement.
→ Ne pas appliquer une optimisation au hasard. Examiner d’abord les métriques par appel et identifier le levier responsable.
À retenir en une phrase
Optimiser Claude en production consiste à mesurer chaque appel puis à choisir le bon levier :
prompt cachingpour les préfixes stables répétés,streamingpour l’interactivité,Message Batches APIpour les traitements asynchrones volumineux, sans jamais sacrifier le niveau minimal de qualité et de fiabilité défini par les evals.

