Taglia la cronologia della chat per ridurre i costi: finestra scorrevole o riassunto
Limita ciò che reinvii a ogni turno: mantieni gli ultimi messaggi o un breve riassunto. Aritmetica dei token per una chat di 50 turni e un helper Python.

In questa pagina
Il tuo bot di supporto chatta da 50 turni e ogni nuovo messaggio costa più del precedente. L'API non ricorda nulla, quindi il tuo codice rinvia l'intera conversazione ogni volta. La soluzione è limitare ciò che invii: mantieni il system prompt e gli ultimi turni (una finestra scorrevole), oppure sostituisci i vecchi turni con un breve riassunto. Qui sotto trovi l'aritmetica per una chat di 50 turni e un helper che puoi copiare.
La guida alla chat multi-round di DeepSeek (api-docs.deepseek.com, verificata il 1 novembre 2026) lo dice chiaramente: il server non registra il contesto delle richieste precedenti, quindi il client invia l'intera lista messages a ogni chiamata. Il formato compatibile OpenAI su CheapTokens funziona allo stesso modo. Se è una novità per te, inizia da perché una chat lunga costa di più e come funziona l'array messages.
Cosa invia davvero il turno 50#
Supponi di gestire un bot di supporto con un system prompt di 400 token. In un turno tipico l'utente scrive circa 60 token e il bot risponde con circa 190. Un turno completo aggiunge 250 token alla cronologia. Sono ipotesi: sostituiscile con i numeri del campo usage delle tue risposte.
Al turno 50 la richiesta trasporta il system prompt, 49 turni precedenti e il nuovo messaggio: 400 + 49 × 250 + 60 = 12,710 token di input, per ottenere una risposta di 190 token. Somma l'intera chat. Il system prompt e il nuovo messaggio vengono inviati ogni volta: 50 × 460 = 23,000. La cronologia ripetuta aggiunge 250 × 1,225 = 306,250. In totale: 23,000 + 306,250 = 329,250 token di input, contro 50 × 190 = 9,500 token di output.
La cronologia in ogni richiesta cresce di un turno, quindi il totale cresce con il quadrato della lunghezza della chat. Passa da 50 a 100 turni e la parte di cronologia ripetuta quadruplica all'incirca.
Provalo tu stessoProva: se inviassi solo il system prompt, gli ultimi 4 turni e il nuovo messaggio, quanti token di input trasporterebbe il turno 50?Mostra risposta
1.460 (400 + 4 × 250 + 60), contro 12.710 con la cronologia completa. Stessa domanda, stessa lunghezza della risposta, una frazione dell'input.
Opzione 1: una finestra scorrevole#
L'idea: invia sempre il system prompt, scarta tutto tranne gli ultimi N turni. Conservi la cronologia completa nel tuo storage e tagli solo la copia che invii.
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):]Chiamalo dopo aver aggiunto il nuovo messaggio dell'utente. Con keep_pairs=4 sono 4 coppie utente/assistant più il nuovo messaggio, 9 messaggi, e la slice inizia sempre su un messaggio utente. Ecco come si inserisce in una chiamata reale:
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 riga print è quella utile: guarda il primo numero. Senza il taglio sale a ogni turno. Con la finestra smette di crescere una volta che la chat supera il turno 4.

In numeri: dal turno 5 in poi, ogni richiesta è di 400 + 4 × 250 + 60 = 1,460 token di input. I primi quattro turni crescono ancora normalmente e sommano a 3.340. L'intera chat: 3,340 + 46 × 1,460 = 70,500 token di input, circa un quinto dei 329.250 che invii con la cronologia completa. L'output resta 50 × 190 = 9,500.

