Aller au contenu
Formation Claude

Tapez au moins deux lettres.

Commencer

Coût, cache et performance

Comprendre la facture, la diviser par dix avec la mise en cache, traiter en lot, choisir le bon effort, et mesurer au lieu de supposer.

10 min de lecturePartie 6 — L’API et les agentsTechnique

À la fin de ce chapitre, vous saurez

  • Décomposer une facture et savoir où part réellement l’argent
  • Mettre en cache correctement, et diagnostiquer un cache qui ne prend pas
  • Choisir entre appel direct et traitement par lot
  • Mesurer un coût avant de déployer plutôt qu’après
Dans ce chapitre
  1. D’où vient la facture
  2. La mise en cache
  3. Le principe
  4. L’invariant qui explique tout
  5. Les instructions en cours de conversation
  6. Le seuil minimal
  7. L’arithmétique
  8. Le traitement par lot
  9. L’effort, et le résultat contre-intuitif
  10. Choisir le modèle par le coût
  11. Ce qu’il faut retenir

Un projet fondé sur l’API se juge sur trois axes : la qualité, la latence et le coût. Les deux premiers se voient tout de suite. Le troisième se découvre à la première facture, et c’est souvent trop tard pour reconcevoir.

Ce chapitre donne les mécanismes et l’ordre dans lequel les appliquer.

D’où vient la facture

Deux compteurs, avec des prix différents.

Les jetons d’entrée — tout ce que le modèle lit : instruction système, historique, documents, résultats d’outils.

Les jetons de sortie — tout ce qu’il écrit, réflexion comprise. Facturés plusieurs fois plus cher que l’entrée.

Trois conséquences qu’on sous-estime systématiquement.

Une conversation coûte de plus en plus cher à chaque tour. L’API est sans état : au vingtième message, vous payez la relecture des dix-neuf précédents. Le coût d’une conversation croît en carré de sa longueur.

La réflexion approfondie est de la sortie. Elle est facturée au tarif de sortie, même si vous n’en affichez pas le contenu.

Les résultats d’outils sont de l’entrée, et ils s’accumulent. Une recherche web qui ramène quarante mille jetons les fait payer à chaque tour suivant de la même conversation.

La mise en cache

C’est le levier principal, et de très loin. Bien utilisée, elle divise le coût d’entrée par dix sur la partie stable de vos requêtes.

Le principe

Le cache fonctionne par appariement de préfixe exact. Vous marquez un point de coupure ; tout ce qui précède est mis en cache. À l’appel suivant, si les octets sont identiques jusqu’à ce point, la partie cachée est facturée à environ un dixième du prix.

L’ordre de rendu est : tools, puis system, puis messages. Un marqueur sur le dernier bloc système met donc en cache les outils et l’instruction système.

python
reponse = client.messages.create(
    model="claude-opus-5",
    max_tokens=4096,
    system=[
        {
            "type": "text",
            "text": INSTRUCTION_LONGUE_ET_STABLE,
            "cache_control": {"type": "ephemeral"},
        }
    ],
    messages=[{"role": "user", "content": question_variable}],
)

print(reponse.usage.cache_creation_input_tokens)  # écrits dans le cache
print(reponse.usage.cache_read_input_tokens)      # lus depuis le cache
print(reponse.usage.input_tokens)                 # payés plein tarif

L’invariant qui explique tout

Un seul octet différent dans le préfixe invalide tout ce qui suit.

Cela suffit à expliquer la quasi-totalité des caches qui ne prennent pas.

Ce qui casse le cachePourquoi
Une date ou une heure dans l’instruction systèmeChange à chaque requête
Un identifiant de session ou de requête en têteIdem
json.dumps(d) sans sort_keys=TrueL’ordre des clés varie
Une liste d’outils construite dynamiquementL’ordre change
Un nom d’utilisateur dans l’instruction systèmePréfixe par utilisateur, aucun partage
Un changement de modèleLes caches sont propres à un modèle

Le diagnostic est immédiat : si cache_read_input_tokens reste à zéro sur des requêtes au préfixe théoriquement identique, il y a un invalidateur. Comparez les octets réellement envoyés entre deux requêtes.

Les instructions en cours de conversation

