O frontend costumava ser algo fixo. Designers desenhavam. Engenheiros construíam. Os usuários recebiam o que era lançado.
Isso acabou.
As interfaces sendo lançadas em 2026 são parcialmente desenhadas pelo próprio agente, em tempo real, a partir do que o usuário realmente pediu. Peça uma tabela, obtenha uma tabela. Não um parágrafo descrevendo uma.
UI Generativa é a camada que permite que agentes parem de descrever e comecem a mostrar. Três padrões surgiram para como construí-la, e as diferenças entre eles importam mais do que a maioria dos times imagina.
Mas não existe apenas uma maneira de construir isso. Existem três. E a maioria dos times escolhe um sem saber que fez uma escolha.
A pilha de protocolos
Três protocolos. Cada um faz um trabalho.
MCP conecta agentes a ferramentas. A2A conecta agentes entre si. AG-UI conecta agentes a usuários.
AG-UI é a camada de streaming que carrega tudo que você verá abaixo: chamadas de ferramentas, esquemas A2UI, eventos MCP App, deltas de estado. Roda sobre SSE. O estado flui nos dois sentidos no mesmo stream. O usuário edita, o agente vê. O agente altera, o usuário vê.
A2UI é a especificação do Google para agentes emitirem UI como esquema. Ela roda sobre AG-UI. O CopilotKit a implementa em produção.
Você não escreve um parser para nada disso. O CopilotKit é um cliente AG-UI e decodifica o stream para você.
Os três padrões que a maioria dos times confunde
Pergunte a dez desenvolvedores o que é UI Generativa. Você obtém dez respostas. A maioria delas está descrevendo o padrão que seu framework atual implementa.
Existem apenas três. O espectro vai de mais controle a mais flexibilidade.
- Controlado: Você pré-constrói os componentes. O agente escolhe qual renderizar.
- Declarativo: O agente emite um esquema. Seu app mapeia para componentes.
- Aberto: O agente escreve HTML puro. Seu app renderiza em uma sandbox.

Todo framework de UI Generativa em 2026 está em algum lugar dessa linha. As diferenças são arquiteturais, não cosméticas. Cada padrão quebra seu aplicativo de uma forma diferente em escala.
Eu testei diferentes stacks. A maioria cobre bem um padrão. Escolhi o CopilotKit porque ele suporta todos os três no mesmo runtime, rodando sobre AG-UI. Essa é a stack na qual tudo abaixo roda.
Padrão 1: Controlado, frontend é dono da UI

É por aqui que a maioria dos times começa. É também por aqui que a maioria dos times fica presa.
Você pré-constrói um componente React. Você o vincula a um nome de ferramenta. O agente escolhe essa ferramenta e o componente renderiza inline no chat com os args do agente como props.
Um hook no frontend. Zero código de agente. É só isso.
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: "Render a breakdown of expenses by category.",30 parameters: expenseChartSchema,31 render: ExpenseChart,32 });3334 return null;35}
O hook registra a ferramenta no runtime do CopilotKit. O runtime a anuncia para o agente via AG-UI. Quando o agente a chama, os args são transmitidos e seu componente renderiza inline. Nenhuma ferramenta Python para escrever, nenhum esquema para conectar, nenhuma rota de API para adicionar.
Seu sistema de design continua no comando.
Aquele gráfico de despesas não é um mockup. O AI Financial Coach Agent renderiza cards exatamente como ele para orçamentos reais, planos de poupança e pagamento de dívidas.
Quer o hook puro primeiro? É o 'use-generative-ui-examples.tsx' no Generative UI Starter Project.
O custo de tokens
Cada componente que você registra ocupa espaço no contexto do agente antes mesmo do usuário dizer algo. A descrição de uma ferramenta típica com seu esquema JSON consome cerca de 400 tokens. 25 componentes são 10.000 tokens a cada interação. Você paga esse custo por requisição.
O agente também escolhe o componente errado. Muitos parecem similares. Gráfico de pizza e gráfico de rosca ambos "mostram proporções". Ele chuta.
Quando adicionar estado no lado do agente
Estado compartilhado é o único caso onde vale a pena escrever uma ferramenta Python. O agente escreve no estado da sessão. Outras partes da UI se inscrevem e re-renderizam sem uma segunda chamada de LLM. Fixe uma métrica, o dashboard atualiza. Adicione uma linha, a tabela redesenha.
1from google.adk.agents import LlmAgent2from google.adk.tools import ToolContext34def pin_metric(tool_context: ToolContext, label: str, value: float) -> dict:5 """Pin a metric to the user's dashboard."""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])
O frontend lê as métricas fixadas através do hook de estado compartilhado do CopilotKit. O componente de chat ainda renderiza inline porque o mesmo nome de ferramenta está conectado com o hook do frontend.
Fixe uma métrica no chat. O painel redesenha sem uma segunda chamada de modelo. Esse é o AI Dashboard Canvas Agent.
O AI Deep Research Agent vai além. O plano, cada busca, cada escrita de arquivo, tudo isso é transmitido como cards ao vivo. Para todo o resto, o hook do frontend é a história completa.
Quando lançar com Controlado: Dez ou menos fluxos de alto valor. A precisão do design importa. Você sabe exatamente quais UIs precisa.
Quando não lançar: Seu código base cresce linearmente com os casos de uso. 25 componentes significam 25 definições de ferramentas em cada turno do agente.
O que quebra: O agente escolhe o componente errado. Duas descrições de ferramentas se sobrepõem semanticamente. Acima de 15 ferramentas, provavelmente duas delas parecem "exibe dados". Solução: reescreva as descrições para nomear a intenção do usuário, não o visual. "Use quando o usuário pedir para comparar proporções de um todo" é melhor do que "renderiza um gráfico de pizza".
Padrão 2: Declarativo (A2UI), agente emite esquema

