Aller au contenu principal
Retour au blog

Économiser des tokens dans Claude Code : les leviers natifs

Cache de prompt, /clear et /compact, Tool Search, skills, règles scopées, hooks : les leviers natifs de Claude Code pour réduire ta conso de tokens.

Flavien Métivier · 11 min de lecture
Sommaire · 10 parties

Ouvre /context dans une session qui tourne depuis deux heures. Avant même que tu aies tapé une ligne utile, une bonne part de la fenêtre est occupée : un CLAUDE.md qui s'est empilé au fil des retours d'expérience, des serveurs MCP que personne n'appelle, trois sujets sans rapport mélangés dans la même conversation. Chaque tour de dialogue relit tout cela. Tu ne paies pas seulement ce que Claude produit, tu paies surtout ce qu'il relit.

Le réflexe courant est d'aller chercher un outil tiers qui compresse les sorties de commandes ou raccourcit les réponses. Ces outils ont leur utilité, on les passera au crible plus loin dans cette série. Mais Claude Code embarque déjà une dizaine de leviers qui s'attaquent à la cause. Les leviers natifs d'économie de tokens sont les mécanismes intégrés (cache de prompt, compaction, chargement différé des outils et des skills, sous-agents, hooks) qui réduisent le contexte envoyé à chaque tour sans changer de modèle. Pour situer l'enjeu, la doc officielle sur les coûts cite une moyenne d'environ 13 $ par développeur et par jour actif, 150 à 250 $ par mois, et moins de 30 $ par jour actif pour 90 % des utilisateurs.

Pourquoi Claude Code consomme-t-il autant de tokens ?

Parce que le contexte entier est renvoyé à chaque requête. Claude Code ne se souvient de rien entre deux messages : prompt système, définitions d'outils, CLAUDE.md, mémoire, tous les messages et résultats d'outils précédents repartent à chaque tour. Un fichier lu au tour 3 est relu au tour 4, au tour 5, et ainsi de suite. Le coût d'une session croît donc avec la taille du contexte multipliée par le nombre de tours, pas avec le travail fourni. Une session « fourre-tout » coûte plus cher que trois sessions ciblées qui font le même travail.

Ce qui évite de tout payer plein tarif, c'est le prompt caching, automatique dans Claude Code. L'ordre des couches détermine ce qui reste en cache : prompt système et outils d'abord, puis contexte projet (CLAUDE.md, mémoire, règles sans paths), puis la conversation. Un changement dans la conversation laisse le reste en cache ; un changement dans une couche haute invalide tout ce qui suit. Le mécanisme côté API est détaillé dans notre article sur le prompt caching de l'API Claude.

Comment mesurer sa consommation avec /usage et /context ?

Deux commandes natives suffisent pour un premier diagnostic. /context montre ce qui occupe la fenêtre en ce moment : outils MCP, mémoire, skills, historique. /usage affiche la consommation de la session et, depuis la v2.1.251, une ligne Prompt cache (main) après la première réponse : nombre de requêtes, part des tokens d'entrée servis par le cache, misses, cache chaud ou froid avec le TTL en vigueur. Depuis la v2.1.260, elle nomme aussi la cause probable du dernier miss quand elle est identifiable.

bash
Prompt cache (main):   14 requests · 91% of input tokens from cache · 2 misses (last 6m 10s ago, 310.2k tokens re-cached) · 1 expected rebuild (compaction or tool-result clearing) · warm (1h TTL, last activity 40s ago)

Sur abonnement, /usage répartit aussi la consommation récente par skill, sous-agent, plugin et serveur MCP, et lève un signal dès qu'un comportement pèse 10 % ou plus de l'usage récent. Les chiffres sont approximatifs et calculés sur l'historique local. Règle d'usage : si la ligne cache affiche beaucoup de misses, ne cherche pas un outil, cherche ce qui a changé dans ton préfixe. La mesure fine à l'échelle d'une équipe fera l'objet d'un article dédié de la série.

Le prompt caching est-il automatique dans Claude Code ?

