Méthode · IA

Le coût d’un agent IA : mesurer et réduire la facture de jetons

Pourquoi la facture d’un agent grandit avec chaque tour, comment la mesurer à partir du champ usage, et les leviers qui comptent : cache de prompt, modèle adapté, contexte maîtrisé.

Comment un LLM est facturé

Les API de LLM facturent au jeton (token), avec deux tarifs :

  • les jetons d’entrée : tout ce qui est envoyé au modèle (consignes, historique, documents, résultats d’outils) ;
  • les jetons de sortie : ce que le modèle produit, raisonnement compris quand il est activé. Ils coûtent plusieurs fois plus cher que l’entrée.

Le prix dépend aussi du modèle : un grand modèle peut coûter plusieurs fois le prix d’un petit, pour chaque jeton. Les ordres de grandeur, et non les tarifs exacts qui changent souvent, suffisent pour raisonner.

Pourquoi un agent coûte plus cher

Un appel unique (résumer un texte) envoie une fois l’entrée. Un agent fonctionne en boucle : à chaque tour, le harness renvoie toute la conversation au modèle, qui n’a pas de mémoire. Chaque fichier lu, chaque sortie de commande est donc refacturé à tous les tours suivants.

Tour 1 : consignes (8 000) + demande (200)                          →   8 200 jetons envoyés
Tour 2 : tout le tour 1 + appel d'outil + résultat (3 000)          →  11 400 jetons envoyés
Tour 3 : tout le tour 2 + lecture d'un fichier (6 000)              →  17 600 jetons envoyés
...
Tour 20 : la conversation entière, renvoyée une vingtième fois      → 120 000 jetons envoyés

Total facturé en entrée sur 20 tours : la somme de tous ces envois, bien plus que 120 000.

Conséquence : le coût d’une session croît bien plus vite que sa durée. Une session de vingt tours peut coûter des dizaines de fois une session de deux tours, et une sortie d’outil volumineuse lue au début pèse sur toute la suite.

Mesurer avant d’optimiser

Chaque réponse de l’API indique sa consommation exacte dans un champ usage :

"usage": {
  "input_tokens": 1830,
  "cache_creation_input_tokens": 0,
  "cache_read_input_tokens": 41200,
  "output_tokens": 640
}

Journaliser ce champ pour chaque appel, avec la tâche concernée, permet de savoir où va l’argent :

import json

# Tarifs symboliques par million de jetons : remplacer par la grille réelle du fournisseur et du modèle.
TARIF = {"entree": 1.0, "ecriture_cache": 1.25, "lecture_cache": 0.1, "sortie": 5.0}

def cout(usage):
    return (
        usage.get("input_tokens", 0) * TARIF["entree"]
        + usage.get("cache_creation_input_tokens", 0) * TARIF["ecriture_cache"]
        + usage.get("cache_read_input_tokens", 0) * TARIF["lecture_cache"]
        + usage.get("output_tokens", 0) * TARIF["sortie"]
    ) / 1_000_000

# journal.jsonl : une ligne par appel, avec la tâche et le champ usage de la réponse
par_tache = {}
for ligne in open("journal.jsonl"):
    appel = json.loads(ligne)
    par_tache[appel["tache"]] = par_tache.get(appel["tache"], 0) + cout(appel["usage"])

for tache, total in sorted(par_tache.items(), key=lambda t: -t[1]):
    print(f"{tache:30} {total:8.4f}")

Le classement révèle presque toujours une ou deux tâches qui représentent l’essentiel de la dépense : c’est là qu’il faut agir, pas ailleurs.

Le cache de prompt

Puisque chaque tour renvoie le même début de conversation, les fournisseurs proposent un cache de prompt : un préfixe déjà vu récemment est relu pour une petite fraction du prix normal, et traité plus vite. Dans l’exemple ci-dessus, 41 200 jetons sur 43 030 viennent du cache.

  • Le cache porte sur un préfixe exact : consignes et outils stables en tête, ce qui change à la fin.
  • Modifier les consignes, l’ordre des outils ou un horodatage en tête de prompt invalide tout ce qui suit.
  • Le cache expire après quelques minutes d’inactivité (durée variable selon le fournisseur et l’option choisie).

Sur un agent, c’est en général le levier le plus rentable : il ne change rien au résultat et réduit fortement la facture d’entrée.

Le bon modèle pour chaque tâche

Utiliser le plus grand modèle partout est confortable, et cher. Une répartition par tâche est plus juste :

TâcheModèle adapté
Classer, extraire un champ, router une demandePetit modèle rapide
Résumer, reformuler, répondre sur un document fourniModèle intermédiaire
Planifier, coder, raisonner sur plusieurs fichiersGrand modèle

Les traitements sans urgence (classer des milliers de demandes la nuit) passent par l’API de traitement par lots des fournisseurs, sensiblement moins chère qu’un appel interactif. Un changement de modèle se valide sur un jeu d’évaluation : moins cher n’a d’intérêt que si la qualité tient.

Un contexte maîtrisé

Chaque jeton évité dans le contexte est évité à tous les tours suivants. Les techniques de l’article Gérer la fenêtre de contexte sont aussi des économies :

  • sorties de commandes bornées (tail, --oneline, grep) plutôt que complètes ;
  • lecture d’une plage de lignes plutôt que du fichier entier ;
  • instructions permanentes courtes, procédures dans des skills chargés à la demande ;
  • exploration volumineuse confiée à un sous-agent qui ne renvoie que sa conclusion ;
  • une nouvelle session par sujet, plutôt qu’une conversation qui s’allonge sans fin ;
  • une longueur de sortie plafonnée, adaptée à la tâche.

Les leviers par ordre d’impact

  1. Mesurer par tâche : on n’optimise que ce qu’on voit.
  2. Activer et préserver le cache de prompt : préfixe stable, changements en fin.
  3. Réduire le contexte : sorties bornées, lectures ciblées, sessions courtes.
  4. Choisir le modèle par tâche, validé par une évaluation.
  5. Passer en lot ce qui n’est pas urgent.
🍪 Gestion des cookies
Ce site utilise des cookies pour mesurer l'audience (Google Analytics) et lire des vidéos (YouTube). Vous pouvez personnaliser votre choix.
Mentions légales
Réglages des cookies
Essentiels Nécessaires au fonctionnement du site — ne peuvent pas être désactivés.
Google Analytics Analyse d'audience (pages vues, sources de trafic). Aucune donnée personnelle identifiante.
YouTube Permet de lire les vidéos YouTube intégrées sur cette page.