Sin generar texto, ¿cómo maneja Jev un navegador y construye interfaces? Análisis de Browser Use y json-render
A través de los ejemplos de código abierto Browser Use y json-render, explicamos cómo Jev toma decisiones estructuradas dentro de un espacio limitado de acciones o componentes, y por qué la lectura del DOM, la generación de texto, el ensamblaje de JSON, la validación, el renderizado y la ejecución final siguen dependiendo del código circundante.
Índice

Cuando se crea un sistema de IA que opera un navegador, el enfoque más intuitivo suele ser entregar una captura de pantalla o el DOM a un modelo grande de propósito general, pedirle que analice la página y planifique el siguiente paso, y después hacer que genere una posición de clic, un selector o una llamada a una herramienta.
Con la creación de interfaces suele ocurrir algo parecido. El usuario describe lo que necesita, el modelo genera directamente JSON, JSX o código de front-end, y el sistema intenta analizar, validar y renderizar el resultado.
Jev Ultrafast de Browser Use y el experimento de Jev en json-render siguen otra ruta:
Primero, el código limita lo que el modelo puede hacer a un conjunto finito; Jev solo elige dentro de ese conjunto.
En Browser Use, ese conjunto está formado por las acciones ejecutables y los elementos interactivos de la página actual. En json-render, está formado por componentes, configuraciones de propiedades, enlaces de datos y posiciones de diseño preparados previamente por la aplicación.
Jev no necesita escribir un plan completo de operaciones ni generar todo un árbol de UI en JSON. Solo responde preguntas como estas:
- ¿El siguiente paso debe ser hacer clic, introducir texto, desplazarse o esperar?
- ¿Sobre qué elemento de la página actual debe actuar?
- ¿Qué componentes deben aparecer en la interfaz?
- ¿En qué contenedor padre, ranura y orden debe colocarse un componente?
Estos dos ejemplos no demuestran que «un modelo que no genera texto pueda hacerlo todo». Muestran otra arquitectura de software: convertir una tarea de generación abierta en una secuencia de decisiones restringidas y verificables.
Qué hace realmente Jev aquí
Jev es un modelo System One publicado por TypeSafe AI. Recibe un state junto con un conjunto de preguntas tipadas definidas por el desarrollador y devuelve resultados estructurados como Choice, Score o Noul, en lugar de un texto largo pensado para una persona.
Puede entenderse como una función de decisión con salidas probabilísticas:
Estado actual
↓
El desarrollador construye un conjunto finito de candidatos
↓
Jev elige, puntúa o evalúa
↓
El código convencional valida el resultado
↓
Se ejecuta una acción o se renderiza la interfaz
En este esquema:
Choice: selecciona una opción de un conjunto dado;Score: sitúa el resultado en los niveles ordenados definidos por el desarrollador;Noul: devuelve la probabilidad de que una afirmación concreta sea verdadera.
Lo importante no es el formato de respuesta, sino el reparto de responsabilidades. Jev no genera libremente textos para la página, selectores del navegador, JavaScript ni JSON completo; el código sigue controlando el estado, el flujo, los permisos y la ejecución. TypeSafe describe este patrón como «estado no estructurado de entrada y decisiones probabilísticas tipadas de salida». (typesafe.ai)
Veamos cómo Browser Use y json-render aplican este patrón en sistemas reales.
Browser Use: primero convertir la página en un espacio finito de acciones
El proyecto jev-ultrafast de Browser Use muestra un agente de navegador: el usuario proporciona un objetivo en lenguaje natural, el programa lee la página actual, Jev elige la siguiente acción y el código del navegador la ejecuta.
La tarea de la demostración pública consiste en buscar en Google Flights un vuelo de ida de Zürich a London. El proyecto informa de un tiempo grabado de unos 7,1 segundos, incluidos las llamadas a modelos, la generación de texto, la ejecución en el navegador, la carga de la página y los reintentos por decisiones obsoletas. Aun así, es una sola tarea con una sola configuración del navegador, no una referencia general de fiabilidad para sitios arbitrarios. (github.com)
Paso 1: el código lee la página; Jev no se limita a «mirar una captura»
En cada ciclo de decisión, el código del navegador lee primero los controles y textos visibles de la página y crea una tabla numerada de elementos.
Una versión simplificada podría ser:
[1] button Cambiar tipo de billete · Ida y vuelta
[2] combobox ¿Desde dónde? · San Francisco
[3] combobox ¿Adónde? · vacío
[4] textbox Salida · vacío
[5] button Buscar
La tabla contiene el tipo de elemento, el nombre, el valor actual y el índice. El programa también conserva el nodo DOM real asociado a cada índice para volver a resolver el objetivo antes de ejecutarlo.
En este ejemplo, Jev no observa directamente una captura y adivina que un botón está en las coordenadas (482, 316). Las capturas se usan principalmente para demostraciones e inspección humana. Las decisiones reales se basan en el estado estructurado extraído del DOM. El proyecto también aclara que las etiquetas de la página se añaden al renderizar la captura y no controlan el navegador. (github.com)
La diferencia es importante.
Si un modelo genera libremente coordenadas o un CSS Selector, podría devolver:
- un selector que no existe en la página;
- una posición del elemento que ya está desactualizada;
- un control cubierto o no interactivo;
- un fragmento de JavaScript capaz de ejecutar comportamientos arbitrarios.
En cambio, Jev Ultrafast obliga al modelo a elegir únicamente entre los índices de elementos que el programa acaba de observar.
Paso 2: Jev elige la acción y el elemento objetivo
El proyecto ofrece este conjunto de acciones:
CLICK
TYPE_TEXT
SELECT
SCROLL_UP
SCROLL_DOWN
WAIT
DONE
BLOCKED
Según el estado actual de la página, el programa solo ofrece las acciones y los objetivos compatibles que están realmente disponibles en ese momento.
Por ejemplo:
- si la página no contiene un menú desplegable, no se ofrece ningún objetivo para
SELECT; - si hay tres campos de texto, los objetivos de entrada se limitan a esos tres elementos;
- si hay diez elementos sobre los que se puede hacer clic, los objetivos de clic se limitan a esos diez elementos.
Una decisión puede simplificarse así:
Pregunta 1: ¿Cuál debe ser la siguiente acción?
Candidatos: CLICK / TYPE_TEXT / SELECT / WAIT / DONE
Pregunta 2: Si la acción es CLICK, ¿sobre qué elemento hay que hacer clic?
Candidatos: [1] / [5] / [8] / [11]
Pregunta 3: Si la acción es TYPE_TEXT, ¿qué elemento debe recibir el texto?
Candidatos: [2] / [3] / [4]
Estas preguntas pueden evaluarse en paralelo dentro de una sola solicitud. Solo se ejecuta el objetivo compatible con la acción seleccionada. Si Jev elige CLICK, el programa lee únicamente click_target; no ejecuta un objetivo calculado de antemano para TYPE_TEXT.
El proyecto denomina a esto un espacio de acciones dinámico e indexado. Reduce el número de llamadas secuenciales al modelo necesarias en cada paso y evita que el modelo genere libremente los parámetros de operación. (github.com)
Paso 3: llamar a un modelo generativo solo cuando haya que escribir texto
Jev puede decidir que ahora hay que escribir en el campo de origen, pero no genera el texto que debe introducirse.
Cuando la acción es TYPE_TEXT, el sistema llama a un pequeño modelo generativo para producir el valor a partir de la tarea actual y del campo objetivo. Por ejemplo:
{
"text": "Zürich"
}
El resultado todavía debe analizarse como un objeto JSON muy pequeño antes de que el navegador pueda escribirlo.
Por tanto, este agente combina dos capacidades distintas:
| Tarea | Componente responsable |
|---|---|
| Decidir si el siguiente paso es hacer clic, escribir, seleccionar o esperar | Jev |
| Elegir sobre qué elemento de la página actuar | Jev |
| Generar el texto en lenguaje natural que debe introducirse | Modelo generativo pequeño |
| Leer el DOM y el estado de la página | Código del navegador |
| Hacer clic, escribir y seleccionar | Código del navegador |
| Verificar que el objetivo se ha completado de verdad | Código de validación independiente |
Por eso, decir que «Jev maneja el navegador» no significa que Jev complete por sí solo toda la tarea.
Una descripción más precisa es: Jev es el selector de acciones dentro del bucle del navegador.
Paso 4: el código vuelve a comprobar la página antes de ejecutar
Después de que el modelo elige, el programa no hace clic a ciegas.
Antes de ejecutar, Jev Ultrafast comprueba:
- si la página actual sigue siendo la misma que observó el modelo;
- si el nodo DOM correspondiente sigue existiendo;
- si el elemento está cubierto por otro contenido;
- si su geometría actual sigue siendo válida;
- si el valor del formulario y el contexto cercano aún coinciden con la instantánea;
- si ha cambiado la entrada utilizada para solicitar la generación de texto.
Si la página cambia antes de que llegue la respuesta del modelo, la decisión anterior puede haber quedado invalidada. El programa la trata como una decisión obsoleta en lugar de seguir operando sobre un elemento antiguo.
El proyecto limita explícitamente en qué puede convertirse la salida del modelo: no se transforma directamente en un CSS Selector, coordenadas de pantalla, un comando de shell ni JavaScript ejecutable. Todo objetivo ejecutado debe volver a resolverse como un nodo DOM real que ya había sido observado. (github.com)
Este código no es «inteligente», pero determina si el sistema es fiable.
El resultado de siete segundos no puede atribuirse solo a Jev
En seis ejecuciones alternadas, el proyecto informa de que ambas implementaciones completaron la tarea tres veces. El tiempo mediano bajó de unos 9,450 segundos a 7,092 segundos, una reducción aproximada del 25 %; las llamadas al protocolo del navegador bajaron de 1.092 a 101. El autor también subraya que solo fueron tres ejecuciones por implementación con la misma tarea y configuración del navegador, no una prueba general de fiabilidad. (github.com)
Por tanto, la mejora de rendimiento no procede solo de la velocidad del modelo, sino de toda la implementación del navegador:
- leer los controles visibles en una sola pasada;
- reducir los viajes de ida y vuelta del protocolo del navegador;
- reunir las preguntas sobre acción y objetivo en una misma decisión;
- llamar al modelo generativo solo cuando hace falta introducir texto;
- esperar únicamente los cambios de página necesarios después de ejecutar;
- evitar incluir texto irrelevante de la página en el contexto del modelo.
Por eso sería incorrecto concluir que sustituir un modelo por Jev hace que cualquier agente de navegador termine en siete segundos.
El MVP actual tampoco admite de forma completa shadow DOM, iframe, canvas, carga de archivos, pestañas emergentes, desplazamiento anidado ni widgets de teclado arbitrarios. Incluso cuando el modelo elige DONE, el sistema exige una comprobación independiente de que la tarea se ha completado realmente. (github.com)
json-render: dejar que Jev elija componentes en lugar de generar todo el JSON de la página
json-render aborda otro problema: cómo componer una interfaz directamente renderizable a partir de una solicitud en lenguaje natural.
Los sistemas tradicionales de UI generativa suelen pedir al modelo que produzca directamente:
- código React o Vue;
- un árbol completo de UI en JSON;
- CSS y propiedades de diseño;
- lógica de gestión de eventos;
- configuración de enlaces de datos.
El enfoque es flexible, pero también ofrece al modelo un espacio de salida enorme. Puede escribir mal el nombre de un componente, generar una propiedad inexistente, referirse a una acción no registrada o producir un JSON que no se pueda analizar.
El experimento de Jev en json-render reformula el problema:
La aplicación prepara primero una colección de instancias de componentes válidas, y Jev solo decide cuáles usar y cómo combinarlas.
Esta capacidad sigue marcada como experimental. experimental_composeSpec y experimental_createEvaluator no se han publicado como API estables; sus nombres y comportamiento pueden cambiar entre versiones. La documentación recomienda fijar una versión exacta y revisar el registro de cambios. (json-render.dev)
La aplicación proporciona primero el catálogo de componentes y los candidatos
Supongamos que el usuario pide:
Crea un panel de ventas con una tabla de pedidos en la parte superior, una fila de métricas de ingresos, número de pedidos y clientes nuevos debajo, y un gráfico de ingresos semanales al final.
La aplicación no entrega esta frase directamente a Jev para que escriba libremente el JSON de la interfaz.
Primero proporciona los candidatos:
Dashboard
OrdersTable
MetricRow
RevenueMetric
OrdersMetric
NewCustomersMetric
RevenueBarGraph
Cada candidato no es solo un nombre, sino una instancia de componente configurada por la aplicación. Puede incluir:
- tipo de componente;
- propiedades fijas;
- configuración de diseño disponible;
- enlaces de estado;
- enlaces de datos;
- acciones permitidas;
- una descripción del candidato destinada al modelo.
Por ejemplo, un botón puede predefinirse así:
Componente: Button
Texto: Guardar
Acción: savePreferences
Argumentos: leer el estado actual de /name
Jev puede decidir si usa este botón, pero no puede inventar una acción no registrada como deleteAllUsers.
La documentación de json-render destaca que la plataforma controla las capacidades disponibles y el sistema de diseño. Jev solo puede elegir entre los componentes, configuraciones y enlaces de acciones que proporciona la aplicación; los textos, datos o componentes ausentes no son creados automáticamente por Jev. (json-render.dev)
Fase 1: elegir qué componentes necesita la interfaz
Al crear una interfaz nueva, el primer grupo de decisiones determina:
- qué candidato será el nodo raíz;
- qué componentes deben seleccionarse;
- cuántas instancias de un componente reutilizable se necesitan;
- qué variante debe elegirse cuando existen varias variantes del mismo recurso.
Por ejemplo:
Componente raíz: Dashboard
Incluir:
- OrdersTable
- MetricRow
- RevenueMetric
- OrdersMetric
- NewCustomersMetric
- RevenueBarGraph
Una vez tomadas estas decisiones, el código convencional ensambla de inmediato un Spec inicial, comprueba las propiedades de los componentes y los argumentos de las acciones contra el esquema del catálogo, y transmite una vista previa que ya puede renderizarse.
En ese momento, el diseño todavía puede seguir el orden del catálogo, pero el usuario ya ve un resultado intermedio estructuralmente válido.
Esto es distinto de pedir a un modelo que emita todo el JSON token a token: Jev no escribe JSON serializado. El código construye el JSON a partir de elecciones restringidas. (json-render.dev)
Fase 2: decidir relaciones padre-hijo y orden
Una vez seleccionados los componentes, un segundo grupo de decisiones resuelve el diseño:
- a qué nodo padre pertenece cada componente;
- en qué ranura con nombre del padre debe colocarse;
- en qué orden aparecen los componentes hermanos.
La estructura final puede ser:
Dashboard
├── OrdersTable
├── MetricRow
│ ├── RevenueMetric
│ ├── OrdersMetric
│ └── NewCustomersMetric
└── RevenueBarGraph
Después, el código comprueba:
- que exista exactamente una raíz válida;
- que no se haya introducido un ciclo padre-hijo;
- que la profundidad no supere el límite;
- que el componente esté colocado en una ranura válida;
- que cada candidato se utilice el número permitido de veces;
- que todas las propiedades, enlaces y argumentos de acciones pasen la validación del esquema.
Si el diseño compuesto es incoherente, el sistema conserva la vista previa validada anteriormente en lugar de emitir un árbol de UI dañado.
En estructuras simples con una sola raíz, o con un único hijo en una sola ranura, la segunda evaluación de diseño puede ni siquiera ser necesaria. (json-render.dev)
Editar una interfaz también es elegir, no reescribirla por completo
json-render también puede editar un Spec existente, por ejemplo:
- eliminar el botón Guardar;
- mover la tabla de pedidos por encima del gráfico;
- sustituir un tipo de gráfico por otro candidato ya disponible;
- cambiar el orden de los campos;
- reemplazar la configuración de un componente.
Estas ediciones suelen seguir un protocolo secuencial:
- Seleccionar el elemento que debe cambiar.
- Seleccionar la nueva receta de componente o el destino.
- Aplicar el cambio mediante código.
- Validar de nuevo el árbol completo.
Siempre que es posible, se conservan los identificadores de componentes no modificados, los enlaces de estado, los datos y los hijos compatibles. El Spec de entrada no se muta directamente. (json-render.dev)
Elegir un botón no significa que se ejecute automáticamente
json-render separa con claridad «componer la interfaz» de «ejecutar una acción de negocio».
Jev puede seleccionar un botón enlazado a savePreferences, pero el composer no invoca esa acción. La ejecución solo ocurre cuando el usuario hace clic y la gestiona el action handler de la aplicación anfitriona.
La aplicación todavía debe encargarse de:
- verificar los permisos del usuario;
- validar los argumentos;
- aplicar autorización en el servidor;
- comprobar la validez de los datos;
- garantizar idempotencia y auditoría;
- pedir una segunda confirmación para operaciones peligrosas.
La documentación advierte expresamente que registrar una acción en el catálogo no la vuelve segura para aceptar argumentos arbitrarios. El composer tampoco puede validar el estado futuro en tiempo de ejecución ni autorizar en nombre de la aplicación. (json-render.dev)
Una estructura válida no significa que la interfaz sea necesariamente correcta
json-render puede garantizar que la salida se ajusta a su estructura y esquema admitidos, pero no que la interfaz elegida por Jev sea completa, razonable o visualmente buena.
La documentación ofrece este ejemplo:
Genera un panel con la tabla en la parte superior
Esta petición puede seleccionar solo una tabla porque no exige explícitamente métricas ni un gráfico.
Una solicitud más específica:
Crea un panel de ventas:
coloca la tabla de pedidos en la parte superior;
debajo, coloca una fila de métricas de ingresos, pedidos y clientes nuevos;
al final, coloca el gráfico de ingresos semanales.
tiene más probabilidades de seleccionar todos los candidatos necesarios y ordenarlos como se espera.
Esto muestra un límite importante: Jev solo decide dentro del espacio de candidatos; el desarrollador sigue siendo responsable de que ese espacio esté completo y de que la solicitud sea clara.
La API reutilizable descrita en la documentación pública limita por defecto el proceso a un máximo de 32 evaluaciones, 32 elementos creados por lote y una profundidad máxima de 8. El Playground público reduce los límites a 14 elementos por lote, 14 evaluaciones y profundidad 4. Cuando se alcanza un límite de llamadas, elementos o profundidad, el sistema puede devolver un Spec parcial, pero que «el proceso haya terminado» no significa que el resultado sea semánticamente correcto. (json-render.dev)
En realidad, los dos ejemplos usan la misma arquitectura
Si colocamos Browser Use y json-render uno al lado del otro, vemos que resuelven problemas distintos con una estructura casi idéntica.
| Etapa | Browser Use | json-render |
|---|---|---|
| Objetivo del usuario | Buscar un vuelo, rellenar un formulario, abrir una página | Crear o modificar una interfaz |
| Estado leído por el código | DOM visible, controles, texto y valores | Spec actual, candidatos de componentes, catálogo y estructura del árbol |
| Espacio finito de candidatos | Clic, entrada, selección, desplazamiento y elementos interactivos | Instancias de componentes, padres, ranuras y orden |
| Responsabilidad de Jev | Elegir la acción y el objetivo | Elegir componentes, relaciones padre-hijo y orden |
| Responsabilidad del modelo generativo | Generar texto solo cuando se necesita introducirlo | En la ruta de Jev, no genera libremente la UI; los textos y datos nuevos deben proporcionarse antes o generarse por separado |
| Responsabilidad del código convencional | Instantáneas del DOM, comprobación de vigencia, ejecución, espera y verificación del resultado | Ensamblaje del Spec, validación del esquema, validación del árbol, renderizado y autorización de acciones |
| Principales modos de fallo | Estado de página obsoleto, objetivo ausente, controles no compatibles | Candidatos ausentes, solicitud ambigua, diseño incompleto, selección deficiente |
| Verificación final | Comprobar si el objetivo de la tarea se cumplió realmente | Comprobar si el Spec está completo, es utilizable y cumple los requisitos del producto |
Ambos siguen la misma fórmula:
Convertir el entorno en estado estructurado
↓
Convertir las acciones posibles en un conjunto finito de candidatos
↓
Dejar que Jev elija
↓
Dejar que el código valide y ejecute
↓
Volver a observar el resultado
Frente a la generación libre del siguiente paso, este enfoque renuncia a parte de la flexibilidad a cambio de límites de control más claros.
Por qué un modelo que no genera texto puede seguir pareciendo «inteligente»
La inteligencia no tiene por qué expresarse como un artículo, un programa o una conversación.
En muchos flujos de software, el sistema solo necesita una decisión:
- ¿Qué botón debe pulsarse ahora?
- ¿En qué zona debe colocarse este elemento?
- ¿Debe continuar la ejecución?
- ¿Qué configuración de componente encaja mejor con la petición del usuario?
- ¿El resultado actual ya ha cumplido el objetivo?
Un LLM de propósito general puede generar primero una explicación y después envolver la respuesta en JSON. Pero si el código solo necesita una opción, buena parte de ese texto intermedio puede no aportar valor.
Los experimentos de Browser Use y json-render trasladan una parte mayor del «proceso de pensamiento» al diseño del sistema:
- el desarrollador define el estado;
- el desarrollador define el espacio de candidatos;
- el desarrollador define las reglas de ejecución;
- el modelo cubre únicamente las decisiones semánticas que las reglas tradicionales no resuelven bien.
Esta arquitectura no elimina los errores; cambia su forma.
Jev no devolverá un componente o una acción fuera del conjunto de candidatos, pero aún puede:
- elegir el botón equivocado;
- elegir el componente equivocado;
- declarar el final demasiado pronto;
- escoger una distribución peor entre varias razonables;
- omitir contenido necesario porque la solicitud es ambigua.
La seguridad de tipos garantiza la interfaz, no la verdad. El informe de investigación cargado también subraya que una estructura restringida no garantiza una decisión de negocio correcta; el diseño de preguntas, el modelado del estado, los umbrales y la validación independiente siguen siendo fundamentales en producción.
Qué tareas encajan con este patrón
Browser Use y json-render ofrecen una prueba práctica:
Si una tarea puede descomponerse en «elegir entre un conjunto finito de candidatos», puede tener sentido asignar ese nodo de decisión a Jev.
Entre las tareas que encajan relativamente bien están:
- selección de acciones en navegadores y aplicaciones de escritorio;
- enrutamiento de herramientas y habilidades de agentes;
- composición de interfaces a partir de un catálogo de componentes controlado;
- elección entre diseños candidatos;
- clasificación de correos, tickets de soporte y documentos;
- selección de contenido relevante entre pruebas candidatas;
- decisión de reintentar un resultado o escalarlo a una persona.
No conviene entregar directamente a Jev tareas como:
- redactar artículos largos o respuestas de atención al cliente;
- generar textos nuevos que no existen en el conjunto de candidatos;
- diseñar libremente un sistema visual completamente nuevo;
- escribir programas complejos;
- realizar cálculos aritméticos o de fechas de varios pasos;
- inventar una solución cuando no existe una acción candidata;
- tareas que exigen razonamiento prolongado y planificación abierta.
Los productos reales suelen combinar distintos modelos:
Modelo de propósito general: genera objetivos, texto, código o planes candidatos
Jev: juzga, filtra y enruta entre candidatos
Código convencional: valida, ejecuta, aplica alternativas y registra
El pequeño modelo de texto de Browser Use es un ejemplo directo de este reparto: Jev decide que hay que introducir texto; el modelo generativo decide cuál.
La verdadera lección es separar responsabilidades, no los dos demos
Lo más reutilizable de Browser Use y json-render no es que «Jev pueda navegar por la web» o que «Jev pueda generar una UI».
Una conclusión más precisa es:
- Browser Use convierte la operación libre del navegador en selección de acciones sobre elementos DOM reales;
- json-render convierte la escritura libre de JSON de UI en selección y ordenación dentro del catálogo de componentes de la aplicación;
- Jev aporta decisiones semánticas;
- el código limita permisos, mantiene el estado, valida la estructura y ejecuta el resultado;
- cuando hace falta texto abierto, sigue interviniendo un modelo generativo.
Esta arquitectura convierte a la IA, de único conductor del sistema, en un nodo de decisión dentro de un flujo controlado por código.
Para los equipos que realmente quieren incorporar IA al software de producción, esto puede ser más importante que la capacidad de un modelo para generar una respuesta completa de una sola vez. La fiabilidad de un sistema no depende solo de lo que el modelo elige, sino también de:
- qué estado vio el modelo;
- qué candidatos proporcionó el desarrollador;
- qué acciones permite el sistema;
- si los resultados erróneos pueden interceptarse;
- si el sistema puede volver a decidir después de que cambie la página o la interfaz;
- si la finalización se verifica de manera independiente.
No generar texto no significa que Jev no pueda hacer nada.
Significa que la inteligencia del modelo no se expresa principalmente como una cadena, sino como un conjunto de decisiones que el software puede consumir directamente y que, aun así, debe validar con cuidado.