Élaguer l'historique de conversation pour réduire les coûts : fenêtre glissante ou résumé
Plafonnez ce que vous renvoyez à chaque tour : gardez les derniers messages ou un court résumé. Calcul des tokens pour une conversation de 50 tours et un helper Python.

Sur cette page
Votre bot de support discute depuis 50 tours, et chaque nouveau message coûte plus cher que le précédent. L'API ne mémorise rien, donc votre code renvoie toute la conversation à chaque fois. La solution est de plafonner ce que vous envoyez : gardez le prompt système et les derniers tours (une fenêtre glissante), ou remplacez les anciens tours par un court résumé. Voici l'arithmétique pour une conversation de 50 tours et un helper que vous pouvez copier.
Le guide du chat multi-tours de DeepSeek (api-docs.deepseek.com, vérifié le 1er novembre 2026) le dit clairement : le serveur n'enregistre pas le contexte des requêtes précédentes, donc le client envoie la liste messages complète à chaque appel. Le format compatible OpenAI sur CheapTokens fonctionne de la même manière. Si c'est nouveau pour vous, commencez par pourquoi une longue conversation coûte plus cher et comment fonctionne le tableau messages.
Ce que le tour 50 envoie réellement#
Supposons un bot de support avec un prompt système de 400 tokens. Dans un tour typique, l'utilisateur écrit environ 60 tokens et le bot répond avec environ 190. Un tour complet ajoute 250 tokens à l'historique. Ce sont des hypothèses : remplacez-les par les chiffres du champ usage de vos propres réponses.
Au tour 50, la requête transporte le prompt système, 49 tours précédents et le nouveau message : 400 + 49 × 250 + 60 = 12,710 tokens d'entrée, pour obtenir une réponse de 190 tokens. Additionnez toute la conversation. Le prompt système et le nouveau message sont envoyés à chaque fois : 50 × 460 = 23,000. L'historique répété ajoute 250 × 1,225 = 306,250. Au total : 23,000 + 306,250 = 329,250 tokens d'entrée, contre 50 × 190 = 9,500 tokens de sortie.
L'historique de chaque requête grandit d'un tour, donc le total croît avec le carré de la longueur de la conversation. Passez de 50 à 100 tours et la part d'historique répété quadruple environ.
Essayez vous-mêmeEssayez : si vous n'envoyiez que le prompt système, les 4 derniers tours et le nouveau message, combien de tokens d'entrée le tour 50 transporterait-il ?Afficher la réponse
1 460 (400 + 4 × 250 + 60), contre 12 710 avec l'historique complet. Même question, même longueur de réponse, une fraction de l'entrée.
Option 1 : une fenêtre glissante#
L'idée : toujours envoyer le prompt système, supprimer tout sauf les N derniers tours. Vous conservez l'historique complet dans votre propre stockage et ne taillez que la copie que vous envoyez.
def trim_history(messages, keep_pairs=4):
"""System prompt + the last keep_pairs turns + the new user message."""
system = [m for m in messages if m["role"] == "system"]
rest = [m for m in messages if m["role"] != "system"]
return system + rest[-(keep_pairs * 2 + 1):]Appelez-la après avoir ajouté le nouveau message de l'utilisateur. Avec keep_pairs=4, cela fait 4 paires utilisateur/assistant plus le nouveau message, 9 messages, et la tranche commence toujours sur un message utilisateur. Voici comment l'intégrer dans un appel réel :
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.cheaptokens.dev/v1",
api_key=os.environ["CHEAPTOKENS_API_KEY"],
)
MODEL = "deepseek-ai/DeepSeek-V4-Flash-0731"
history = [{"role": "system", "content": "You are a concise support assistant."}]
def ask(text):
history.append({"role": "user", "content": text})
resp = client.chat.completions.create(
model=MODEL,
messages=trim_history(history),
max_tokens=500,
)
answer = resp.choices[0].message.content
history.append({"role": "assistant", "content": answer})
print(resp.usage.prompt_tokens, resp.usage.completion_tokens)
return answerLa ligne print est la plus utile : surveillez le premier nombre. Sans élagage, il grimpe à chaque tour. Avec la fenêtre, il cesse de croître une fois que la conversation dépasse le tour 4.

En chiffres : à partir du tour 5, chaque requête fait 400 + 4 × 250 + 60 = 1,460 tokens d'entrée. Les quatre premiers tours croissent encore normalement et totalisent 3 340. Toute la conversation : 3,340 + 46 × 1,460 = 70,500 tokens d'entrée, environ un cinquième des 329 250 que vous envoyez avec l'historique complet. La sortie reste à 50 × 190 = 9,500.