Oui, et tu n'as rien à activer. En revanche, tu as de quoi le perdre. Le TTL dépend de la façon dont tu paies : 1 heure pour la conversation principale sur abonnement, tant que tu restes dans les limites du plan ; 5 minutes dès que tu tires sur des crédits d'usage, et par défaut en clé API ou via un cloud provider. Les requêtes hors conversation principale (sous-agents, compaction, workflows) sont à 5 minutes par défaut, même sur abonnement. Pour forcer une heure en API, la doc du prompt caching décrit le réglage promptCacheTtl ou la variable CLAUDE_CODE_PROMPT_CACHE_TTL=1h (v2.1.242+). L'écriture en cache d'une heure est facturée plus cher : elle ne vaut que si tes sessions dorment réellement.

  • Changer de modèle en cours de session : chaque modèle a son propre cache, le tour suivant relit tout sans hit. Même effet avec une skill dont le frontmatter impose un autre model, et avec l'alias opusplan, où chaque bascule entre plan et exécution change de modèle.
  • Activer le fast mode : il modifie un en-tête qui fait partie de la clé de cache. Active-le en début de session.
  • Brancher ou débrancher un serveur MCP dont les outils étaient chargés d'avance : le cache saute. Fais le ménage avant de démarrer.
  • Mettre à jour Claude Code : le prompt système change, la première conversation suivante repart de zéro. La mise à jour automatique s'applique au lancement suivant, jamais en cours de session.
  • Passer derrière un proxy LLM qui supprime les marqueurs cache_control : tout l'historique est facturé sans cache à chaque tour. Vérifie la ligne Prompt cache (main).

À l'inverse, éditer des fichiers, modifier CLAUDE.md, changer de mode de permission ou utiliser /rewind conservent le cache. Bonne nouvelle pour la génération 5.5 : changer l'effort en cours de session ne casse pas le cache sur Opus 5.5, Sonnet 5.5 et Haiku 5.5, alors que c'est le cas sur la plupart des modèles précédents.

/clear ou /compact : lequel choisir et quand ?

Utilise /clear quand tu changes de tâche, /compact quand la même tâche s'allonge. /clear est gratuit : il repart d'une conversation vide. Règle simple : une tâche, une session. Fais un /rename avant pour retrouver la session avec /resume. /compact, lui, est une grosse requête : il relit toute la conversation pour la résumer. Si le cache est chaud, il coûte une fraction de ce que la taille du contexte laisse croire ; si le cache a expiré, il retraite tout en entrée non cachée. Pour abandonner une mauvaise piste, /rewind (ou double Échap) revient à un tour dont le préfixe est déjà en cache, ce qui est moins cher que compacter.

La vraie valeur de /compact est dans son argument : tu dis à Claude ce qu'il doit conserver. Sans consigne, le résumé garde ce que le modèle juge important. Pour que la consigne s'applique à toutes les compactions, y compris automatiques, la doc propose une section dédiée dans le CLAUDE.md racine. Version adaptée à un projet Symfony :

bash
# Compact instructions

When compacting, preserve: the list of modified files, failing PHPUnit/PHPStan output,
the current migration or refactoring plan, and decisions about Doctrine mappings.
Drop exploratory file reads and successful command output.

Le CLAUDE.md racine est relu depuis le disque après une compaction. Une consigne donnée uniquement en conversation peut, elle, disparaître au résumé : si elle compte, écris-la dans le fichier. Compacte aux ruptures naturelles (tests au vert, fonctionnalité terminée) plutôt que de laisser l'auto-compaction se déclencher au milieu d'une refonte.

Nouveauté du 14 octobre 2026 (v2.1.299) : la compaction au repos. En terminal, une conversation de plus de 200k tokens laissée inactive environ 54 minutes est compactée juste avant l'expiration du cache d'une heure, pour que ton prochain message ne retraite pas tout. "idleCompaction": false dans les settings la désactive, CLAUDE_CODE_IDLE_COMPACT_MIN_TOKENS change le seuil. Si ton équipe laisse trois sessions ouvertes pendant le déjeuner, ce comportement la concerne directement. Vérifie ta version avec claude --version.

Comment réduire le contexte chargé au démarrage ?

Tout ce qui se charge au démarrage est relu à chaque tour, au tarif cache, mais relu. Premier poste : CLAUDE.md. La doc recommande de rester sous 200 lignes ; au-delà, le fichier consomme plus de contexte et l'adhésion aux consignes se dégrade. Piège fréquent : les @imports organisent le fichier mais ne réduisent pas le coût, car les fichiers importés se chargent au lancement. Les techniques de découpage sont détaillées dans l'optimisation avancée de CLAUDE.md.

Deuxième poste : les procédures rares. Une skill fonctionne par divulgation progressive : seule sa description d'une ligne est listée au démarrage, le corps ne se charge qu'à l'invocation. Une procédure de release de 80 lignes placée dans une skill ne coûte presque rien tant que tu ne publies pas ; dans CLAUDE.md, elle est relue à chaque tour de chaque session. Avec disable-model-invocation: true, la skill n'apparaît même pas dans la liste : coût nul jusqu'à ce que tu l'appelles avec /nom.

