Il frontend era una volta una cosa fissa. I designer lo disegnavano. Gli ingegneri lo costruivano. Gli utenti ottenevano ciò che veniva spedito.
È finita.
Le interfacce che verranno spedite nel 2026 sono disegnate in parte dall'agente stesso, in tempo reale, partendo da ciò che l'utente ha effettivamente richiesto. Chiedi una tabella, ottieni una tabella. Non un paragrafo che la descrive.
La Generative UI è lo strato che permette agli agenti di smettere di descrivere e iniziare a mostrare. Sono emersi tre pattern su come costruirla, e le differenze tra di loro contano più di quanto la maggior parte dei team realizzi.
Ma non c'è un solo modo per fare questo. Ce ne sono tre. E la maggior parte dei team ne sceglie uno senza sapere di averlo fatto.
Lo stack di protocolli
Tre protocolli. Ognuno fa un lavoro.
MCP connette gli agenti agli strumenti. A2A connette gli agenti tra loro. AG-UI connette gli agenti agli utenti.
AG-UI è lo strato di streaming che trasporta tutto ciò che vedrai sotto: chiamate a strumenti, schemi A2UI, eventi MCP App, delta di stato. Funziona su SSE. Lo stato scorre in entrambe le direzioni sullo stesso flusso. L'utente modifica, l'agente vede. L'agente muta, l'utente vede.
A2UI è la specifica di Google per gli agenti che emettono UI come schema. Viaggia su AG-UI. CopilotKit lo spedisce in produzione.
Non scrivi un parser per niente di tutto questo. CopilotKit è un client AG-UI e decodifica il flusso per te.
I tre pattern che la maggior parte dei team confonde
Chiedi a dieci sviluppatori cos'è la Generative UI. Ottieni dieci risposte. La maggior parte descrive il pattern che il loro framework attuale spedisce.
Ce ne sono solo tre. Lo spettro va da più controllo a più flessibilità.
- Controllato: Pre-costruisci i componenti. L'agente sceglie quale renderizzare.
- Dichiarativo: L'agente emette uno schema. La tua app lo mappa ai componenti.
- Aperto: L'agente scrive HTML grezzo. La tua app lo renderizza in una sandbox.

Ogni framework Gen UI nel 2026 si trova da qualche parte su questa linea. Le differenze sono architetturali, non estetiche. Ogni pattern rompe la tua app in modo diverso su larga scala.
Ho provato diversi stack. La maggior parte copre bene un pattern. Ho scelto CopilotKit perché supporta tutti e tre sullo stesso runtime, viaggiando su AG-UI. Questo è lo stack su cui gira tutto ciò che segue.
Pattern 1: Controllato, il frontend possiede la UI

