Data di pubblicazione: 30 aprile 2026
Grazie all'AI integrata, il tuo sito web o la tua applicazione web può eseguire attività basate sull'AI, senza dover eseguire il deployment, gestire o ospitare autonomamente i modelli. Potresti trovare difficile passare da una demo a una funzionalità pronta per la produzione. Questo documento tratta considerazioni tecniche e UX per aiutarti a evitare gli errori più comuni.
Prepara il modello in un momento ragionevole
Applicabile a: tutte le API, ad esempio Summarizer, Translator e Writer.
Azione consigliata:inizializza la sessione non appena hai stabilito chiaramente l'intenzione dell'utente di utilizzare la funzionalità di AI, ad esempio quando un utente naviga in una superficie di strumenti di AI pertinente, passa il mouse sopra uno spazio di lavoro AI o interagisce con l'interfaccia utente circostante della funzionalità. Il pre-riscaldamento della sessione consente al modello di caricarsi in memoria in modo silenzioso in background mentre l'utente configura l'attività, eliminando la latenza di avvio a freddo evitabile. Cerca di anticipare i tempi iniziando la successiva attività AI più probabile non appena inizi il rendering del risultato corrente, ad esempio se la funzionalità è progettata per un utilizzo iterativo.
Non:a meno che non sia necessario, non attendere che l'utente faccia clic su "Genera" per inizializzare la sessione. Ciò comporta un ritardo di avvio a freddo, perché il modello deve prima essere caricato in memoria e preparare la pipeline di esecuzione.
Impostare i prompt iniziali durante la creazione
Si applica all'API Prompt.
Azione consigliata: fornisci le istruzioni di sistema durante l'inizializzazione della sessione per migliorare la velocità del primo prompt.
Non:iniziare con una sessione vuota e inviare le istruzioni di sistema nell'ambito della prima chiamata prompt(). Ciò aumenta la latenza perché costringe il modello a
elaborare queste istruzioni all'ultimo momento.
// ✅ DO: Create the session as early as possible (tip on warming up the model early) and use initialPrompts for system instructions in the create call
const session = await LanguageModel.create({
initialPrompts: [
{ role: 'system', content: 'You are a helpful assistant specialized in code reviews.' }
]
});
// A few moments later, when the user triggers the AI feature
const review = await session.prompt(`Review the following code:\n\n${code}`);
// ❌ DON'T: Send instructions using prompt() after creation
// const slowerSession = await LanguageModel.create();
// await slowerSession.prompt(`You are a helpful assistant specialized in code reviews.\n\nReview the following code:\n\n${code}`); // Higher latency
Clonare le sessioni per le attività ripetitive
Si applica all'API Prompt.
Per l'API Prompt, ogni sessione tiene traccia del contesto della conversazione, tenendo conto di tutte le interazioni precedenti. Poiché un clone eredita tutto dalla sessione principale, inclusi i prompt iniziali e tutta la cronologia delle interazioni fino al momento della clonazione, struttura l'utilizzo in modo da ereditare solo ciò che ti serve.
Azione consigliata:
- Crea una sessione di base: per gestire in modo efficiente attività non correlate, crea una sessione di base che contenga solo le istruzioni di sistema e nessun contesto conversazionale precedente.
- Clona la base: utilizza
clone()nella sessione di base per le nuove attività per risparmiare il sovraccarico dell'analisi delle istruzioni di sistema. In questo modo puoi creare conversazioni parallele o reimpostare un'attività sulla sua baseline.
Azione sconsigliata:
- Non riutilizzare la stessa sessione per attività non correlate ed evita di clonare sessioni che contengono già una cronologia delle interazioni non necessaria. Entrambi i pattern possono causare l'interferenza di un contesto precedente non correlato con l'attività attuale.
- Non chiamare ripetutamente
create()con istruzioni di sistema identiche. Utilizza invece il pattern di clonazione per ottimizzare il rendimento.
// ✅ DO: Create a baseline session and clone it for each new task
const baseSession = await LanguageModel.create({
initialPrompts: [{
role: 'system',
content: 'You are a technical editor...',
}],
});
// Clone the base session once for the first task
const task1 = await baseSession.clone();
const response1 = await task1.prompt("Review this first draft...");
// ... Repeat the cloning pattern for subsequent independent tasks
// Each task starts fresh from the baseline system instructions
// ❌ DON'T:
// Bad performance pattern: repeated create() calls for identical tasks.
// This forces the model to re-parse instructions every time, increasing latency.
// const sessionA = await LanguageModel.create({ initialPrompts: [...] });
// await sessionA.prompt("Task 1...");
// const sessionB = await LanguageModel.create({ initialPrompts: [...] });
// await sessionB.prompt("Task 2...");
// Bad quality pattern: reusing the same session for unrelated tasks.
// const session = await LanguageModel.create();
// await session.prompt("Analyze this financial report...");
// Unrelated task in the same session:
// await session.prompt("Now write a children's story...");
Eliminare le sessioni inutilizzate
Applicabile a: tutte le API.
Azione consigliata:chiama esplicitamente destroy() sulle sessioni che non ti servono più per liberare memoria quando una funzionalità non è più in uso. Se utilizzi un pattern di clonazione, mantieni la sessione di base ed
elimina i cloni che non ti servono più.
Non:mantenere attive più sessioni di grandi dimensioni. Ogni sessione consuma memoria,
il che crea un utilizzo non necessario delle risorse e potrebbe diventare un problema. Le sessioni
verranno pulite naturalmente dal Garbage Collector, ma chiamando destroy()
la memoria viene liberata più rapidamente.
// ✅ DO: Use the clone and destroy it immediately after
const clone = await baseSession.clone();
const response = await clone.prompt("Quick task...");
// Free memory right away: destry the clone, keep the baseSession
clone.destroy();
Eseguire il rendering delle risposte in streaming in modo sicuro ed efficiente
Si applica a: tutte le API con supporto dello streaming (Prompt, Summarizer, Writer, Rewriter e Translator).
Azione consigliata:considera tutto l'output del modello LLM come contenuti non attendibili. Sanitizza l'output combinato completo, non solo i blocchi, perché il codice dannoso potrebbe essere suddiviso tra gli aggiornamenti. Prima del rendering, utilizza l'API Sanitizer dove supportata. Per evitare una riduzione del rendimento, utilizza un parser Markdown per lo streaming come streaming-markdown.
Non impostare direttamente innerHTML a ogni aggiornamento del blocco. Questo metodo è lento,
soprattutto con formattazione complessa come l'evidenziazione della sintassi, ed è vulnerabile
all'iniezione.
import * as smd from "streaming-markdown";
// Set up virtual buffer and Sanitizer API
const sanitizer = new Sanitizer({
allowElements: ['figure', 'figcaption', 'p', 'br', 'strong', 'em', 'img', 'a'],
allowAttributes: {
'loading': ['img'], 'decoding': ['img'], 'src': ['img'], 'href': ['a']
}
});
// Create an off-screen fragment so the parser doesn't cause flicker
// or trigger XSS in the live DOM during the building process.
const buffer = new DocumentFragment();
const parser = smd.parser_new(buffer);
// Use sanitizer as a gatekeeper / cleaner function so we can combine it with the streaming Markdown parser
function syncSanitized(target, sourceFragment) {
// .sanitize() returns a fresh, clean DocumentFragment
const cleanFragment = sanitizer.sanitize(sourceFragment);
// replaceChildren is the modern high-performance way to swap DOM content
target.replaceChildren(cleanFragment);
}
// Streaming Logic
// `chunks` keeps track of the raw string (useful for logs/debug)
chunks += chunk;
// Let the parser build the DOM incrementally in the buffer.
// This is high-performance because the buffer is not live
smd.parser_write(parser, chunk);
// Use the Sanitizer API to port the content safely to the container.
syncSanitized(container, buffer);
Ottimizzare l'input per la velocità
Applicabile a: tutte le API.
Azione consigliata:trasmetti al modello solo ciò che è strettamente necessario. Elimina tutto ciò che non è pertinente all'attività in questione. Per set di dati di grandi dimensioni, fornisci una breve panoramica e una piccola selezione di elementi pertinenti.
Non inviare alle API testo non elaborato, metadati non necessari, tag HTML o elenchi di grandi dimensioni non filtrati. La latenza aumenta in modo significativo con le dimensioni dell'input, il che può far sembrare che la funzionalità di AI non funzioni su molti dispositivi.
// ✅ DO: Send only relevant text
const cleanText = document.querySelector('#article').innerText;
const summary = await Summarizer.summarize(cleanText);
// ❌ DON'T: Send the entire DOM structure
// const dirtyText = document.querySelector('#article').innerHTML;
Utilizzare l'output strutturato per risultati prevedibili
Si applica all'API Prompt.
Azione consigliata:quando vuoi che il modello restituisca dati in un formato specifico, utilizza l'output strutturato fornendo un campo responseConstraint per fornire uno schema JSON. In questo modo
l'output è prevedibile e non è necessario eseguire post-elaborazioni complesse
o analisi manuali.
Non fare affidamento solo su istruzioni in linguaggio naturale (come "output solo JSON"). I modelli potrebbero includere riempitivi conversazionali che interrompono l'analisi.
// ✅ DO: Use a JSON Schema for predictable results
const schema = {
type: "object",
properties: {
isTopicCats: { type: "boolean" }
}
};
const result = await session.prompt(`Is this post about cats?\n\n${post}`, {
responseConstraint: schema,
});
console.log(JSON.parse(result).isTopicCats);
Disaccoppia la generazione dai vincoli di lunghezza
Si applica all'API Prompt, in quanto è l'unica API che supporta gli schemi di output strutturato.
Azione consigliata:lascia che il modello generi la risposta in modo naturale, quindi utilizza la logica lato client per troncare il testo in modo che si adatti alla tua UI.
Non:applicare limiti di caratteri rigidi come maxLength: 125 utilizzando
schemi di output strutturato. Quando la risposta di un modello supera il limite impostato, il modello potrebbe passare a token ad alta densità, come lingue straniere o emoji, per comprimere il significato, con conseguente output senza senso.
/* DO: Handle overflow using CSS */
.result {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis; /* Displays '…' */
}
// ❌ DON'T: Force length in the prompt
const result = await session.prompt("Write a bio in exactly 50 characters.");
Tieni informato l'utente
Applicabile a: tutte le API.
Consiglio:a seconda della complessità e della durata prevista dell'attività, utilizza animazioni, segnali visivi e indicatori di avanzamento per tenere informato l'utente. L'approccio ottimale dipende dal tuo caso d'uso e dalla lunghezza prevista dell'output dell'API. Ecco alcune idee:
- Streaming per contenuti lunghi: per i riepiloghi o la chat, lo streaming crea un effetto macchina da scrivere per token per impostazione predefinita. In questo modo, la conversazione sembrerà naturale e potrai ricevere un feedback immediato.
- Non in streaming per attività brevi (o attività asincrone lunghe): per output brevi, ad esempio testo alternativo, il non in streaming può creare una UI più raffinata. Inoltre, offre il tempo di preparare in modo speculativo la prossima attività di AI mentre viene eseguita quella attuale. Questo approccio funziona anche per attività asincrone o in background più lunghe. Se l'utente non è bloccato nell'output per continuare il suo percorso, non è necessario produrre l'output in tempo reale. Indica che la procedura è in corso nell'UI.
- Transizioni visive per gli aggiornamenti: quando traduci o riscrivi il testo, utilizza animazioni, ad esempio la trasformazione delle parole.
Azione sconsigliata: aggiorna la UI senza segnali visivi.
Allinearsi al modello mentale di tempo e lavoro dell'utente
Applicabile a: tutte le API.
Azione consigliata: considera un ritardo artificiale di uno o due secondi se una risposta è quasi istantanea. Paradossalmente, gli utenti potrebbero trovare i risultati più attendibili quando percepiscono un processo di generazione in linea con la difficoltà percepita dell'attività. Utilizza le animazioni per segnalare che è stato eseguito un processo di AI.
Non:sorprendere gli utenti con sostituzioni immediate dell'interfaccia utente.
Consenti agli utenti di navigare rapidamente e annullare le modifiche dell'AI
Applicabile a: tutte le API.
Azione consigliata:dota la tua UI di un cursore o di una cronologia di navigazione che consenta agli utenti di esplorare diversi risultati in modo sicuro e di annullare rapidamente le modifiche apportate dall'AI. In questo modo, le diverse versioni sono sempre facilmente disponibili.
Non sovrascrivere la bozza precedente dell'utente o un risultato dell'AI che potrebbe aver apprezzato senza un modo per tornare indietro, ripristinare o confrontare le versioni.
Consentire il controllo e gli override da parte degli utenti
Applicabile a: tutte le API.
Azione:imposta l'utente come editor finale di tutti i contenuti generati. Fornisci override intuitivi in modo che l'utente mantenga la piena proprietà dell'output finale. Le API potrebbero produrre risultati errati.
Non:imporre un risultato generato dall'AI come unica opzione.
Memorizza nella cache i risultati per le attività ripetute
Applicabile a: tutte le API.
Azione consigliata:implementa una cache dei risultati locali (ad esempio utilizzando sessionStorage o
IndexedDB) per input o query ripetuti. Normalizza l'input eliminando
gli spazi bianchi e convertendo il testo in minuscolo per aumentare i successi della cache. Per gli input pesanti, ad esempio le immagini, genera un hash da utilizzare come chiave della cache. Imposta una durata (TTL) conservativa per la cache (o pubblica i risultati memorizzati nella cache durante l'aggiornamento in background). Consenti all'utente di attivare una nuova inferenza se il risultato non è
soddisfacente.
Non: eseguire di nuovo la stessa inferenza per una query di ricerca ripetuta o un input di dati identico in cui la variabilità non è auspicabile, ad esempio quando un utente naviga avanti e indietro tra i risultati di ricerca. In questo modo si ottimizzano la reattività e l'utilizzo efficiente del calcolo locale.
// ✅ DO: Check a local cache before running inference
async function getAiResponse(userInput, forceRefresh = false) {
// Normalize the query to increase cache hits
const query = userInput.trim().toLowerCase();
const cacheKey = `ai_results_${query}`;
const TTL_MS = 3600000; // 1 hour conservative TTL
if (!forceRefresh) {
const itemStr = localStorage.getItem(cacheKey);
if (itemStr) {
const item = JSON.parse(itemStr);
const now = Date.now();
// Check if the item has expired
if (now < item.expiry) {
// Lightweight safety check before rendering
if (isValid(item.value)) return item.value;
} else {
// Delete the stale entry if the TTL has passed
localStorage.removeItem(cacheKey);
}
}
}
// Fallback: Run inference if no valid cache exists
const session = await LanguageModel.create();
const response = await session.prompt(userInput);
// Store the result for future use (with an expiration)
const cacheData = {
value: response,
expiry: Date.now() + TTL_MS
};
localStorage.setItem(cacheKey, JSON.stringify(cacheData));
return response;
}