Votre équipe utilise Claude Code ?

Formation intra sur vos projets réels : de la demi-journée à 2 jours, 6 devs max.

Voir les formats →

Troisième poste : les conventions par dossier. Dans .claude/rules/, une règle sans paths se charge au lancement comme CLAUDE.md. Avec paths, elle ne se charge que quand Claude lit, écrit ou édite un fichier correspondant. Parfait pour séparer les conventions d'un projet Symfony :

bash
---
paths:
  - "src/Controller/**/*.php"
  - "tests/Functional/**/*.php"
---

# Conventions contrôleurs

- Contrôleurs fins : la logique va dans un service ou un handler Messenger.
- Attributs de routing (#[Route]), pas de YAML.
- Tests fonctionnels : WebTestCase, jamais d'appel réel vers un service externe.

Ce fichier, par exemple .claude/rules/symfony-controllers.md, ne coûte rien tant que la session ne touche pas aux contrôleurs. Dernier réflexe simple : interdire la lecture de ce qui n'a aucune raison d'être lu (vendor/, var/cache/, node_modules/) via des règles deny dans un .claude/settings.json versionné. C'est une règle d'équipe, pas une préférence personnelle.

Qu'est-ce que Tool Search et que reste-t-il à faire côté MCP ?

Tool Search diffère le chargement des outils MCP : seuls leurs noms et les instructions des serveurs entrent dans le contexte, les schémas complets sont chargés à la demande. Il est actif par défaut. Brancher dix serveurs coûte donc beaucoup moins qu'avant, mais pas zéro. Deux leviers restent valables : /mcp pour désactiver ce que le projet n'utilise pas, et préférer une CLI (gh, aws, gcloud, sentry-cli) quand elle existe. La doc indique qu'elles restent plus économes en contexte, car elles n'ajoutent aucun listing d'outils.

Pour un serveur dont tu as besoin à chaque tour, "alwaysLoad": true dans .mcp.json charge ses outils d'emblée, à réserver à très peu de serveurs. ENABLE_TOOL_SEARCH=auto:N charge les schémas d'avance tant qu'ils pèsent moins de N % du contexte (10 % pour auto). Si tu développes tes propres serveurs, le guide pour connecter Claude Code à tes outils internes reste la référence ; garde des descriptions d'outils courtes, elles sont relues à chaque tour.

Comment filtrer les sorties verbeuses avec un hook ?

Une suite PHPUnit qui affiche des milliers de lignes pour signaler une seule erreur injecte ces milliers de lignes dans le contexte, relues à chaque tour suivant. La doc donne l'exemple d'un hook PreToolUse qui réécrit la commande Bash pour ne garder que les échecs. On le déclare dans les settings :

json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "~/.claude/hooks/filter-phpunit-output.sh"
          }
        ]
      }
    ]
  }
}

Voici une adaptation pour PHPUnit et Pest. Elle corrige un défaut de l'exemple officiel : un pipe vers grep | head écrase le code de sortie des tests, et Claude croirait que la suite a réussi. Ici, PIPESTATUS restitue le vrai code de sortie du runner. Teste-le sur des échecs réels avant de le diffuser :

bash
#!/usr/bin/env bash
# ~/.claude/hooks/filter-phpunit-output.sh (chmod +x, nécessite jq)
input=$(cat)
cmd=$(jq -r '.tool_input.command // ""' <<<"$input")

case "$cmd" in
  *"|"*) echo '{}'; exit 0 ;;   # commande déjà pipée : on n'y touche pas
  *vendor/bin/phpunit*|*bin/phpunit*|*vendor/bin/pest*) ;;
  *) echo '{}'; exit 0 ;;
esac

# Garde les tests en échec et le bilan ; PIPESTATUS restitue le code du runner
filtered="{ $cmd; } 2>&1 | grep -E -A 8 '^[0-9]+[)] |FAILURES!|ERRORS!|^OK |^Tests: |PHP Fatal' | head -120; exit \${PIPESTATUS[0]}"

jq --arg c "$filtered" \
  '{hookSpecificOutput: {hookEventName: "PreToolUse", permissionDecision: "ask", updatedInput: (.tool_input + {command: $c})}}' \
  <<<"$input"

Trois précisions tirées de la doc des hooks. updatedInput remplace l'objet d'entrée entier, d'où la fusion .tool_input + {command: …}. Un hook qui échoue ne bloque pas par défaut ; "onFailure": "block" existe depuis la v2.1.295. Et permissionDecision: "allow" court-circuiterait l'invite de permission pour la commande réécrite : le script utilise "ask" pour garder la validation, à toi d'arbitrer selon ton mode de permission. Limite honnête : un filtre trop agressif cache précisément l'information dont Claude a besoin pour corriger, et un hook est du code que l'équipe doit maintenir.