Qui è dove la maggior parte dei team inizia. È anche dove la maggior parte dei team si blocca.
Pre-costruisci un componente React. Lo leghi a un nome di strumento. L'agente sceglie quello strumento e il componente viene renderizzato in linea nella chat con gli argomenti dell'agente come props.
Un hook frontend. Zero codice agente. Tutto qui.
1"use client";2import { z } from "zod";3import { useComponent } from "@copilotkit/react-core/v2";45const expenseChartSchema = z.object({6 title: z.string(),7 data: z.array(z.object({ label: z.string(), value: z.number() })),8});910function ExpenseChart({ title, data }: z.infer<typeof expenseChartSchema>) {11 return (12 <section className="rounded-xl border p-4">13 <h3 className="text-sm font-medium">{title}</h3>14 <ul className="mt-2 grid gap-1">15 {data.map((d) => (16 <li key={d.label} className="flex justify-between text-sm">17 <span>{d.label}</span>18 <span>${d.value}</span>19 </li>20 ))}21 </ul>22 </section>23 );24}2526export function ExpensesCopilot() {27 useComponent({28 name: "showExpenseChart",29 description: "Renderizza una suddivisione delle spese per categoria.",30 parameters: expenseChartSchema,31 render: ExpenseChart,32 });3334 return null;35}
L'hook registra lo strumento con il runtime di CopilotKit. Il runtime lo pubblicizza all'agente tramite AG-UI. Quando l'agente lo chiama, gli argomenti arrivano in streaming e il tuo componente viene renderizzato in linea. Nessuno strumento Python da scrivere, nessuno schema da cablare, nessuna rotta API da aggiungere.
Il tuo design system rimane al comando.
Quel grafico delle spese non è un mockup. L'Agente Consulente Finanziario AI renderizza carte proprio come questa per budget reali, piani di risparmio e piani di estinzione debiti.
Vuoi prima l'hook nudo? È 'use-generative-ui-examples.tsx' nel Progetto Starter Generative UI.
La tassa di token
Ogni componente che registri siede nella finestra di contesto dell'agente prima che l'utente abbia detto qualsiasi cosa. Una descrizione tipica di uno strumento con il suo schema JSON occupa circa 400 token. 25 componenti sono 10.000 token ad ogni turno. Paghi questa tassa per richiesta.
L'agente sceglie anche il componente sbagliato. Troppi si assomigliano. Grafico a torta e grafico a ciambella entrambi "mostrano proporzioni". Lui indovina.
Quando aggiungere stato lato agente
Lo stato condiviso è l'unico caso in cui vale la pena scrivere uno strumento Python. L'agente scrive nello stato della sessione. Altre parti della UI si iscrivono e si ri-renderizzano senza una seconda chiamata LLM. Fissa una metrica, la dashboard si aggiorna. Aggiungi una riga, la tabella si ridisegna.
1from google.adk.agents import LlmAgent2from google.adk.tools import ToolContext34def pin_metric(tool_context: ToolContext, label: str, value: float) -> dict:5 """Fissa una metrica alla dashboard dell'utente."""6 pinned = tool_context.state.get("pinnedMetrics", [])7 tool_context.state["pinnedMetrics"] = pinned + [{"label": label, "value": value}]8 return {"status": "pinned"}910agent = LlmAgent(name="dashboard_agent", model="gemini-3.5-flash", tools=[pin_metric])
Il frontend legge le metriche fissate attraverso l'hook di stato condiviso di CopilotKit. Il componente della chat renderizza ancora in linea perché lo stesso nome di strumento è cablato con l'hook frontend.
Fissa una metrica in chat. Il pannello si ridisegna senza una seconda chiamata al modello. Questo è l'Agente Dashboard Canvas AI.
L'Agente di Ricerca Approfondita AI lo porta più avanti. Il piano, ogni ricerca, ogni scrittura di file, tutto scorre in streaming come carte live. Per tutto il resto, l'hook frontend è l'intera storia.
Quando spedire Controllato: Dieci o meno flussi ad alto valore. La precisione del design è importante. Conosci esattamente le UI di cui hai bisogno.
Quando non farlo: Il tuo codebase cresce linearmente con i casi d'uso. 25 componenti significano 25 definizioni di strumenti che siedono in ogni turno dell'agente.
Cosa si rompe: L'agente sceglie il componente sbagliato. Due descrizioni di strumenti si sovrappongono semanticamente. Oltre 15 strumenti, probabilmente due di loro sembrano "mostra dati". Soluzione: riscrivi le descrizioni per nominare l'intenzione dell'utente, non l'aspetto visivo. "Usa quando l'utente chiede di confrontare proporzioni di un intero" batte "renderizza un grafico a torta".
Pattern 2: Dichiarativo (A2UI), l'agente emette lo schema