Cas fréquent : vous voulez ajouter une consigne au milieu d’une conversation — changement de mode, contexte nouveau. Modifier l’instruction système invalide tout l’historique cché.

Sur les modèles qui le prennent en charge, un message de rôle system peut être ajouté dans la liste des messages, après l’historique. Le préfixe caché reste intact, et l’instruction porte l’autorité d’une consigne d’opérateur plutôt que d’un message utilisateur.

python
messages = [
    *historique,
    {"role": "user", "content": message_utilisateur},
    {"role": "system", "content": "Mode concis : réponses de moins de 40 mots."},
]

Le seuil minimal

Un préfixe trop court n’est pas mis en cache, sans erreur ni avertissement : cache_creation_input_tokens reste simplement à zéro. Le seuil varie selon les modèles — quelques centaines à quelques milliers de jetons. Vérifiez avec le compteur d’usage plutôt que de supposer.

L’arithmétique

Une écriture en cache coûte un peu plus cher qu’une lecture normale ; une lecture coûte environ un dixième. Le seuil de rentabilité se situe donc à partir de la deuxième requête avec une durée de vie courte.

Autrement dit : dès que deux requêtes partagent un préfixe substantiel, la mise en cache est rentable. Ce n’est pas une optimisation avancée, c’est un réglage par défaut.

Le traitement par lot

Pour tout ce qui n’a pas besoin d’une réponse immédiate, l’API de lots divise le coût par deux.

python
lot = client.messages.batches.create(
    requests=[
        {
            "custom_id": f"ticket-{t.id}",
            "params": {
                "model": "claude-opus-5",
                "max_tokens": 1024,
                "system": SYSTEME,          # partagé, donc cachable
                "messages": [{"role": "user", "content": t.texte}],
            },
        }
        for t in tickets
    ]
)

On interroge ensuite le lot jusqu’à ce que son traitement soit terminé, puis on parcourt les résultats. Trois points pratiques.

Les résultats arrivent dans un ordre quelconque. Indexez par custom_id, jamais par position. C’est la source de bug la plus fréquente.

Chaque résultat a son propre statut. Réussite, erreur, annulation, expiration : traitez les quatre.

Le lot se combine avec le cache. Une instruction système partagée par mille requêtes est mise en cache, et l’ensemble bénéficie en plus de la remise de lot.

Bon pour : classification nocturne, analyse de corpus, réindexation, enrichissement de base, évaluations. Inutilisable pour : toute interface où quelqu’un attend.

L’effort, et le résultat contre-intuitif

Le réglage d’effort du chapitre 2 a un impact direct sur la facture, et il ne va pas dans le sens qu’on croit.

Sur une tâche courte, un effort élevé consomme plus pour un résultat identique. Baissez.

Sur une tâche longue et agentique, un effort élevé coûte souvent moins cher. Un modèle qui réfléchit mieux au départ enchaîne moins d’allers-retours ; un modèle qui bâcle recommence trois fois — et chaque reprise fait relire tout l’historique.

Il existe par ailleurs un mécanisme de budget de tâche : on annonce au modèle une enveloppe de jetons pour une boucle entière, et il s’en sert pour se répartir le travail et conclure proprement plutôt que d’être coupé net. À ne pas confondre avec max_tokens, qui est un plafond dur dont le modèle n’a pas conscience.

Choisir le modèle par le coût

Le chapitre 2 donnait la règle qualitative. Voici son pendant économique.

Le modèle rapide pour les tâches mécaniques en volume : classification, extraction, étiquetage, reformulation. Sur des dizaines de milliers d’appels, l’écart de facture est considérable.

Le modèle intermédiaire pour la majorité du travail applicatif.

Le modèle le plus capable pour ce qui le mérite : raisonnement long, agents autonomes, cas où une erreur coûte plus cher que l’appel.

Le mélange est souvent la bonne réponse : un modèle rapide pour trier et pré-filtrer, un modèle capable sur les seuls cas retenus. Attention cependant à la conséquence sur le cache : changer de modèle en cours de conversation invalide le cache. Faites le tri dans un appel séparé plutôt qu’au milieu d’une session.

Un assistant documentaire, du prototype au budget tenable

La situation

Un assistant qui répond sur une documentation interne de 400 pages. Le prototype fonctionne. La projection à mille questions par jour donne un coût mensuel inacceptable.