Nel codice, l'intera modifica è un argomento nella chiamata:
Confronta
La modifica in una riga
Prima
messages=historyDopo
messages=trim_history(history)Il problema: una finestra dimentica. Se l'utente chiede al turno 40 "qual era il mio numero d'ordine?" e il numero era nel turno 3, il modello non l'ha mai visto. Due soluzioni economiche. Estrai i fatti stabili (nome, numero d'ordine, piano) dalla chat nel tuo codice e aggiungili al system prompt, dove la finestra non li taglia mai. Oppure aggiungi un riassunto, che è l'opzione successiva.
Opzione 2: un riassunto dei vecchi turni#
Invece di scartare i vecchi turni, li comprimi. Ogni pochi turni, invii al modello i turni appena usciti dalla finestra, più il riassunto corrente, e chiedi un nuovo riassunto breve. Poi inserisci quel riassunto nel messaggio di sistema.
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}] + recentIl riassunto non è gratis: è una chiamata extra al modello. Supponi un riassunto di circa 300 token, aggiornato ogni 5 turni (9 volte in 50 turni), con ogni aggiornamento che legge circa 1.600 token (il vecchio riassunto più cinque turni più l'istruzione) e ne scrive 300. Per stare sul sicuro, conta il riassunto in ogni richiesta dal turno 5 in poi (in realtà compare dopo il primo aggiornamento, quindi è una leggera sovrastima): 400 + 300 + 4 × 250 + 60 = 1,760 token di input.
Totali per la chat: richieste principali 3,340 + 46 × 1,760 = 84,300 token di input, chiamate di riassunto 9 × 1,600 = 14,400 di input e 9 × 300 = 2,700 di output. Complessivamente 84,300 + 14,400 = 98,700 token di input e 9,500 + 2,700 = 12,200 token di output.
Il riassunto costa un po' più della sola finestra e in cambio il modello sa ancora cosa è successo nel turno 3.
Quanto costano le tre configurazioni#
Ecco la stessa chat di 50 turni su DeepSeek-V4-Flash, prezzata dal vivo dai totali sopra:
I prezzi provengono dal listino live, quindi i numeri si aggiornano quando cambia la tariffa. L'ordine no: la finestra invia il minimo, il riassunto sta nel mezzo, la cronologia completa è la più costosa.
Per una chat come questa, il modello CheapTokens da cui partire è DeepSeek-V4-Flash. Ha una finestra di contesto di 380K (una chat di 50 turni ci sta anche senza taglio), fino a 32.768 token di output per risposta, un prezzo fisso a qualsiasi ora del giorno e, in totale, contando insieme input e output, è più economico di OpenRouter. L'id del modello è deepseek-. Se vuoi confrontare i modelli sulla configurazione a finestra (1.410 token di input per richiesta in media, 190 di output, 50 richieste), ecco la tabella live:
| Modello | Input $/1M | Output $/1M | Per richiesta | 50 richieste | OpenRouter, 50 richieste |
|---|---|---|---|---|---|
| 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 |
1410 token di input e 190 token di output per richiesta. I prezzi per 1M di token sono attuali e cambiano insieme alle nostre tariffe; la colonna OpenRouter mostra i prezzi di riferimento per lo stesso carico di lavoro.
GLM-5.3-Flash ha un contesto di 390K e MiniMax-M2.7 di 180K, sufficiente per una chat con taglio. I prezzi attuali sono sulla pagina dei prezzi, e la documentazione mostra come inviare la prima richiesta.
Quale scegliere#
La finestra è la scelta predefinita: tre righe di codice, nessuna chiamata extra, nessuna modalità di errore aggiuntiva. Usala per bot di supporto, tutor e role-play, dove gli ultimi turni portano la conversazione e il system prompt porta le regole. Aggiungi il riassunto quando gli utenti fanno riferimento a cose dette molto tempo prima, come in un assistente personale con un'unica conversazione senza fine. Mantieni la finestra abbastanza piccola perché il modello veda ancora il contesto immediato, e abbastanza grande da contenere un intero scambio domanda-risposta. Quanto ci sta in tutto è un limite a parte, trattato in cos'è una finestra di contesto.
Verifica rapida
L'utente chiede al turno 40 un numero d'ordine fornito nel turno 3. Usi una finestra di 4 turni senza riassunto. Cosa succede?
Mostra risposta
Risposta: Il modello non può vederlo, perché il turno 3 è stato tagliato dalla richiesta
L'API è stateless. Il modello vede solo ciò che è nella richiesta, quindi i fatti che ti servono ancora devono restare nel system prompt o in un riassunto.