Questo è il pattern di cui la maggior parte delle app agente in produzione finisce per avere bisogno.
L'agente emette uno schema JSON che descrive la UI. La tua app ha un catalogo di componenti che mappa i nodi dello schema a React (o Svelte, Flutter, qualsiasi cosa). Uno strumento. Molte UI.
A2UI è la specifica standard. CopilotKit spedisce il runtime. ADK esegue l'agente. AG-UI è il filo.
Lo strumento agente restituisce tre operazioni in ordine: crea una superficie, invia l'albero dei componenti, invia i dati.
1def search_flights(flights: list[Flight]) -> dict[str, Any]:2 """Cerca voli e li mostra come carte ricche."""3 return {4 "a2ui_operations": [5 {"type": "create_surface", "surfaceId": SURFACE_ID, "catalogId": CATALOG_ID},6 {"type": "update_components", "surfaceId": SURFACE_ID, "components": FLIGHT_SCHEMA},7 {"type": "update_data_model", "surfaceId": SURFACE_ID, "data": {"flights": flights}},8 ]9 }
Questa è la funzione reale, non pseudocodice. Il middleware del runtime vede il contenitore a2ui_operations nel risultato dello strumento e inoltra le superfici al frontend. Aggiungere hotel? Nuovo file di schema. Un'altra funzione con un ID superficie diverso. Zero lavoro extra sul frontend.
Schema fisso vs schema dinamico
L'albero dei componenti sopra vive in flights.json. L'hai scritto tu. L'agente riempie solo i dati. Questo è uno schema fisso.
Lo schema dinamico lo capovolge: un LLM secondario scrive l'albero dei componenti per ogni turno dal contesto della conversazione. Stesso contenitore a2ui_operations alla fine. La vetrina Google ADK spedisce entrambi.
Il catalogo è il contratto
Le definizioni elencano i componenti che l'agente può emettere, con schemi Zod per le props. I renderer riempiono in React. I refusi diventano errori di build invece di schermate bianche.
1const renderers: CatalogRenderers<TravelDefinitions> = {2 FlightCard: ({ props }) => (3 <article className="rounded-xl border p-4">4 <header className="flex justify-between">5 <span>{(props as any).airline}</span>6 <span>{(props as any).price}</span>7 </header>8 <div className="text-sm text-muted-foreground">9 {(props as any).origin} → {(props as any).destination} · {(props as any).departureTime}10 </div>11 </article>12 ),13};1415export const travelCatalog = createCatalog(travelDefinitions, renderers, {16 catalogId: "copilotkit://travel-catalog",17 includeBasicCatalog: true,18});
Entrambe le metà vivono nel Progetto Starter Generative UI, cablate e abbinate. search_flights in 'a2ui_fixed_schema.py', il catalogo FlightCard in 'renderers.tsx'. Chiedi voli. Guarda le carte scorrere in streaming nella chat.
I pulsanti e altri componenti interattivi portano un'azione nello schema. Il catalogo base la collega a onClick. Il click spara un evento all'agente tramite AG-UI. L'agente decide cosa renderizzare dopo. Zero gestori di click.
La matematica dei token
50 tipi di carte o 500, l'agente vede una funzione. I token per turno rimangono piatti man mano che la tua libreria di componenti cresce.
Estendibile a qualsiasi framework di rendering perché è solo JSON. Qualsiasi agente che già parla AG-UI può guidare A2UI dal giorno zero. Non tocchi il codice dell'agente per cablare questo.
Compromesso: L'LLM possiede il layout. L'output varia da esecuzione a esecuzione all'interno del tuo catalogo. Se stai spedendo informative legali, superfici di marketing o qualsiasi cosa in cui il posizionamento esatto dei pixel è importante, questo non è il tuo secchio.
Dichiarativo è il pattern costruito per la coda lunga. Dashboard, risultati, moduli, carte, widget.
Quando spedire Dichiarativo: Hai più casi d'uso che tempo per pre-costruire. Ti importa dell'economia dei token oltre la fase del prototipo.
Cosa si rompe: Hai costruito un FlightCard personalizzato. Ogni volo viene renderizzato come la carta generica del catalogo base. Nessun errore nella console. Il CATALOG_ID sull'agente e catalogId in createCatalog sul frontend non corrispondono. Il frontend non riconosce il catalogo a cui l'agente sta mirando, torna al base. Abbina esattamente le stringhe su entrambi i lati.
Pattern 3: Aperto, nessun catalogo, nessuna regola

Il terzo pattern è l'estremo opposto. Nessun catalogo. Nessuno schema. Solo una tela bianca.
Due sotto-pattern vivono in questo secchio.
MCP Apps
Un server MCP espone superfici UI che l'agente guida. Excalidraw è l'esempio che mi è rimasto impresso. L'agente ottiene il controllo completo della tela. Disegna diagrammi dal tuo contesto. Possiede ogni pixel sulla lavagna.

