GenUI es un conjunto de paquetes de Flutter, hoy en alpha, que deja a un modelo de lenguaje construir la interfaz en tiempo de ejecución a partir de un catálogo de widgets que tú defines. A2UI es el protocolo que tiene debajo: un formato JSON, independiente de framework, con el que el agente describe esa interfaz. Juntos convierten una conversación con un modelo en pantallas de verdad, con sus botones, sus formularios y sus selectores de fecha, en vez de un muro de texto. Funciona; la pregunta es dónde meterlo y dónde no. Vamos con el código delante.

Qué son GenUI y A2UI (y qué no son)

GenUI es un conjunto de paquetes de Flutter que deja a un modelo de lenguaje componer la interfaz en tiempo de ejecución. Tú le das un catálogo de widgets (los que tu app ya sabe pintar) y el modelo decide cuáles usar y cómo rellenarlos según la conversación con el usuario. En lugar de devolver un párrafo describiendo tres vuelos, el agente devuelve un carrusel de tarjetas con sus botones.

A2UI es la capa de debajo. Es un protocolo abierto cuya versión 0.9 publicó Google el 17 de abril de 2026, con un formato JSON para que un agente describa una interfaz sin atarse a ningún framework. Hay renderizadores para Flutter, React, Angular y Lit, y el SDK de agente llega primero en Python, con Go y Kotlin anunciados. GenUI, por ahora, habla A2UI 0.9.

Conviene separar esto de otra cosa que suena parecida: usar un asistente de IA para escribir tu código Flutter. Eso ocurre en tu editor, antes de compilar. GenUI ocurre en producción, con el usuario delante, y la interfaz cambia en cada respuesta del modelo. Son dos problemas distintos y aquí hablamos solo del segundo.

Cómo funciona por dentro

El flujo tiene cuatro pasos y un bucle:

  1. El usuario escribe o toca algo. Tu app manda ese mensaje al agente junto con el catálogo de widgets disponibles.
  2. El agente responde con texto y con una descripción de UI en formato A2UI.
  3. GenUI deserializa esa descripción y construye los widgets reales de tu catálogo.
  4. El usuario interactúa, el estado vuelve al modelo y el ciclo se repite.

La pieza central es el catálogo. Cada widget que quieras poner a disposición del modelo lo declaras como un CatalogItem: un nombre, un esquema de datos y una función que construye el widget. El esquema es lo que el modelo lee para saber qué datos tiene que rellenar.

final riddleCard = CatalogItem(
  name: 'RiddleCard',
  dataSchema: _schema,
  widgetBuilder: (itemContext) {
    final json = itemContext.data as Map<String, Object?>;
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(json['question'] as String),
        Text(json['answer'] as String),
      ],
    );
  },
);

Lo que el modelo emite, por el cable, es JSON plano:

{
  "id": "welcome-text",
  "component": "Text",
  "text": "Welcome to GenUI",
  "variant": "h1"
}

El estado vive en un DataModel, un almacén observable. Los widgets se enlazan a rutas dentro de ese modelo, y cuando un TextField cambia un valor, solo se reconstruye lo que depende de esa ruta. Para quien viene de Flutter, el modelo mental no es raro: es gestión de estado reactiva, con la diferencia de que el árbol de widgets lo propone un modelo en vez de tú.

Las tres formas de conectarlo

El SDK trae tres maneras de hablar con un modelo, y la que elijas marca dónde vive el coste y el riesgo.

Firebase AI Logic. Todo pasa en el cliente y Firebase gestiona la clave de Gemini. Es la vía rápida para un prototipo o para una app sin backend propio. Pagas en latencia de red y en que la lógica del prompt viaja en el dispositivo.

Servidor A2UI. Tu agente corre en el servidor y Flutter solo renderiza lo que llega por WebSocket. Es la opción para cuando ya tienes backend, quieres controlar el prompt y el modelo, y no te apetece exponer nada en el cliente. Más piezas que mantener, más control a cambio.

