Memoria IA: cronologia conversazioni e token
Punti chiave da ricordare: Dare memoria a un'IA conversazionale si basa su tre meccanismi: una sliding window con priorità (system prompt + ultimi scambi sempre inclusi), un budget di token controllato per gestire i costi (una conversazione di 10 scambi costa 5 volte di più), e un sistema di fallback tra modelli LLM per garantire la disponibilità. Questa è la differenza tra uno strumento e un vero assistente.
La prima versione dell'IA in TAMSIV era amnesica. "Aggiungi del pane alla mia lista della spesa" funzionava perfettamente. Ma proseguire con "Mettila per domani" falliva miseramente — l'IA non sapeva di quale attività si stesse parlando. Ogni scambio ripartiva da zero.
Questo problema è fondamentale in qualsiasi applicazione IA conversazionale. I LLM non hanno alcuna memoria nativa. Ad ogni richiesta, è necessario inviare l'intero contesto. E questo cambia tutto — in termini di UX, costo e architettura.
Ecco come ho dato memoria all'IA di TAMSIV.
Perché i LLM non hanno memoria?
È controintuitivo quando si usa ChatGPT o Claude, ma questi modelli non hanno alcuna persistenza tra le richieste. Ogni chiamata API è indipendente. La "memoria" che percepisci in una conversazione ChatGPT, è l'applicazione che invia la cronologia completa ad ogni messaggio.
Concretamente, quando invii il tuo 5° messaggio in una conversazione, l'API riceve:
- Il system prompt (le istruzioni di comportamento)
- Il messaggio 1 + la risposta 1
- Il messaggio 2 + la risposta 2
- Il messaggio 3 + la risposta 3
- Il messaggio 4 + la risposta 4
- Il tuo messaggio 5
Ad ogni scambio aggiuntivo, il payload cresce. E con esso, due problemi: la finestra di contesto (limite tecnico del modello) e il costo in token (ogni token viene fatturato).
Questo è ciò che la documentazione di OpenAI chiama gestione dello stato della conversazione.
Come funziona la sliding window di TAMSIV?
La soluzione classica è la sliding window: si mantengono solo gli ultimi N scambi. Ma una finestra scorrevole grezza è troppo semplicistica per un'app come TAMSIV, dove l'IA deve comprendere riferimenti ad azioni passate.
Ho implementato una sliding window con priorità:
- Priorità massima: il system prompt (sempre incluso, mai troncato)
- Priorità alta: gli ultimi 2 scambi (il contesto immediato)
- Priorità alta: le function calls e i loro risultati (le azioni eseguite — creazione di attività, modifica di memo, ecc.)
- Priorità media: gli scambi precedenti (da 3 a N-2)
- Priorità bassa: gli scambi più vecchi, riassunti o eliminati in base al budget di token
Perché le function calls sono prioritarie? Perché in TAMSIV, quando l'utente dice "Modifica la priorità dell'attività che abbiamo appena creato", l'IA deve sapere quale attività è stata creata. Questa informazione si trova nel function_result di uno scambio precedente. Senza di essa, l'IA non può risolvere il pronome "la".
Come gestire il budget dei token senza far esplodere i costi?
Questo è il nocciolo della questione. Una conversazione di 10 scambi può costare 5 volte di più di uno scambio isolato, perché il payload cumulativo viene inviato ogni volta.
Esempio concreto con un modello a 0.001$ / 1000 token:
- Scambio 1: ~500 token (system prompt + messaggio) = 0.0005$
- Scambio 5: ~2500 token (cronologia 1-4 + messaggio 5) = 0.0025$
- Scambio 10: ~5000 token (cronologia 1-9 + messaggio 10) = 0.005$
- Totale conversazione 10 scambi: ~25 000 token cumulati = 0.025$
Per un'app con migliaia di utenti, questi centesimi si sommano rapidamente. Ho implementato tre salvaguardie:
- Limite di 20 scambi per conversazione: oltre, si consiglia di avviare una nuova conversazione. Questo evita conversazioni-mostro di 100 scambi.
- Contatore di token stimato: prima di ogni chiamata, il backend stima il numero di token del payload completo. Se supera il budget, gli scambi più vecchi vengono troncati.
- Scelta del modello in base alla complessità: un messaggio semplice ("Aggiungi del pane") utilizza un modello leggero. Una richiesta complessa ("Riorganizza le mie attività della settimana per priorità") utilizza un modello più potente.
Come funziona il fallback tra modelli LLM?
In produzione, l'affidabilità non è negoziabile. Se il modello principale (configurato tramite OPENROUTER_MODEL) restituisce un errore 429 (rate limit) o 503 (servizio non disponibile), l'utente non deve accorgersene.
Il backend di TAMSIV implementa un fallback automatico:
- Chiamata al modello principale tramite OpenRouter
- Se errore 429/503 → riprova con
OPENROUTER_FALLBACK_MODEL - L'
AlertServiceinvia un'email all'amministratore per segnalare il fallback - L'utente riceve la sua risposta normalmente — nessuna degradazione percepibile
In produzione, TAMSIV effettua 2 o 3 fallback a settimana. È minimo, ma succede. Senza questo meccanismo, l'utente vedrebbe un messaggio di errore generico — e probabilmente lascerebbe l'app.
La scelta di OpenRouter come proxy LLM (piuttosto che chiamare direttamente l'API OpenAI o Anthropic) è strategica: permette di cambiare modello senza modificare il codice. Se esce un nuovo modello, basta cambiare una variabile d'ambiente. La pipeline vocale completa rimane identica.
Che impatto ha la memoria sull'esperienza utente?
La differenza è spettacolare. Prima della cronologia delle conversazioni, ogni scambio era indipendente. Dopo, l'IA diventa un vero assistente:
- "Modifica la priorità dell'attività che abbiamo appena creato" → l'IA sa quale attività, e la modifica
- "Alla fine, mettila per venerdì" → l'IA capisce che "la" si riferisce all'ultimo evento creato
- "Aggiungi anche un memo su questo" → l'IA riprende l'argomento della conversazione per creare il memo
- "No, ho detto domani, non dopodomani" → l'IA corregge comprendendo il riferimento temporale
Questa è la differenza tra un modulo vocale (ripeti tutto ogni volta) e un assistente che ascolta e ricorda. Questo è ciò che rende il Dittafono di TAMSIV utilizzabile quotidianamente.
Come il system prompt influenza la qualità delle risposte?
Il system prompt è il documento più importante dell'applicazione. È quello che definisce il comportamento dell'IA: tono, formato di risposta, function tools disponibili, vincoli.
Il system prompt di TAMSIV include:
- La persona: "Sei l'assistente vocale di TAMSIV, un'applicazione di gestione delle attività e dei memo."
- I function tools: le 7 funzioni che l'IA può chiamare (
create_task,update_task,create_memo,update_memo,create_calendar_event,ask_clarification,end_conversation) - I vincoli: risposte brevi (l'utente ascolta tramite TTS), nessun markdown, nessuna lista lunga
- Il contesto utente: la lingua preferita, il fuso orario, il piano (Free/Pro/Team)
Un system prompt ben progettato riduce drasticamente le allucinazioni e le risposte fuori tema. È un investimento che si riflette su ogni conversazione.
Come gestire le conversazioni multimodali (voce + testo)?
In TAMSIV, l'utente parla ma l'IA risponde con la voce (tramite OpenAI TTS) E con il testo (visualizzato sullo schermo). La cronologia memorizza entrambe le forme:
- Lato utente: il testo trascritto dallo STT (non l'audio grezzo — troppo pesante in token)
- Lato IA: il testo della risposta (inviato al TTS e visualizzato)
La pipeline completa è: Audio → STT → Testo → LLM (con cronologia) → Testo → TTS → Audio. La cronologia vive solo nello strato testuale, il che semplifica enormemente l'architettura.
Quali alternative alla sliding window esistono?
La sliding window non è l'unico approccio. Esistono altre strategie:
- Summarization: riassumere gli scambi precedenti in un paragrafo condensato. Vantaggio: massima compressione. Svantaggio: perdita di dettagli e una chiamata LLM aggiuntiva per il riassunto.
- RAG (Retrieval Augmented Generation): memorizzare la cronologia in un database vettoriale e recuperare solo gli scambi pertinenti per similarità semantica. Potente ma pesante da implementare.
- Memoria esplicita: memorizzare "fatti" estratti dalle conversazioni (preferenze utente, attività ricorrenti) in un database strutturato. Questo è ciò che fa ChatGPT con la sua funzione "Memory".
Per TAMSIV, la sliding window con priorità è il miglior compromesso: semplice da implementare, efficiente in termini di token e sufficiente per conversazioni da 5 a 15 scambi. Se le conversazioni diventassero molto più lunghe, prenderei in considerazione il RAG.
Come implementare una cronologia delle conversazioni nel tuo progetto?
Se stai costruendo un'app con un LLM, ecco i passaggi:
- Memorizza la cronologia lato server: non fidarti mai del client per mantenere lo stato della conversazione. Il backend è la fonte della verità.
- Implementa una sliding window: inizia in modo semplice (mantenendo gli ultimi N scambi), quindi aggiungi le priorità se necessario.
- Budgetizza i token: conta i token prima di ogni chiamata. Tronca in modo intelligente se il budget viene superato.
- Aggiungi un fallback: almeno, un modello di backup in caso di errore del modello principale.
- Misura i costi: registra ogni chiamata con il numero di token utilizzati. Questo permette di ottimizzare il sistema nel tempo.
La dashboard di amministrazione di TAMSIV mostra le metriche delle conversazioni in tempo reale: numero medio di scambi, costo medio per conversazione, tasso di fallback. Questi dati sono essenziali per ottimizzare i costi in produzione.
FAQ
Quanti scambi fa un utente medio per conversazione?
In TAMSIV, la media è di 3-5 scambi. L'utente tipico dice "Aggiungi un'attività per domani: chiamare il dentista", conferma l'anteprima e prosegue con una modifica ("Mettila in alta priorità"). Le conversazioni lunghe (10+ scambi) rappresentano meno del 10% del volume.
Il costo della cronologia delle conversazioni è significativo?
Sì, è la principale voce di spesa della pipeline IA. Ogni scambio aggiuntivo aumenta il costo cumulativo. Per TAMSIV, il costo medio per conversazione è di circa 0.01-0.03 EUR con il modello principale. Il modello di fallback è generalmente più economico, il che compensa parzialmente i costi aggiuntivi.
È necessario memorizzare la cronologia nel database?
Per TAMSIV, la cronologia vive in memoria (lato backend) durante la sessione WebSocket. Non viene persistita nel database — quando la connessione si chiude, la cronologia viene persa. Questa è una scelta deliberata: le conversazioni sono brevi e transitorie. Se hai bisogno di riprendere conversazioni in seguito, dovrai persistere nel database.
OpenRouter vs chiamare direttamente le API dei fornitori LLM?
OpenRouter agisce come un proxy che unifica l'accesso a decine di modelli (OpenAI, Anthropic, Google, ecc.) tramite una singola API. Il vantaggio: cambiare modello senza modificare il codice. Lo svantaggio: uno strato aggiuntivo (latenza marginale). Per un'app come TAMSIV che necessita di flessibilità e fallback, è una scelta ovvia.
La memoria di conversazione funziona con la modalità Realtime?
TAMSIV ha tre modalità WebSocket. In modalità LiveWebSocket (la modalità predefinita), la cronologia è gestita manualmente come descritto in questo articolo. In modalità Realtime (OpenAI Realtime API), la cronologia è gestita nativamente dall'API — è un protocollo bidirezionale con stato. La modalità legacy funziona in batch senza persistenza.