Este é o padrão que a maioria dos apps de agente em produção acaba precisando.
O agente emite um esquema JSON descrevendo a UI. Seu app tem um catálogo de componentes que mapeia nós do esquema para React (ou Svelte, Flutter, qualquer coisa). Uma ferramenta. Muitas UIs.
A2UI é a especificação padrão. O CopilotKit implementa o runtime. O ADK executa o agente. AG-UI é o meio de transmissão.
A ferramenta do agente retorna três operações em ordem: criar uma superfície, enviar a árvore de componentes, enviar os dados.
1def search_flights(flights: list[Flight]) -> dict[str, Any]:2 """Search flights and display them as rich cards."""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 }
Esta é a função real, não pseudocódigo. O middleware do runtime vê o container a2ui_operations no resultado da ferramenta e encaminha as superfícies para o frontend. Adicionar hotéis? Novo arquivo de esquema. Mais uma função com um surfaceId diferente. Zero trabalho extra no frontend.
Esquema fixo vs esquema dinâmico
A árvore de componentes acima está em flights.json. Você a escreveu. O agente apenas preenche os dados. Isso é um esquema fixo.
O esquema dinâmico inverte isso: um LLM secundário escreve a árvore de componentes a cada interação a partir do contexto da conversa. O mesmo container a2ui_operations no final. O showcase do Google ADK implementa ambos.
O catálogo é o contrato
As definições listam os componentes que o agente pode emitir, com esquemas Zod para as props. Os renderizadores preenchem com React. Erros de digitação se tornam erros de compilação, não telas em branco.
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});
Ambas as metades estão no Generative UI Starter Project, conectadas e pareadas. search_flights em 'a2ui_fixed_schema.py', o catálogo FlightCard em 'renderers.tsx'. Peça voos. Veja os cards sendo transmitidos no chat.
Botões e outros componentes interativos carregam uma ação no esquema. O catálogo básico a conecta ao onClick. O clique dispara um evento de volta para o agente via AG-UI. O agente decide o que renderizar a seguir. Zero manipuladores de clique.
A matemática dos tokens
50 tipos de card ou 500, o agente vê uma única função. O custo de tokens por interação permanece estável conforme sua biblioteca de componentes cresce.
Extensível para qualquer framework de renderização porque é apenas JSON. Qualquer agente que já fale AG-UI pode usar A2UI no dia zero. Você não toca no código do agente para configurar isso.
Compensação: O LLM é dono do layout. A saída varia de execução para execução dentro do seu catálogo. Se você está lidando com divulgações legais, superfícies de marketing ou qualquer coisa onde o posicionamento exato de pixels importa, este não é seu caso.
Declarativo é o padrão construído para a cauda longa. Dashboards, resultados, formulários, cards, widgets.
Quando lançar com Declarativo: Você tem mais casos de uso do que tempo para pré-construir. Você se importa com a economia de tokens após a fase de protótipo.
O que quebra: Construiu um FlightCard personalizado. Cada voo renderiza como o card genérico do catálogo básico. Nenhum erro no console. O CATALOG_ID no agente e o catalogId no createCatalog no frontend não correspondem. O frontend não reconhece o catálogo que o agente está mirando, cai para o básico. Corresponda exatamente as strings em ambos os lados.
Padrão 3: Aberto, sem catálogo, sem regras

O terceiro padrão é o extremo oposto. Sem catálogo. Sem esquema. Apenas uma tela em branco.
Dois sub-padrões vivem neste balde.
MCP Apps
Um servidor MCP expõe superfícies de UI que o agente controla. Excalidraw é o exemplo que ficou comigo. O agente obtém controle total do canvas. Desenha diagramas a partir do seu contexto. É dono de cada pixel na tela.

