Data di pubblicazione: 23 giugno 2026
Ogni sessione di LanguageModel ha una finestra di contesto finita. Man mano che una conversazione cresce, il modello accumula l'intera cronologia dei messaggi
nel suo contesto: ogni prompt dell'utente e ogni risposta dell'assistente. Quando la finestra
si riempie, viene attivata la gestione automatica del overflow del browser. Elimina le coppie di messaggi più vecchie, una coppia di prompt e risposta alla volta, per liberare spazio per il nuovo prompt. Se il prompt in entrata è così grande che non ci sta nemmeno rimuovendo l'intera cronologia della conversazione, la chiamata non riesce e viene visualizzato un QuotaExceededError.
La compressione delle sessioni è un'alternativa proattiva: riepiloga la cronologia della conversazione con l'API Summarizer, quindi riavvia una nuova sessione utilizzando questi riepiloghi come initialPrompts. Il browser non espelle mai
initialPrompts durante la gestione dell'overflow di runtime, quindi il riepilogo compresso
rimane ancorato in modo permanente nel contesto del modello, a condizione che i riepiloghi
stessi rientrino nella finestra contestuale quando viene chiamato create(). La nuova
sessione mantiene lo stesso thread conversazionale a una frazione del costo
originale dei token.
La compattazione delle sessioni consente alle conversazioni LanguageModel di lunga durata di rimanere all'interno della finestra contestuale senza perdere la continuità. I passaggi principali sono:
- Monitora
contextUsagerispetto acontextWindowe mostralo all'utente. - Ascolta l'evento
contextoverflowcome avviso tempestivo. - Rileva la lingua di ogni messaggio con l'API Language Detector, quindi riassumilo con un'istanza dell'API Summarizer che riconosce la lingua.
- Distruggi la vecchia sessione e creane una nuova con
initialPrompts. - Conserva una copia di
fullHistoryper il recupero degli errori.
Monitorare l'utilizzo del contesto
L'API Prompt espone due attributi per monitorare il livello di completezza del contesto di una sessione:
session.contextUsage: il numero di token attualmente consumati.session.contextWindow: la capacità totale di token della sessione.
Rifletti questo aspetto in un elemento <progress> in modo che gli utenti sappiano a colpo d'occhio quanto la sessione si avvicina al limite. Imposta value e max direttamente sui conteggi dei token; il
browser ridimensiona automaticamente la barra:
<progress id="token-bar" value="0" max="1"></progress>
<label for="token-bar" id="token-label">Context: — / — tokens</label>
function updateTokenDisplay(session) {
const usage = session.contextUsage;
const total = session.contextWindow;
tokenBar.value = usage;
tokenBar.max = total;
tokenLabel.textContent =
`${Math.round(usage)} / ${Math.round(total)} tokens ` +
`(${Math.round((usage / total) * 100)}%)`;
}
Chiama updateTokenDisplay() dopo ogni risposta al prompt in modo che la barra rimanga
aggiornata.
Ascolta il contesto in overflow
Quando un nuovo prompt supera il contesto rimanente, inizia il recupero automatico del browser: vengono rimosse le coppie di prompt e risposte più vecchie una alla volta finché non viene liberato spazio sufficiente. L'evento contextoverflow viene attivato nel momento in cui inizia
l'espulsione. Registra un gestore subito dopo aver creato la sessione:
session.addEventListener('contextoverflow', () => {
showWarning('⚠ Context window nearly full. Consider compacting the session.');
});
Esistono due proprietà importanti di questo comportamento di sfratto:
initialPromptsnon vengono eliminati al runtime. Il browser non li rimuove per fare spazio a un prompt in arrivo. Tuttavia, se la dimensione combinata diinitialPromptspassata aLanguageModel.create()è troppo grande per rientrare nella finestra contestuale,create()rifiuta con unQuotaExceededError, quindi assicurati che la compattazione sia sufficientemente piccola da consentire di continuare la conversazione.- Lo sfratto ha un limite. Se il prompt in entrata è così grande che la rimozione
dell'intera conversazione precedente non è sufficiente, la chiamata
prompt()opromptStreaming()non va a buon fine e viene visualizzato un messaggioQuotaExceededErrore non viene rimosso nulla.
Scopri di più sulla gestione dell'overflow del contesto nella documentazione dell'API Prompt.
Utilizza l'evento contextoverflow per avvisare l'utente, disattivare il pulsante di invio o
attivare automaticamente la compattazione prima che il browser inizi a eliminare silenziosamente
la cronologia delle conversazioni.
Comprimere la sessione
La compattazione prevede tre passaggi:
- Riassumi ogni messaggio nella cronologia della conversazione con l'API Summarizer.
- Distruggi la vecchia sessione.
- Crea una nuova sessione con i riepiloghi come
initialPrompts.
Riassumere la cronologia
L'API Summarizer è ideale per comprimere i singoli messaggi di chat. Per ogni messaggio, rileva innanzitutto la lingua con l'API Language Detector in modo che il riepilogo possa essere configurato correttamente:
async function detectLanguage(text, threshold = 0.7) {
const detector = await LanguageDetector.create();
const results = await detector.detect(text);
if (results.length > 0 && results[0].confidence >= threshold) {
return results[0].detectedLanguage;
}
return null; // confidence too low — caller falls back to navigator.language
}
La soglia di confidenza 0.7 evita di agire in base a rilevamenti incerti. Quando
il livello di confidenza è inferiore alla soglia, torna a navigator.language.
Successivamente, crea un riepilogatore configurato per la lingua rilevata. Preferisci
preference: 'speed' per selezionare la variante del modello più piccola e con latenza inferiore e
torna a preference: 'auto' se il modello più veloce non supporta la
lingua rilevata:
const summarizers = {}; // cache, keyed by `${format}:${lang}`
async function getSummarizer(format, lang) {
const key = `${format}:${lang}`;
if (summarizers[key]) return summarizers[key];
const baseOptions = {
type: 'tldr',
format, // 'markdown' or 'plain-text'
length: 'short',
expectedInputLanguages: [lang],
expectedContextLanguages: [lang],
outputLanguage: lang,
};
let options = { ...baseOptions, preference: 'speed' };
let avail = await Summarizer.availability(options);
if (avail === 'unavailable') {
options = { ...baseOptions, preference: 'auto' };
avail = await Summarizer.availability(options);
}
if (avail === 'unavailable') {
throw new Error('Summarizer API unavailable on this device.');
}
summarizers[key] = await Summarizer.create(options);
return summarizers[key];
}
La memorizzazione nella cache dei riepiloghi per la coppia format+lang evita chiamate create() ridondanti
quando i messaggi consecutivi condividono la stessa lingua.
L'argomento format deriva dai contenuti del messaggio stesso. Se specifichi
'markdown' per il testo normale, puoi introdurre formattazioni indesiderate, mentre se specifichi
'plain-text' per Markdown, vengono rimossi i recinti di codice e l'enfasi. Una piccola espressione regolare
distingue le due:
function looksLikeMarkdown(text) {
return /(?:^#{1,6} |^[-*+] |\d+\. |\*\*|__|\[.+?\]\(|^> |^```)/m.test(text);
}
Una volta risolti la lingua e il formato, riepiloga ogni messaggio e passa una stringa context in modo che il modello comprenda che sta comprimendo un turno di chat, non un documento autonomo:
const compacted = [];
for (const msg of history) {
const lang = (await detectLanguage(msg.content)) ?? navigator.language;
const format = looksLikeMarkdown(msg.content) ? 'markdown' : 'plain-text';
const summarizer = await getSummarizer(format, lang);
const summary = await summarizer.summarize(msg.content.trim(), {
context:
`This is a ${msg.role} turn from a chat conversation. ` +
`Preserve its key meaning as concisely as possible.`,
});
// Only use the summary if it's actually shorter.
compacted.push({
role: msg.role,
content:
summary.trim().length < msg.content.length ? summary.trim() : msg.content,
});
}
Eliminare la vecchia sessione
Rilascia le risorse della sessione precedente prima di creare la sostituzione:
session.destroy();
session = null;
Creare una nuova sessione con la cronologia compattata
Passa i messaggi compattati come initialPrompts per inizializzare la nuova sessione con il contesto della conversazione:
// Collect every language the detector was confident about.
const sessionLangs =
confidentLangs.size > 0 ? [...confidentLangs] : [navigator.language];
session = await LanguageModel.create({
expectedInputs: [{ type: 'text', languages: sessionLangs }],
expectedOutputs: [{ type: 'text', languages: sessionLangs }],
initialPrompts: compacted,
});
// Re-register the overflow handler on the new session.
session.addEventListener('contextoverflow', () => {
/* ... */
});
La nuova sessione inizia a un contextUsage inferiore. La conversazione riprende da dove era stata interrotta: il modello ha i riepiloghi come contesto precedente, quindi può rispondere a domande aggiuntive sugli argomenti precedenti.
Gestisci gli errori
Se il riepilogo o la creazione della sessione non riesce dopo che la vecchia sessione è già stata eliminata, l'utente non può più chattare. Mantieni un array fullHistory separato che non viene mai sovrascritto dalla compattazione e utilizzalo come fallback di ripristino:
const history = []; // current session's view, replaced on each compaction
const fullHistory = []; // every original message, never overwritten
// In the catch block:
if (!session) {
session = await LanguageModel.create({
initialPrompts: fullHistory.map(({ role, content }) => ({ role, content })),
});
session.addEventListener('contextoverflow', () => {
/* ... */
});
}
Il recupero da fullHistory potrebbe riportare il contesto vicino alla capacità, ma l'utente è almeno tornato a uno stato di funzionamento e può tentare immediatamente un'altra compattazione.
(Facoltativo) Impedire la compattazione di alcuni contenuti
Se ci sono parti critiche di un messaggio che devono sempre rimanere nel contesto, ad esempio esempi di codice, elaborale separatamente. L'esempio seguente suddivide un messaggio in segmenti alternati di prosa e recinzione del codice, quindi riassume solo le parti in prosa lasciando intatti i segmenti di codice:
// Splits text into alternating prose and code-fence segments.
// Returns [{ type: 'prose'|'code', content: string }, …]
function splitByCodeFences(text) {
const parts = [];
const re = /^```[^\n]*\n[\s\S]*?^```[ \t]*$/gm;
let lastIndex = 0;
let match;
while ((match = re.exec(text)) !== null) {
if (match.index > lastIndex) {
parts.push({
type: 'prose',
content: text.slice(lastIndex, match.index),
});
}
parts.push({ type: 'code', content: match[0] });
lastIndex = match.index + match[0].length;
}
if (lastIndex < text.length) {
parts.push({ type: 'prose', content: text.slice(lastIndex) });
}
return parts;
}
Prova la demo
La demo della compattazione della sessione ti consente di chattare con l'API Prompt e compattare la sessione in qualsiasi momento. La barra dei token mostra l'utilizzo del contesto in tempo reale e cambia colore man mano che il contesto si riempie. Dopo ogni compattazione, una voce di log registra i conteggi dei token prima e dopo, in modo da poter osservare direttamente la riduzione.
Puoi esaminare il JSON della conversazione completo e compresso nella sezione comprimibile Debug: JSON della conversazione in fondo alla pagina.