Implementare il protocollo client da zero è doloroso, quindi CopilotKit spedisce un MCPAppsMiddleware. Attaccalo al tuo agente e puntalo a qualsiasi server MCP Apps.
1const agent = new BuiltInAgent({2 model: "openai/gpt-5.5",3 prompt: "Sei un assistente utile.",4}).use(5 new MCPAppsMiddleware({6 mcpServers: [{ type: "http", url: "https://mcp.excalidraw.com/mcp", serverId: "my-server" }],7 }),8);
Avvia la Vetrina MCP Apps e stai prenotando voli e hotel all'interno della finestra della chat. Stesso middleware, veri server MCP. O vai oltre.
L'AI MCP App Builder permette all'agente di scrivere una nuova app in una sandbox E2B, poi la renderizza in tempo reale.
0:45
HTML in Sandbox
L'agente scrive HTML grezzo. La tua app lo renderizza all'interno di un iframe in sandbox in modo che non possa dirottare la sessione.
Il runtime registra uno strumento di rendering HTML e lo spedisce all'agente tramite AG-UI. L'agente lo chiama con qualsiasi markup voglia. Non c'è uno strumento HTML da definire lato agente. Il runtime lo inietta.
L'istruzione lato agente sta facendo un lavoro reale:
1canvas_agent = LlmAgent(2 name="canvas_agent",3 model="gemini-3.5-flash",4 instruction=(5 "Sei un assistente di visualizzazione. Quando l'utente chiede di vedere, "6 "disegnare o visualizzare qualsiasi cosa, genera un'interfaccia utente HTML interattiva. "7 "Usa solo classi Tailwind. Nessun font esterno. Attieniti a colori "8 "neutri a meno che l'utente non ne nomini uno."9 ),10)
Senza quelle regole di stile, il modello predefinisce l'estetica più rumorosa nei suoi dati di addestramento quella settimana. Con loro, ottieni qualcosa di vicino al tuo marchio la maggior parte del tempo. Non sempre.
Il problema dell'incoerenza del marchio
Ho provato a spedire Aperto come UI primaria per un agente. L'ho ritirato in una settimana.
"Neo-brutalista" martedì. "Clone iOS 4" mercoledì. Le regole di stile nel prompt spingono l'agente verso il tuo marchio. Non lo garantiscono. Il marchio continuava a cambiare. Il prodotto sembrava poco serio.

Aperto non è inutile. È applicato male.
La scelta giusta per una cosa: interazioni usa e getta dove all'utente non importa che aspetto ha l'interfaccia e non la rivedrà mai più. "Mostrami come funzionano gli elettroni." "Dammi uno strano grafico a barre delle mie ultime 10 query." "Visualizza questa risposta API." Il genere di cose che vedi nelle panoramiche AI di Google.
Quando spedire Aperto: Query monouso. Visualizzazioni usa e getta. Esperimenti in sandbox. Mai come superficie primaria.
Cosa si rompe: L'iframe si renderizza. I pulsanti non cliccano. I moduli non si inviano. I flag della sandbox sono troppo stretti, o troppo larghi in un modo che il browser rifiuta. Imposta la sandbox dell'iframe per permettere script e permettere moduli. Nient'altro. Mai permettere same-origin.
Come scegliere
Esegui l'albero decisionale prima di scrivere codice.
Il designer ha mockup pixel-perfect per questo flusso? Controllato.
Decine di tipi di carte o widget da spedire? Dichiarativo.
Visualizzazione monouso, usa e getta che l'utente non vedrà mai due volte? Aperto.
Non riesci a decidere? Predefinisci a Dichiarativo. Aggiorna a Controllato per i primi 3 flussi. Mai Aperto come predefinito.
Se stai già spedendo e non sei sicuro di dove sei atterrato, conta gli strumenti di rendering. Oltre 15, sei in Controllato e il muro è vicino. Inizia a cablare A2UI questa settimana.
Tre pattern. Tre scommesse.
Controllato scommette su di te. Componenti pre-costruiti, pixel-perfect. Costoso oltre 25 di loro.
Dichiarativo scommette sullo schema. Lo schema è il contratto. L'agente lo riempie. Scala piatto.
Aperto scommette sul modello. Nessun catalogo, nessuno schema, HTML grezzo. Buono per cose usa e getta. Fragile per qualsiasi cosa spedita due volte.
L'errore non è scegliere il pattern sbagliato. È non sapere di averne scelto uno.
La maggior parte dei team predefinisce a Controllato perché il framework predefinisce a Controllato. Colpiscono il muro a 25 componenti e allungano la mano verso Aperto perché sembra convincente nelle demo. Nessuna delle due è stata una decisione. Entrambe erano deriva.
Scegli di proposito. Abbina il pattern al problema. Controllato per i flussi che devono essere esatti. Dichiarativo per la coda lunga. Aperto per l'usa e getta.
Modelli Agente Generative UI Open Source
Il riferimento per tutti e tre vive nella nuova sezione Agenti Generative UI di awesome-llm-apps. Clona ciò di cui hai bisogno. Butta via ciò di cui non hai bisogno.
Pubblicherò altro sulla spedizione di agenti in produzione, AG-UI e i pattern che scalano. Seguimi @Saboo_Shubham_ per rimanere sintonizzato.