Implementar o protocolo do cliente do zero é trabalhoso, então o CopilotKit implementa um MCPAppsMiddleware. Anexe-o ao seu agente e aponte-o para qualquer servidor MCP Apps.
1const agent = new BuiltInAgent({2 model: "openai/gpt-5.5",3 prompt: "You are a helpful assistant.",4}).use(5 new MCPAppsMiddleware({6 mcpServers: [{ type: "http", url: "https://mcp.excalidraw.com/mcp", serverId: "my-server" }],7 }),8);
Inicie o MCP Apps Showcase e você estará reservando voos e hotéis dentro da janela de chat. Mesmo middleware, servidores MCP reais. Ou vá além.
O AI MCP App Builder permite que o agente escreva um aplicativo totalmente novo em uma sandbox E2B e depois o renderize ao vivo.
0:45
HTML em sandbox
O agente escreve HTML puro. Seu app renderiza dentro de um iframe em sandbox para que não possa sequestrar a sessão.
O runtime registra uma ferramenta de renderização HTML e a envia para o agente via AG-UI. O agente a chama com qualquer marcação que desejar. Não há ferramenta HTML para definir no lado do agente. O runtime a injeta.
A instrução no lado do agente está fazendo trabalho real:
1canvas_agent = LlmAgent(2 name="canvas_agent",3 model="gemini-3.5-flash",4 instruction=(5 "You are a visualization assistant. When the user asks to see, "6 "draw, or visualize anything, generate an interactive HTML UI. "7 "Use Tailwind classes only. No external fonts. Stick to neutral "8 "colors unless the user names one."9 ),10)
Sem essas regras de estilo, o modelo padrão para qualquer estética que estava mais presente em seus dados de treinamento naquela semana. Com elas, você obtém algo próximo da sua marca na maioria das vezes. Nem sempre.
O problema de inconsistência de marca
Tentei usar o padrão Aberto como UI principal para um agente. Desisti em uma semana.
"Neo-brutalista" na terça. "Clone do iOS 4" na quarta. Regras de estilo no prompt empurram o agente em direção à sua marca. Elas não a garantem. A marca continuava mudando. O produto parecia pouco sério.

O padrão Aberto não é inútil. É mal aplicado.
Escolha certa para uma coisa: interações descartáveis onde o usuário não se importa com a aparência da interface e nunca mais a verá. "Me mostre como os elétrons funcionam." "Me dê um gráfico de barras estranho das minhas últimas 10 consultas." "Visualize esta resposta de API." O tipo de coisa que você vê nas visões gerais do Google AI.
Quando lançar com Aberto: Consultas únicas. Visualizações descartáveis. Experimentos em sandbox. Nunca como a superfície principal.
O que quebra: O iframe renderiza. Botões não clicam. Formulários não enviam. As flags da sandbox são muito restritas, ou muito permissivas de uma forma que o navegador recusa. Configure a sandbox do iframe para permitir scripts e permitir formulários. Nada mais. Nunca allow-same-origin.
Como escolher
Execute a árvore de decisão antes de escrever código.
O designer tem mockups pixel-perfect para este fluxo? Controlado.
Dezenas de tipos de card ou widgets para lançar? Declarativo.
Visualização única e descartável que o usuário nunca verá duas vezes? Aberto.
Não consegue decidir? Padrão para Declarativo. Atualize para Controlado para os 3 principais fluxos. Nunca use Aberto como padrão.
Se você já está lançando e não tem certeza onde caiu, conte as ferramentas de renderização. Acima de 15, você está no Controlado e a parede está próxima. Comece a configurar A2UI esta semana.
Três padrões. Três apostas.
Controlado aposta em você. Componentes pré-construídos, pixel-perfect. Caro acima de 25 deles.
Declarativo aposta no esquema. O esquema é o contrato. O agente o preenche. Escala horizontalmente.
Aberto aposta no modelo. Sem catálogo, sem esquema, HTML puro. Bom para descartáveis. Frágil para qualquer coisa que seja lançada duas vezes.
O erro não é escolher o padrão errado. É não saber que você escolheu um.
A maioria dos times padrão para Controlado porque o framework padrão para Controlado. Eles batem na parede com 25 componentes e recorrem ao Aberto porque parece convincente em demonstrações. Nenhuma das duas foi uma decisão. Ambas foram deriva.
Escolha com propósito. Combine o padrão com o problema. Controlado para os fluxos que precisam ser exatos. Declarativo para a cauda longa. Aberto para o descartável.
Templates Open Source de Agentes com UI Generativa
A referência para todos os três está na nova seção Generative UI Agents do awesome-llm-apps. Clone o que precisar. Remova o que não precisar.
Vou publicar mais sobre como lançar agentes em produção, AG-UI e os padrões que escalam. Siga-me @Saboo_Shubham_ para ficar ligado.










