Tokens, contexte et fenêtre de conversation
Mis à jour le 29 juillet 2026
Tokens, contexte et fenêtre de conversation
Le token est l’unité que le modèle manipule et celle que votre facture comptabilise. Tant que cette notion reste floue, vos coûts le resteront aussi, et vous rencontrerez tôt ou tard l’erreur de dépassement de contexte sans savoir d’où elle vient. Cette leçon lève les deux difficultés.
Qu’est-ce qu’un token ?
Un token n’est pas un mot. C’est un fragment de texte que le modèle traite comme une unité indivisible, et en français un token représente en moyenne 0,7 mot. La bibliothèque tiktoken permet de voir concrètement le découpage : notez comment « allez-vous » se scinde en deux tokens tandis que « aujourd’hui », plus fréquent dans le corpus d’entraînement, tient en un seul. C’est ce détail qui explique qu’un texte français consomme davantage de tokens qu’un texte anglais de longueur comparable.
from openai import OpenAI
client = OpenAI()
# Pour estimer les tokens, utilisez la bibliothèque tiktoken
import tiktoken
# cl200k_base sert ici d'exemple : chaque génération de modèles a son encodeur,
# vérifiez celui du modèle que vous appelez avant de vous fier au comptage
enc = tiktoken.get_encoding("cl200k_base")
texte = "Bonjour, comment allez-vous aujourd'hui ?"
tokens = enc.encode(texte)
print(f"Texte : {texte}")
print(f"Nombre de tokens : {len(tokens)}")
print(f"Tokens : {tokens}")
print(f"Décodés : {[enc.decode([t]) for t in tokens]}")
# Résultat :
# Texte : Bonjour, comment allez-vous aujourd'hui ?
# Nombre de tokens : 9
# Tokens : [38025, 11, 4068, 67590, 5072, 76439, 30, ...]
# Décodés : ['Bonjour', ',', ' comment', ' allez', '-vous', " aujourd'hui", ' ?']
Vérifiez toujours quel encodeur correspond au modèle que vous appelez : un comptage effectué avec le mauvais encodeur reste une approximation utile, mais ne correspondra pas exactement à la facturation.
La fenêtre de contexte
Chaque modèle dispose d’une fenêtre de contexte maximale, et le point qui piège les débutants est qu’elle englobe l’input et l’output. Ce n’est pas un budget d’entrée : c’est un budget total. Si votre prompt occupe 190 000 tokens d’une fenêtre de 200 000, il ne reste que 10 000 tokens pour la réponse, et le modèle sera coupé au milieu d’une phrase sans autre avertissement.
# Génération précédente, pour référence :
# GPT-5.4 : 1 000 000 tokens de contexte
# GPT-5.3 : 200 000 tokens de contexte
# gpt-5.6-sol : 200 000 tokens de contexte
# gpt-5.6-terra : 200 000 tokens de contexte
# Exemple : si votre input fait 190 000 tokens dans une fenêtre de 200 000,
# il reste seulement 10 000 tokens pour la réponse
response = client.responses.create(
model="gpt-5.6-terra",
input="Un très long texte...",
max_output_tokens=10000 # Limiter explicitement
)
Après coup, la mesure exacte se lit dans response.usage, qui distingue les tokens d’entrée, ceux de sortie et le total :
response = client.responses.create(
model="gpt-5.6-terra",
input="Expliquez les tokens en trois phrases."
)
usage = response.usage
print(f"Tokens en entrée : {usage.input_tokens}")
print(f"Tokens en sortie : {usage.output_tokens}")
print(f"Total : {usage.total_tokens}")
# Résultat :
# Tokens en entrée : 12
# Tokens en sortie : 58
# Total : 70
Trois leviers d’optimisation
Le premier levier est la concision du prompt. Les formules de politesse et les précautions oratoires n’améliorent pas la réponse et se paient au token près : la première version ci-dessous en consomme trente-cinq pour un résultat identique à la seconde, qui en consomme dix. À l’échelle d’un service qui traite un million de requêtes, l’écart n’est plus anecdotique.
# MAUVAIS — prompt verbeux (35 tokens)
response = client.responses.create(
model="gpt-5.6-terra",
input="Pourriez-vous s'il vous plaît me donner une liste "
"de trois fruits qui sont de couleur rouge, si cela "
"ne vous dérange pas bien entendu ?"
)
# BON — prompt concis (10 tokens)
response = client.responses.create(
model="gpt-5.6-terra",
input="Listez 3 fruits rouges."
)
Le deuxième levier porte sur la sortie, qui coûte plusieurs fois plus cher que l’entrée. Combinez la consigne dans le prompt et le plafond technique : la première cadre la rédaction, le second garantit que votre budget tient même si le modèle ignore la consigne.
# Sans limite — le modèle peut générer beaucoup de tokens
response = client.responses.create(
model="gpt-5.6-terra",
input="Expliquez la photosynthèse."
)
# Avec limite — contrôle du coût
response = client.responses.create(
model="gpt-5.6-terra",
input="Expliquez la photosynthèse en 2 phrases maximum.",
max_output_tokens=100
)
Le troisième levier consiste à estimer le coût avant l’appel, ce qui devient indispensable dès que vous traitez des documents de taille variable : vous pouvez alors refuser ou découper une requête trop lourde plutôt que de la découvrir sur la facture.
import tiktoken
def estimer_cout(texte: str, modele: str = "gpt-5.6-terra") -> dict:
"""Estime le coût d'un appel API."""
enc = tiktoken.get_encoding("cl200k_base")
input_tokens = len(enc.encode(texte))
# Prix approximatifs par million de tokens (vérifiez les prix actuels)
prix = {
"gpt-5.6-sol": {"input": 5.0, "output": 30.0},
"gpt-5.6-terra": {"input": 2.0, "output": 12.0},
"gpt-5.6-luna": {"input": 0.20, "output": 1.20},
}
cout_input = (input_tokens / 1_000_000) * prix[modele]["input"]
return {
"input_tokens": input_tokens,
"cout_input_usd": round(cout_input, 6),
"modele": modele
}
print(estimer_cout("Expliquez la relativité en 3 phrases."))
# Résultat : {'input_tokens': 10, 'cout_input_usd': 2.5e-05, 'modele': 'gpt-5.6-terra'}
Le contexte s’accumule au fil de la conversation
Quand vous enchaînez les échanges avec previous_response_id, chaque tour repart de l’intégralité des tours précédents. Les tokens d’entrée ne cessent donc de croître : un dialogue qui commence à 50 tokens en pèse 150 au deuxième tour et beaucoup plus au dixième. C’est la cause la plus fréquente des factures qui dérapent sans que le trafic ait augmenté, et la surveillance de response.usage.input_tokens est votre signal d’alerte.
# Tour 1 : 50 tokens
r1 = client.responses.create(
model="gpt-5.6-terra",
input="Bonjour, je suis développeur Python."
)
# Tour 2 : 50 + 100 = 150 tokens (contexte cumulé)
r2 = client.responses.create(
model="gpt-5.6-terra",
input="Quels frameworks web me conseillez-vous ?",
previous_response_id=r1.id
)
# Tour 10 : les tokens s'accumulent !
# Surveillez response.usage.input_tokens pour éviter les surprises
print(f"Tokens cumulés au tour 2 : {r2.usage.input_tokens}")
Sur les conversations longues, la parade consiste à tronquer activement l’historique : on supprime les messages les plus anciens jusqu’à repasser sous une limite choisie, tout en conservant le premier, qui porte généralement le contexte fondateur de l’échange.
def conversation_avec_limite(messages: list, limite_tokens: int = 50000):
"""Maintient la conversation sous une limite de tokens."""
enc = tiktoken.get_encoding("cl200k_base")
total = sum(len(enc.encode(m["content"])) for m in messages)
# Supprimer les messages les plus anciens si nécessaire
while total > limite_tokens and len(messages) > 2:
removed = messages.pop(1) # Garder le premier message (contexte)
total -= len(enc.encode(removed["content"]))
return messages
Points clés à retenir
- Un token vaut environ 0,7 mot en français
- La fenêtre de contexte inclut l’input ET l’output
- Les fenêtres varient d’un modèle à l’autre : dans la génération précédente, 1M de tokens pour GPT-5.4 et 200K pour GPT-5.3, o3-pro et o4-mini
- Utilisez
tiktokenpour compter les tokens avant l’appel - Surveillez
response.usagepour contrôler vos coûts - Gérez activement le contexte dans les longues conversations