El tuyo. Conectas el proveedor que quieras y le metes el stream a un A2uiTransportAdapter. Flexibilidad total, cero andamiaje puesto.

Si estás decidiendo, la pregunta útil es si ya tienes servidor. Si lo tienes, el patrón cliente/servidor con A2UI te deja el prompt y el modelo bajo tu control, que es donde vas a querer tenerlos cuando esto pase de demo a producto.

El coste que nadie pone en el titular

Aquí está la parte que las demos se saltan. El PromptBuilder.chat() que trae el SDK genera un prompt de sistema de entre 3.000 y 5.000 tokens, o más. Eso es lo que le explica al modelo cómo construir UI con A2UI, y va en cada petición.

Las consecuencias son concretas. Primero, dinero: pagas esos tokens en cada vuelta de la conversación, no una vez. Segundo, latencia: un prompt grande tarda más en procesarse, y la UI generada ya de por sí llega después de que el modelo responda. Tercero, modelos pequeños: la propia documentación avisa de que ese prompt puede no caber en el contexto de un modelo on-device o pequeño, así que si tu plan era correr esto en local, ajusta expectativas.

La salida que propone el SDK es usar systemPromptFragments para mandar solo el trozo del esquema que tu caso necesita, o escribir un prompt compacto a mano. Las dos opciones funcionan y las dos son trabajo que tendrás que medir. No des por hecho el coste por usuario sin haber contado tokens en un flujo real.

Y el recordatorio grande: el paquete genui está en alpha y la documentación dice, con esas palabras, que va a cambiar. La optimización de latencia percibida figura como "lo siguiente", y la composición de pantalla completa todavía es trabajo futuro. Hoy construye piezas de interfaz, no apps enteras.

Cuándo sí y cuándo no

Para quién tiene sentido hoy:

  • Superficies de chat o asistente donde la interfaz es de verdad impredecible y cada usuario pide algo distinto.
  • Flujos exploratorios y de cola larga —planificar un viaje, filtrar por conversación un catálogo enorme— donde diseñar a mano cada pantalla no compensa.
  • Herramientas internas, donde algo de latencia y algún borde áspero se toleran a cambio de ir rápido.

Para quién no, al menos por ahora:

  • La navegación principal y las pantallas de mucho tráfico. Ahí quieres control de píxel, rendimiento predecible y ninguna dependencia de que un modelo responda.
  • Flujos regulados o de dinero, donde la UI tiene que ser determinista y auditable.
  • Apps que necesitan funcionar sin red o con accesibilidad estricta: una interfaz que se genera sobre la marcha es más difícil de garantizar en ambos frentes.

Hay un punto que no es de rendimiento sino legal. Si la interfaz la genera un modelo, estás poniendo contenido de IA delante del usuario, y el artículo 50 del AI Act pide transparencia sobre eso. Lo tratamos en detalle en nuestro análisis del artículo 50; si vas a meter GenUI en un producto europeo, que entre en la conversación desde el día uno.

Qué haríamos nosotros con un cliente

Si un cliente nos trae esto mañana, no reescribimos su app. Buscamos una superficie contenida, casi siempre un asistente o un flujo de búsqueda conversacional, y montamos ahí un piloto con un catálogo pequeño y bien acotado. Medimos tokens por interacción y latencia real antes de hablar de escalar. Mantenemos el modelo y el prompt en el servidor, no en el cliente, para poder cambiarlos sin publicar una versión nueva en las tiendas.

Y marcamos la fecha de revisión. Una dependencia en alpha no entra en el camino crítico de un roadmap sin un plan por si la API cambia debajo. GenUI es una apuesta razonable de Google, está en el centro de su hoja de ruta de Flutter para 2026, y A2UI tiene renderizadores en media industria. Nada de eso lo vuelve estable hoy.

Si estás valorando si tu app Flutter es candidata, o si el salto de versión que esto puede pedirte encaja con tu calendario, lo vemos. En Dribba llevamos desde 2011 haciendo Flutter con equipo senior in-house, y la IA aplicada es de las partes que más nos gusta pisar con los pies en el suelo.