Dans le code, tout le changement tient en un argument de l'appel :
Comparer
Le changement d'une ligne
Avant
messages=historyAprès
messages=trim_history(history)Le piège : une fenêtre oublie. Si l'utilisateur demande au tour 40 « quel était mon numéro de commande ? » et que le numéro était au tour 3, le modèle ne l'a jamais vu. Deux correctifs peu coûteux. Extrayez les faits stables (nom, numéro de commande, offre) de la conversation dans votre propre code et ajoutez-les au prompt système, où la fenêtre ne les coupe jamais. Ou ajoutez un résumé, ce qui est l'option suivante.
Option 2 : un résumé des anciens tours#
Au lieu de supprimer les anciens tours, vous les compressez. Tous les quelques tours, envoyez au modèle les tours qui viennent de sortir de la fenêtre, plus le résumé courant, et demandez un nouveau résumé court. Placez ensuite ce résumé dans le message système.
def summarize(summary, old_messages):
transcript = "\n".join(f"{m['role']}: {m['content']}" for m in old_messages)
prompt = (
f"Summary so far:\n{summary}\n\nNew turns:\n{transcript}\n\n"
"Rewrite the summary in under 200 words. "
"Keep names, numbers, decisions and open questions."
)
resp = client.chat.completions.create(
model=MODEL,
messages=[{"role": "user", "content": prompt}],
max_tokens=400,
)
return resp.choices[0].message.content
def build_messages(history, summary, keep_pairs=4):
system = history[0]["content"]
if summary:
system += "\n\nEarlier in this chat: " + summary
recent = history[1:][-(keep_pairs * 2 + 1):]
return [{"role": "system", "content": system}] + recentLe résumé n'est pas gratuit : c'est un appel modèle supplémentaire. Supposez un résumé d'environ 300 tokens, rafraîchi tous les 5 tours (9 fois sur 50 tours), chaque rafraîchissement lisant environ 1 600 tokens (l'ancien résumé plus cinq tours plus l'instruction) et écrivant 300. Pour rester du côté sûr, comptez le résumé dans chaque requête à partir du tour 5 (en réalité il apparaît après le premier rafraîchissement, c'est donc une légère surestimation) : 400 + 300 + 4 × 250 + 60 = 1,760 tokens d'entrée.
Totaux pour la conversation : requêtes principales 3,340 + 46 × 1,760 = 84,300 tokens d'entrée, appels de résumé 9 × 1,600 = 14,400 en entrée et 9 × 300 = 2,700 en sortie. Au total 84,300 + 14,400 = 98,700 tokens d'entrée et 9,500 + 2,700 = 12,200 tokens de sortie.
Le résumé coûte un peu plus que la fenêtre seule, et en échange le modèle sait toujours ce qui s'est passé au tour 3.
Ce que coûtent les trois configurations#
Voici la même conversation de 50 tours sur DeepSeek-V4-Flash, tarifée en direct à partir des totaux ci-dessus :
Les prix proviennent de la liste de prix en direct, donc les chiffres se mettent à jour quand le tarif change. L'ordre ne changera pas : la fenêtre envoie le moins, le résumé se situe entre les deux, l'historique complet est le plus cher.
Pour une conversation comme celle-ci, le modèle CheapTokens par lequel commencer est DeepSeek-V4-Flash. Il dispose d'une fenêtre de contexte de 380K (une conversation de 50 tours tient même sans élagage), jusqu'à 32 768 tokens de sortie par réponse, un prix fixe à toute heure de la journée, et au total, entrée et sortie comptées ensemble, il est moins cher qu'OpenRouter. L'identifiant du modèle est deepseek-. Si vous voulez comparer les modèles sur la configuration fenêtre (1 410 tokens d'entrée par requête en moyenne, 190 en sortie, 50 requêtes), voici le tableau en direct :
| Modèle | Entrée $/1M | Sortie $/1M | Par requête | 50 requêtes | OpenRouter, 50 requêtes |
|---|---|---|---|---|---|
| GLM-5.3-Flash | $0.02 | $0.04 | $0.000036 | $0.0018 | $0.0032 |
| DeepSeek-V4-Flash | $0.015 | $0.10 | $0.00004 | $0.002 | $0.0063 |
| MiniMax-M2.7 | $0.05 | $0.15 | $0.000099 | $0.005 | $0.0594 |
1 410 tokens d'entrée et 190 tokens de sortie par requête. Les prix par million de tokens sont actuels et évoluent avec nos tarifs ; la colonne OpenRouter indique des prix de référence pour la même charge de travail.
GLM-5.3-Flash a un contexte de 390K et MiniMax-M2.7 de 180K, ce qui suffit pour une conversation élaguée. Les prix actuels sont sur la page de tarification, et la documentation montre comment envoyer la première requête.
Lequel choisir#
Une fenêtre est le choix par défaut : trois lignes de code, aucun appel supplémentaire, aucun mode de défaillance supplémentaire. Utilisez-la pour les bots de support, les tuteurs et le jeu de rôle, où les derniers tours portent la conversation et le prompt système porte les règles. Ajoutez le résumé quand les utilisateurs font référence à des choses dites il y a longtemps, comme dans un assistant personnel avec une conversation sans fin. Gardez la fenêtre assez petite pour que le modèle voie encore le contexte immédiat, et assez grande pour contenir un échange complet question-réponse. Ce qui tient au total est une limite distincte, traitée dans qu'est-ce qu'une fenêtre de contexte.
Vérification rapide
L'utilisateur demande au tour 40 un numéro de commande donné au tour 3. Vous utilisez une fenêtre de 4 tours sans résumé. Que se passe-t-il ?
Afficher la réponse
Réponse: Le modèle ne peut pas le voir, car le tour 3 a été coupé de la requête
L'API est sans état. Le modèle ne voit que ce qui est dans la requête, donc les faits dont vous avez encore besoin doivent rester dans le prompt système ou dans un résumé.



