Aller au contenu principal

Comptage de tokens et budgétisation

Comprendre les tokens

Les tokens sont l’unité fondamentale de mesure pour les LLM. Chaque appel API est facturé en tokens. Maîtriser le comptage de tokens vous permet de prédire les coûts, d’optimiser vos prompts et de respecter les limites de contexte des modèles.

Compter les tokens avec tiktoken

Installation et utilisation de base

import tiktoken

# Encoder pour les modèles GPT
encodeur = tiktoken.encoding_for_model("gpt-5.3")

def compter_tokens(texte: str) -> int:
    """Compte le nombre de tokens dans un texte."""
    return len(encodeur.encode(texte))

# Exemples
print(compter_tokens("Bonjour"))           # ~1-2 tokens
print(compter_tokens("Bonjour le monde"))  # ~3-4 tokens
print(compter_tokens("Développement"))      # ~2-3 tokens (les accents coûtent plus)

Compter les tokens d’une conversation complète

def compter_tokens_conversation(messages: list[dict]) -> int:
    """Compte les tokens d'une conversation (messages + overhead)."""
    total = 0
    for message in messages:
        total += 4  # Overhead par message (role, etc.)
        total += compter_tokens(message["content"])
        if message.get("name"):
            total += compter_tokens(message["name"])
    total += 2  # Tokens de fin
    return total

conversation = [
    {"role": "system", "content": "Vous êtes un assistant technique."},
    {"role": "user", "content": "Expliquez les microservices."},
    {"role": "assistant", "content": "Les microservices sont une architecture..."},
]

print(f"Tokens totaux : {compter_tokens_conversation(conversation)}")

Budgétisation des tokens

Définir un budget par requête

from dataclasses import dataclass

@dataclass
class BudgetTokens:
    """Gère le budget de tokens pour un appel."""
    limite_contexte: int       # Fenêtre du modèle
    tokens_systeme: int = 0    # Prompt système
    tokens_historique: int = 0 # Historique conversation
    tokens_utilisateur: int = 0 # Message en cours
    reserve_sortie: int = 2000 # Réservé pour la réponse

    @property
    def tokens_disponibles(self) -> int:
        utilises = (
            self.tokens_systeme
            + self.tokens_historique
            + self.tokens_utilisateur
        )
        return self.limite_contexte - utilises - self.reserve_sortie

    @property
    def depasse(self) -> bool:
        return self.tokens_disponibles < 0

    def rapport(self) -> str:
        return (
            f"Contexte: {self.limite_contexte} | "
            f"Système: {self.tokens_systeme} | "
            f"Historique: {self.tokens_historique} | "
            f"Utilisateur: {self.tokens_utilisateur} | "
            f"Réserve sortie: {self.reserve_sortie} | "
            f"Disponible: {self.tokens_disponibles}"
        )

# Exemple avec GPT-5.3 (128K contexte)
budget = BudgetTokens(
    limite_contexte=128_000,
    tokens_systeme=compter_tokens(prompt_systeme),
    tokens_historique=compter_tokens_conversation(historique),
    tokens_utilisateur=compter_tokens(message_utilisateur),
)

if budget.depasse:
    print("Budget dépassé — compaction nécessaire")

Gestion automatique du contexte

def preparer_contexte(
    prompt_systeme: str,
    historique: list[dict],
    message: str,
    limite_modele: int = 128_000,
    reserve_sortie: int = 4_000,
) -> list[dict]:
    """Prépare le contexte en respectant le budget de tokens."""

    tokens_systeme = compter_tokens(prompt_systeme)
    tokens_message = compter_tokens(message)
    budget_historique = (
        limite_modele - tokens_systeme - tokens_message - reserve_sortie
    )

    # Garder les messages les plus récents dans le budget
    messages_gardes = []
    tokens_utilises = 0

    for msg in reversed(historique):
        tokens_msg = compter_tokens(msg["content"]) + 4
        if tokens_utilises + tokens_msg > budget_historique:
            break
        messages_gardes.insert(0, msg)
        tokens_utilises += tokens_msg

    return (
        [{"role": "system", "content": prompt_systeme}]
        + messages_gardes
        + [{"role": "user", "content": message}]
    )

Estimation des coûts à l’avance

def estimer_cout(
    tokens_entree: int,
    tokens_sortie_estime: int,
    modele: str = "gpt-5.3",
) -> dict:
    """Estime le coût d'un appel avant de l'exécuter."""
    tarifs = {
        "gpt-5.3": {"input": 0.50, "output": 1.50},
        "gpt-5.4": {"input": 2.50, "output": 10.00},
        "o4-mini": {"input": 1.10, "output": 4.40},
        "o3-pro": {"input": 20.00, "output": 80.00},
    }

    tarif = tarifs.get(modele, tarifs["gpt-5.3"])
    cout_entree = (tokens_entree / 1_000_000) * tarif["input"]
    cout_sortie = (tokens_sortie_estime / 1_000_000) * tarif["output"]

    return {
        "modele": modele,
        "tokens_entree": tokens_entree,
        "tokens_sortie_estime": tokens_sortie_estime,
        "cout_entree": f"${cout_entree:.6f}",
        "cout_sortie": f"${cout_sortie:.6f}",
        "cout_total": f"${cout_entree + cout_sortie:.6f}",
    }

# Avant d'envoyer un gros prompt
estimation = estimer_cout(
    tokens_entree=50_000,
    tokens_sortie_estime=2_000,
    modele="gpt-5.4",
)
print(estimation)

Fenêtres de contexte des modèles

Connaissez les limites de chaque modèle pour planifier votre budget :

  • GPT-5.3 : 128K tokens de contexte
  • GPT-5.4 : 1M tokens de contexte
  • o4-mini : 200K tokens de contexte
  • o3-pro : 200K tokens de contexte

Points clés à retenir

  • Utilisez tiktoken pour compter les tokens avant chaque appel
  • Réservez toujours un budget pour les tokens de sortie
  • Gérez le contexte automatiquement en éliminant les messages les plus anciens
  • Estimez les coûts avant d’envoyer les requêtes coûteuses