La décomposition

Chaque appel envoie : l’instruction système (2 000 jetons), la documentation pertinente (30 000 jetons), la question (100 jetons). Soit 32 100 jetons d’entrée par question, mille fois par jour.

Correction 1 — mettre en cache ce qui est stable

L’instruction système et le socle documentaire commun ne changent jamais. Ils passent en tête, avec un point de coupure :

python
system=[
    {"type": "text", "text": INSTRUCTION},
    {"type": "text", "text": SOCLE_DOCUMENTAIRE,
     "cache_control": {"type": "ephemeral"}},
]

Vérification immédiate : cache_read_input_tokens doit devenir non nul à partir du deuxième appel.

Correction 2 — trouver l’invalidateur

Il reste à zéro. L’instruction système contenait f"Date du jour : {date.today()}". Un octet par jour, mais surtout : la date était avant le socle documentaire, donc elle invalidait tout.

La date part dans le message utilisateur. Le cache prend.

Correction 3 — ne pas tout envoyer

Envoyer 400 pages pour répondre à une question sur une seule est absurde, et le chapitre 3 rappelle que la qualité en souffre aussi. Un pré-filtrage sélectionne les sections pertinentes.

Le socle commun reste caché ; seules les sections spécifiques varient.

Correction 4 — le bon modèle pour la bonne étape

Le pré-filtrage — « quelles sections concernent cette question ? » — est une tâche de classification. Elle passe sur le modèle rapide, dans un appel séparé pour ne pas casser le cache de l’appel principal.

Le résultat

Le coût par question s’effondre : la majeure partie de l’entrée est lue en cache, le reste a été réduit, et l’étape mécanique tourne sur un modèle bon marché. Le projet devient viable — et la qualité s’améliore, parce que le contexte est mieux ciblé.

Ce qu’il faut retenir de cet exemple

Aucune des quatre corrections n’est une astuce : ce sont des décisions d’architecture. Elles se prennent bien mieux avant le déploiement qu’après la facture.

Ce qu’il faut retenir

Vérifier que c’est passé

3 questions. Rien n’est enregistré, rien n’est envoyé : c’est pour vous.

Question 1

Votre taux de lecture en cache est nul malgré un préfixe identique. Cause la plus probable ?

Voir la réponse

C — Quelque chose varie dans le préfixe : un horodatage, un identifiant, une sérialisation JSON non ordonnée, un outil qui change

Le cache est un appariement de préfixe exact : un seul octet différent invalide tout ce qui suit. Les coupables habituels sont une date insérée dans l’instruction système, un identifiant de requête, un dictionnaire sérialisé sans tri, ou une liste d’outils construite dynamiquement.

Question 2

Quand le traitement par lot est-il le bon choix ?

Voir la réponse

A — Quand la latence n’a pas d’importance : il coûte deux fois moins cher mais la réponse n’est pas immédiate

Le lot divise le coût par deux, contre un délai qui se compte en minutes ou en heures. C’est excellent pour un traitement nocturne, une réindexation, une analyse de corpus. C’est inutilisable pour une interface interactive.

Question 3

Sur une longue session agentique, un effort élevé coûte-t-il plus cher ?

Voir la réponse

A — Souvent moins : mieux réfléchir au départ évite des allers-retours qui coûtent chacun l’historique complet

C’est le résultat contre-intuitif de ce chapitre. Sur une tâche courte, l’effort élevé coûte plus pour rien. Sur une boucle agentique, un modèle qui bâcle sa première approche recommence trois fois, et chaque reprise fait relire tout l’historique.

Le calcul avant le déploiement

Prenez un usage que vous envisagez. Comptez les jetons d’un appel typique avec l’endpoint de comptage, pas à l’estimation. Multipliez par le volume quotidien attendu, puis par trente. Refaites le calcul en supposant 90 % de lecture en cache sur la partie stable. L’écart entre les deux chiffres vous dira si la mise en cache est un confort ou une condition de viabilité.

Un indice, si vous bloquez

Comptez aussi la sortie. Sur un usage conversationnel, elle représente souvent une part de la facture supérieure à ce qu’on imagine, parce qu’elle est facturée plus cher que l’entrée.