Quand déléguer à un sous-agent pour économiser du contexte ?

Quand l'opération est verbeuse et que seul son résultat t'intéresse : suite de tests complète, lecture de logs, exploration d'un module inconnu. Un sous-agent travaille dans son propre contexte, lit vingt fichiers, et ne renvoie à la conversation principale qu'un résumé. Ses requêtes consomment quand même ton quota, avec leur propre cache à 5 minutes, mais les vingt fichiers ne polluent jamais ta session. Pour limiter la facture, donne-leur un modèle plus petit : la répartition par rôle est détaillée dans quel modèle choisir dans Claude Code. Pour lire un seul fichier, ne lance rien : un sous-agent a un coût de démarrage.

Même logique de prudence pour les orchestrations lourdes. Les agent teams, désactivées par défaut (CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1), consomment environ 7 fois plus de tokens qu'une session standard quand les coéquipiers sont en plan mode, chacun ayant sa propre fenêtre. Les /loop et tâches planifiées renvoient tout ton contexte à chaque déclenchement. À lancer sciemment, avec un budget explicite.

L'effort et le plan mode changent-ils la facture ?

Oui. Le raisonnement est facturé comme de la sortie. Sur la génération 5.5, le thinking ne peut plus être désactivé, et MAX_THINKING_TOKENS ne vaut que pour les modèles à budget fixe : les modèles à raisonnement adaptatif ignorent ce plafond. Le levier est donc /effort : bas sur l'exécution mécanique, haut sur la planification et le débogage opaque. Le plan mode (Maj+Tab), lui, coûte un peu plus sur le moment mais évite la réécriture complète quand la direction initiale était mauvaise ; il ne casse pas le cache, sauf avec opusplan pour la raison vue plus haut. Enfin, les habitudes gratuites : des prompts précis (« ajoute la validation dans LoginController::__invoke » plutôt que « améliore ce code ») et Échap dès que Claude part dans le mauvais sens.

Par quel levier commencer ?

Voici la checklist, classée du gain le plus rentable au plus fin. La doc ne chiffre aucun de ces leviers : mesure avec /usage et /context avant et après chaque étape, sinon tu ne sauras pas ce qui a produit un gain.

  • 1. Une tâche, une session : /clear entre deux sujets sans rapport. Effort nul, gain immédiat.
  • 2. Fixer modèle et fast mode en début de session, pas en cours : le cache est préservé.
  • 3. Désactiver les MCP dormants avec /mcp avant de démarrer, et préférer gh et consorts.
  • 4. Passer CLAUDE.md sous 200 lignes : procédures rares en skills, conventions par dossier en règles à paths.
  • 5. Ajouter une section « Compact instructions » et compacter aux ruptures de tâche ; /rewind pour abandonner une piste.
  • 6. Règles deny sur vendor/, var/cache/ et node_modules/, versionnées.
  • 7. Hook de filtrage pour la sortie la plus bavarde du projet, souvent la suite de tests.
  • 8. Sous-agents sur un petit modèle pour les explorations volumineuses.
  • 9. Agent teams et /loop uniquement avec un budget explicite.

Les gains sont rarement dans l'outil qu'on ajoute, ils sont dans ce qu'on retire du contexte. Une fois ces leviers appliqués, tu pourras évaluer les outils tiers (filtrage de sorties, compression de réponses, recherche sémantique) sur une base propre, avec une mesure de référence : c'est le programme des prochains articles. Ces réglages ne font cependant gagner du budget que s'ils sont appliqués partout, pas par un seul développeur motivé : c'est en les versionnant dans le dépôt qu'ils deviennent une convention d'équipe.

Cet article vous a été utile ? Partagez-le.

Portrait de Flavien Métivier, fondateur de The Bearded Bear : barbe longue, lunettes, sur fond sombre

Écrit par

Flavien Métivier

Expert PHP/Symfony indépendant depuis 2014, ancien CTO de Kartable et d'Extrabat. Plus de 80 projets menés, de l'audit à la migration.

Mon parcours

À lire ensuite

Votre équipe utilise Claude Code ?

Formation intra sur vos projets réels : de la demi-journée à 2 jours, 6 devs max.

Newsletter Bear Bytes

Veille Claude Code, Symfony et PHP, retours d'expérience terrain et conseils techniques, directement dans votre boîte mail.