J'ai mesuré ma dépense en tokens, puis je me suis trompé de conclusion
TL;DR
- J'ai mesuré 14 jours de mes propres sessions d'agent de code IA. 97,3 % des tokens d'entrée étaient le même contexte renvoyé tour après tour, et 33 sessions sur 682 représentaient 86,8 % du coût modélisé.
- J'en ai conclu qu'il fallait terminer les sessions plus tôt. Belle histoire, en grande partie fausse : les deux plus grosses sessions contenaient 54 % de tous les tours, donc elles coûtaient le plus parce qu'elles contenaient la moitié du travail, pas parce que leur contexte était pathologique.
- Terminer les sessions plus tôt rapporte environ 20-25 % par tour, pas 86,8 %, et démarrer une nouvelle session a son propre coût.
- La sortie, c'est 0,3 % des tokens mais ~12 % du coût, parce qu'elle est facturée ~50× le prix d'une lecture de cache. Je l'avais qualifiée d'erreur d'arrondi.
- Mes erreurs : j'ai pris l'endroit où la dépense se concentrait pour du gaspillage et pour ce que je pouvais économiser, puis j'ai recommandé le correctif avant de calculer à partir de quand il est rentable.
Tokens, contexte et cache en deux minutes
Un tour, c'est un aller-retour avec le modèle, en pratique un appel d'API : l'agent envoie ce que le modèle doit voir, le modèle renvoie une réponse. Tout se compte en tokens, les morceaux de texte qu'un modèle lit et écrit, et se facture au token.
Ce que l'agent envoie à chaque tour, c'est le contexte : les instructions fixes avec lesquelles il démarre (le préambule), plus tout ce que la conversation a accumulé depuis, réponses, fichiers lus et résultats d'outils compris. Le contexte entier est renvoyé à chaque tour, et repayé, et il grossit au fil de la session.
flowchart LR
C["Contexte accumulé : préambule, messages, fichiers, résultats d'outils"] -->|"renvoyé à chaque tour"| M["Modèle"]
M -->|"tokens de sortie"| R["Réponse"]
R -->|"ajoutée au contexte"| C
Une session, c'est une conversation avec l'agent. Démarrer une nouvelle session repart du préambule, avec un contexte plus petit qu'il faut réécrire dans le cache.
L'essentiel du contexte d'un tour est identique à celui du tour précédent, et le fournisseur le sert depuis un cache. Les tokens d'entrée sont de trois sortes :
- Lectures de cache : du contexte renvoyé depuis le cache.
- Écritures de cache : du contenu stocké dans le cache, comme au démarrage d'une nouvelle session.
- Entrée hors cache : de l'entrée qui n'est ni lue depuis le cache, ni écrite dedans.
La sortie, c'est ce que le modèle écrit en retour. Les prix sont des multiples du prix d'entrée de base. Les ratios que j'utilise, mettez les vôtres :
| Type de token | Prix | Par rapport à une lecture de cache |
|---|---|---|
| Lecture de cache | 0,1× l'entrée de base | |
| Écriture de cache | 1,25× l'entrée de base | ~12,5× |
| Sortie | 5× l'entrée de base | ~50× |
Donc la sortie est facturée ~50× le prix d'une lecture de cache, et ça compte, comme on va le voir.
Ce qu'ont montré 14 jours de mes transcripts
Base de facturation, puisque ça change ce que "coût" veut dire : je suis sur un abonnement, donc rien de tout ça ne produit de facture. Chaque chiffre de coût ici est modélisé au prix catalogue de l'API, ce qui est à mon avis le bon angle de toute façon, c'est ce que le même travail coûterait sur l'API.
Fenêtre de 14 jours, mes propres transcripts locaux (les logs que l'agent garde de chaque session), 682 sessions :
| Mesure | Valeur |
|---|---|
| Tokens d'entrée qui sont des lectures de cache | 97,3 % |
| Contexte moyen repayé à chaque tour | 241 517 tokens |
| Sessions avec un pic de contexte au-dessus de 300k | 33 sessions = 86,8 % du coût |
| Les deux plus grosses sessions (19 538 et 9 533 tours) | 60 % du total |
| Tokens de sortie, toute la fenêtre | 37,5 M |
| Lectures de cache, toute la fenêtre | 13,1 Md |
97,3 % de l'entrée n'est pas du contenu nouveau. C'est le même contexte, renvoyé, tour après tour. (Le pic de contexte, c'est le plus gros contexte qu'une session a atteint.)
La conclusion que j'en ai tirée : terminer les sessions plus tôt
La sortie représente 0,29 % de tous les tokens. Les lectures de cache, 97,3 %. Donc la facture, c'est du contexte repayé, une poignée de sessions la dominent, et le levier est évident : terminer les sessions plus tôt, ne pas laisser le contexte s'accumuler, et tout outil qui promet de compresser la sortie court après une erreur d'arrondi. J'en ai conclu que le correctif, c'était l'hygiène de session : terminer la session quand le sujet change.
Belle histoire. En grande partie fausse.
La mesure mérite quand même d'être publiée. L'erreur aussi, parce que c'est le genre d'erreur qui passe la relecture par les pairs en ayant l'air évidemment juste.
La division qui fait tout tomber
Puis quelqu'un a fait une division que je n'avais pas faite, et la conclusion s'est écroulée.
Les deux grosses sessions contiennent la moitié des tours
Nombre total de tours qu'impliquent mes propres chiffres : 13,1 Md de lectures de cache ÷ 241 517 tokens de contexte moyen = ~54 240 tours.
Les deux sessions marathon, c'est 19 538 + 9 533 = 29 071 tours. Soit 53,6 % de tous les tours de la fenêtre.
| Les deux sessions marathon | Tout le reste | |
|---|---|---|
| Tours | 29 071 | 25 169 |
| Lectures de cache | 7,86 Md | 5,24 Md |
| Contexte moyen déduit par tour | 7,86 Md ÷ 29 071 = ~270k | 5,24 Md ÷ 25 169 = ~208k |
Elles représentent 60 % du coût et contiennent 54 % du travail. Ce qui veut dire qu'elles sont à peine plus chères par tour que tout le reste.
Ce que terminer une session change vraiment
Donc, la version honnête :
- Ces sessions ne dominent pas parce que leur contexte est pathologique. Elles dominent parce qu'elles contiennent la moitié du travail.
- "Terminer la session" fait passer le contexte par tour de ~270k à ~208k. C'est environ 20-25 % par tour, pas 86,8 %.
- Les tours ne disparaissent pas quand on coupe la session en deux. Le travail reste à faire. On repaie un contexte plus petit à chaque fois, c'est tout.
20-25 %, ça reste réel, et je le prendrais quand même. Mais c'est une optimisation ordinaire, pas la découverte spectaculaire que je croyais tenir. Le chiffre de 86,8 % décrit où la dépense se concentre, et je l'ai lu comme ce qu'on peut récupérer. Ce n'est pas la même quantité, et rien dans les données ne reliait les deux.
Le pic de contexte n'est pas le contexte moyen
J'ai aussi écrit que ces sessions étaient "collées juste sous le plafond de 1M", le maximum de contexte qu'une session peut contenir. Une moyenne déduite de ~270k dit le contraire. Le pic de contexte et le contexte moyen sont deux chiffres différents, et je les ai confondus.
Le correctif n'est pas gratuit non plus
Démarrer une nouvelle session réécrit le préambule et reconstruit le contexte au tarif d'écriture de cache, ~12,5× le prix d'une lecture de cache.
Les 2,7 % restants des tokens d'entrée, que j'avais balayés comme du bruit, ce sont les écritures de cache plus l'entrée hors cache. Sur 13,46 Md de tokens d'entrée, 2,7 %, c'est ~363 M de tokens à 12,5× le tarif de lecture, ce qui tombe quelque part entre un quart et un tiers du coût des lectures de cache. Pas du bruit.
Donc "terminer la session" a un seuil de rentabilité : en dessous d'un certain contexte accumulé, couper coûte plus en cache reconstruit que ça n'économise en contexte relu. Je n'ai pas calculé le mien. Il se calcule à partir de données déjà sur mon disque, et j'aurais dû le faire avant de recommander cette pratique à qui que ce soit.
La concentration n'est pas du gaspillage
Le plus gros trou, et celui que j'aimerais qu'on me signale si on relisait mon travail.
86,8 % de la dépense concentrée dans 4,8 % des sessions, ce n'est un problème que si ces sessions ne produisaient pas 86,8 % de la valeur. Elles contenaient 54 % de tous les tours. C'est là que plus de la moitié du travail s'est fait.
Je n'ai jamais séparé "concentré" et "gaspillé". Toute la prescription part du principe que c'est la même chose. C'est peut-être le cas. Les longues sessions dérivent bel et bien, traînent du contexte sans rapport et relisent des fichiers dont personne n'a besoin. Mais c'est un argument que je devrais appuyer sur des preuves de ce que ces sessions ont produit, et je l'ai appuyé sur des preuves de ce qu'elles ont coûté.
Trois leviers, chiffrés
| Levier | Les chiffres | Verdict |
|---|---|---|
| Terminer les sessions plus tôt | contexte par tour ~270k -> ~208k | environ 20-25 % de contexte en moins par tour, moins les nouvelles écritures de cache ; seuil de rentabilité non calculé |
| Compresser la sortie | 0,3 % des tokens, ~12 % du coût | vise ~10-12 % de la facture, pas une erreur d'arrondi |
| Réduire le préambule statique | 12 953 -> 10 075 tokens, face à un contexte moyen de 241k | du bruit |
La compression de la sortie vise ~10-12 % de la facture, pas une erreur d'arrondi. J'ai dit à la fois "la sortie est une erreur d'arrondi" et "la compression de la sortie vise ~10 % de la facture", à huit lignes d'écart, ce qui se lit comme une contradiction. Les deux sont vrais, dans des unités différentes : la sortie, c'est 0,3 % des tokens et ~12 % du coût, parce qu'elle est facturée ~50× le prix d'une lecture de cache. Précisez l'unité, sinon vous allez vous embrouiller, comme moi.
Les leviers intuitifs sont vraiment petits. J'ai réduit mon préambule statique de 12 953 à 10 075 tokens. Face à un contexte moyen de 241k, c'est du bruit. J'ai gardé le changement parce que des instructions plus courtes sont de meilleures instructions, pas pour l'argent.
Mesurez par vous-même
Mesurez avant d'installer quoi que ce soit. Ce conseil-là se généralise, même si ma conclusion, non. Ce qui ne se généralise pas, c'est ma distribution : 682 sessions en 14 jours, dont deux qui contiennent la moitié des tours, c'est la façon de travailler d'une seule personne, et une façon plutôt extrême. Quelqu'un qui lance beaucoup de petites invocations scriptées en CI a le profil inverse, peu de contexte par tour et beaucoup de sessions, et pour lui la compression de la sortie compte nettement plus.
La consommation rapportée par le fournisseur est déjà sur votre disque. Claude Code l'écrit dans ~/.claude/projects/**/*.jsonl.
Ce sur quoi je me suis trompé la première fois, pour vous l'éviter
- C'est une entrée par message, pas par tour : messages de l'utilisateur, messages de l'assistant, résultats d'outils. Comptez les entrées comme des tours et tous les chiffres dérivés sont faux.
- Excluez les entrées sidechain, sinon vous comptez deux fois l'usage des sous-agents (les agents auxiliaires qu'une session lance) sur la session parente.
- Définissez "tour". Vu l'arithmétique plus haut, un tour, c'est en pratique un appel d'API. Ce n'est probablement pas ce que vous supposiez.
- Les quatre champs qu'il vous faut, sur les messages de l'assistant :
input_tokens,output_tokens,cache_read_input_tokens,cache_creation_input_tokens(les écritures de cache).
Les étapes
- Listez les fichiers avec un glob.
- Filtrez les entrées sidechain.
- Additionnez les quatre champs par message de l'assistant.
- Multipliez par votre grille de prix.
- Regroupez par
sessionId. - Triez.
Vingt lignes de Python.
Trois questions à poser au résultat
Deux questions auxquelles répondre, et une à laquelle répondre ensuite :
- Les lectures de cache dominent-elles votre entrée ? Si oui, votre facture, c'est du contexte repayé.
- Une poignée de sessions domine-t-elle ces lectures ? Si oui, regardez de plus près.
- Ces sessions contiennent-elles aussi une part proportionnelle de vos tours ? Si oui, vous avez trouvé où est le travail, pas où est le gaspillage. C'est la question que j'ai sautée.
Avant d'installer un outil "économiseur de tokens"
Mêmes règles que pour n'importe quelle dépendance, on les saute juste plus souvent parce que l'argument de vente, c'est de vous faire économiser de l'argent.
- Ce que ça coûte à faire tourner. Si un skill (un module complémentaire pour l'agent) injecte un millier et quelques tokens d'entrée par tour pour compresser votre sortie, sur des dizaines de milliers de tours le bilan est nul, et sa propre doc vous le dira généralement.
- La licence. Beaucoup de ces outils sont source-available plutôt qu'open source au sens de l'OSI : vous pouvez lire le code, mais la licence n'est pas une licence open source approuvée par l'OSI. C'est une décision, pas un détail.
- Ce devant quoi il se place. Méfiez-vous de tout ce qui termine localement votre trafic OAuth vers le fournisseur (il se met au milieu de votre connexion authentifiée au fournisseur du modèle), ou qui fait de la compression avec perte (corps de fonctions supprimés, fichiers tronqués) devant un agent qui modifie du code. Donner à un agent une vue du code avec perte pour économiser des tokens, c'est un compromis que je ne fais pas, et c'est une question d'exactitude avant d'être une question de coût.
- Les économies qu'il annonce lui-même. Soit vous mesurez l'économie de façon indépendante (comparez la taille des transcripts avec et sans, sur un ensemble de tâches fixe), soit vous ne citez pas de chiffre.
J'ai cité auparavant un chiffre de "60,8 % économisés" venant d'un proxy CLI que j'utilise. C'est l'outil qui corrige sa propre copie, et mes propres notes indiquent que ce même proxy casse certains flags de commande et renvoie des résultats faux. Le citer avec approbation dans un article sur la vérification des affirmations, c'était exactement l'incohérence qu'un lecteur hostile devrait repérer.
Si vous voulez formuler une critique précise d'un outil précis, nommez-le et mettez un lien vers les lignes qui étayent l'affirmation. Décrire un projet identifiable sans le nommer, c'est perdant sur les deux tableaux : évident pour quiconque s'y intéresse, impossible à réfuter pour tous les autres, et le mainteneur ne peut pas répondre.
Ce que j'en retiens
- Concentré, ce n'est pas la même chose que gaspillé, ni que récupérable. Avant de couper les sessions qui coûtent le plus, vérifiez si elles contiennent aussi une part proportionnelle des tours. Mes deux plus grosses en contenaient 54 % pour 60 % du coût : les 86,8 % montraient où la dépense se concentrait, pas combien je pouvais économiser.
- Chiffrez le correctif, pas seulement le problème. Une nouvelle session repaie son contexte au tarif d'écriture de cache, donc terminer les sessions a un seuil de rentabilité que j'aurais dû calculer avant de le recommander. Le coût n'est pas le seul axe non plus : les plus gros contextes sont aussi plus lents, ce que mon chiffrage du découpage n'a jamais pris en compte (voir la mise à jour de novembre 2026).
- Précisez l'unité. La sortie, c'est 0,3 % des tokens et ~12 % du coût. Le pic de contexte et le contexte moyen sont deux chiffres différents. Je me suis embrouillé avec la première paire et j'ai confondu la seconde.
- Les leviers intuitifs sont vraiment petits ; le niveau de modèle est un levier d'une autre taille. Réduire mon préambule, c'était du bruit. La comparaison des modèles vient avec de grosses réserves, et je ne peux pas la classer face au découpage de session (voir la mise à jour de novembre 2026).
- Mesurez avant d'installer quoi que ce soit, et ne croyez pas un outil sur parole quand il annonce ses propres économies. Ma distribution est celle d'une seule personne, et une distribution plutôt extrême.
Mise à jour, novembre 2026
Deux mesures qui changent cet article. J'avais la première avant de publier, et je l'ai laissée de côté.
Les plus gros contextes sont aussi plus lents. En août, j'ai mesuré la latence sur une autre fenêtre, environ 20k tours de l'assistant regroupés par taille de contexte. L'attente médiane par tour augmente avec le contexte :
| Taille du contexte | Attente médiane par tour |
|---|---|
| 0-100k tokens | 4,9 s |
| 100-200k | 14,0 s |
| 300-400k | 19,8 s |
| 800-900k | 30,1 s |
Relire un contexte en cache, c'est bon marché, pas instantané. "Le correctif n'est pas gratuit non plus" chiffrait le découpage uniquement en tarifs de cache, et n'a jamais pris en compte le temps d'attente qui va avec un plus gros contexte. Ce que vaut le passage de ~270k à ~208k, je ne peux pas le dire : les deux tombent dans la tranche 200-300k, que cette mesure ne donne pas. Le contexte médian de cette fenêtre était de 380k, donc aucune de ces médianes ne s'applique aux chiffres de coût plus haut.
Le modèle est un levier que j'avais laissé de côté. J'ai écrit "Les leviers intuitifs sont vraiment petits", à propos de la réduction de mon préambule. Ça tient toujours. Ce que je n'avais pas envisagé, c'est que le niveau de modèle est un levier d'une autre taille. En septembre, le même diff a été relu en CI par Sonnet 4.6, puis par Opus 5 :
| Modèle relecteur | Coût | Tours |
|---|---|---|
| Sonnet 4.6 | 0,27 $ | 10 |
| Opus 5 | 1,31 $ | 24 |
Soit 4,8×. Sur ce dépôt, une revue Opus typique (médiane) coûtait environ 2,2× une revue Sonnet 4.6 typique ; mes notes n'indiquent pas sur combien de revues ça porte. C'est par exécution de CI, une charge de travail différente des sessions interactives plus haut, donc je ne peux pas classer ce levier face aux 20-25 %, qui étaient une baisse du contexte par tour, pas de la facture totale.
Les réserves ne sont pas minces :
- Une partie des 4,8× venait de mon prompt, pas du modèle. Les instructions de revue lui demandaient de vérifier sur le disque quelque chose qui n'existe jamais sur le runner de CI. Le plus petit modèle a sauté l'étape sans rien dire ; le plus gros a essayé de faire en sorte que ce soit vrai, n'a pas réussi à installer les dépendances, puis a lancé un lint et des tests que personne n'avait demandés.
- Les 2,2× incluent peut-être une partie du même excès ; mes notes ne le disent pas.
- La revue la moins chère n'était pas la même revue. Le plus petit modèle a validé ce diff, le plus gros l'a bloqué sur une remarque juste. Le nouveau helper comparait des chaînes brutes alors qu'un type fermé (un type qui liste toutes les valeurs autorisées) existait déjà, donc une nouvelle valeur lui ferait renvoyer un résultat vide sans rien signaler, sans qu'aucun test ne casse.