Un modelo que responde bien en tu máquina no es una función: es una demostración. Entregarla exige estados, medición, un portón humano y un interruptor para apagarla.
Contratas a un practicante brillante y le das las llaves del almacén. Escribe rápido, casi siempre acierta, y cuando se equivoca no lo dice: contesta con la misma seguridad. Lo que necesitas no es uno mejor, es verlo trabajar, una lista de comprobación, alguien que firme lo irreversible y un interruptor para pararlo.
Un token es el trozo mínimo de texto con el que trabaja un modelo: en español, más o menos una palabra corta o parte de una palabra larga. El streaming de tokens es recibir esos trozos conforme se producen en lugar de esperar la respuesta completa. Para la interfaz cambia todo: a los 300 ms ya hay algo en pantalla, y la persona puede cancelar antes de gastar veinte segundos y el costo de la respuesta entera.
Una función de IA tiene más estados que “cargando” y “listo”. Esperando: la petición salió y no hay primer token. Generando: hay texto parcial. Parcial: se cortó por límite de tokens o por cancelación, y lo que hay puede servir. Error recuperable: reintentar tiene sentido. Límite alcanzado: cuota o longitud. Rechazado por el humano: el texto existe pero no se usa. Si el código solo distingue dos, los demás se muestran como error, y un rechazo se ve igual que una caída.
La latencia y el costo son parte de la experiencia, no detalles de operación. La latencia se mide en p95, el tiempo que tarda el 95% de las peticiones: el promedio esconde la cola, que es donde la gente abandona. El costo se mide por generación y por usuario. Mostrar el progreso y el costo estimado no es transparencia decorativa: es lo que permite decidir si vale la pena esperar.
Y la IA no puede ser la única salida. Si el modelo falla, la persona tiene que poder terminar el trabajo a mano o hablar con alguien. Un fallback (una salida de respaldo) a humano no es una derrota técnica: es la diferencia entre una función que se degrada y un incidente.
Un modelo no es determinista: la misma entrada puede dar salidas distintas, y “se siente mejor” no es una medida. La evaluación es un conjunto de casos con resultado conocido y un criterio explícito de qué es aceptable. Sin ese conjunto solo tienes opiniones sobre las últimas cinco respuestas que viste; con él, un cambio de prompt se compara contra la versión actual y el número puede empeorar.
Los guardarraíles tienen dos lados. Lo que no se manda: datos personales, secretos, credenciales; se filtran antes de la petición, no después. Lo que se valida al recibir: que la salida tenga la forma esperada, longitud máxima, enlaces permitidos, HTML escapado. El modelo es una fuente externa: su respuesta se trata como texto de un desconocido, aunque el desconocido seas tú.
Y las acciones irreversibles pasan por una persona. El modelo propone; el humano firma. Ese portón es también un dato: cuántas propuestas se rechazan dice más de la calidad que cualquier encuesta.
Una función de IA sin medición es una demo, y una demo sin fallback es un incidente. Las dos frases apuntan al mismo lugar: si no sabes cómo se está comportando ni qué pasa cuando no responde, no tienes una función, tienes una apuesta.
Modela los estados como una unión discriminada: un tipo con un campo que dice cuál es y datos propios de cada caso. Así el compilador obliga a manejar todos, incluidos el rechazo y el límite. Si el estado es un texto libre con tres banderas, siempre hay una combinación que nadie dibujó.
Para medir, separa RUM de laboratorio. RUM son métricas de usuarios reales, tomadas del navegador de quien usa el producto: ruidosas, pero verdad. El laboratorio es controlado y reproducible, pero de un solo dispositivo. Las dos sirven; confundirlas hace que un portátil rápido decida por todos.
El registro de errores (error tracking) necesita contexto: identificador de la solicitud, modelo, versión del prompt (la instrucción que se le da al modelo), ruta. Sin eso, “falló la IA” no se puede reproducir. Las trazas muestran el camino completo, de la API (la puerta por la que la web pide datos) a la cola y al modelo; sin traza no sabes en qué salto se perdió el tiempo. Y los feature flags (interruptores que se activan sin desplegar) permiten apagar en caliente: un flag que no se evalúa igual en servidor y cliente produce dos versiones de la misma pantalla, así que también se prueba.
// El estado de una generación: cada caso con sus datos, // nada opcional y nada que sobre. type Motivo = 'limite' | 'cancelado'; type Generacion = | { estado: 'esperando'; id: string } | { estado: 'generando'; id: string; texto: string } | { estado: 'parcial'; id: string; texto: string; motivo: Motivo } | { estado: 'error'; id: string; causa: string; reintentar: boolean } | { estado: 'rechazado'; id: string; texto: string; firma: string } | { estado: 'aceptado'; id: string; texto: string; firma: string }; // El compilador exige un caso por estado. Si mañana se // agrega 'revisando', esta función deja de compilar hasta // que alguien decida qué se dibuja en la pantalla. function vista(g: Generacion) { switch (g.estado) { case 'esperando': return <Espera />; case 'generando': return <Texto texto={g.texto} />; case 'parcial': return <Texto texto={g.texto} corte />; case 'error': return <Error causa={g.causa} reintentar={g.reintentar} />; case 'rechazado': return <Rechazo texto={g.texto} firma={g.firma} />; case 'aceptado': return <Entrega texto={g.texto} />; } }
La unión hace visible lo que el producto suele esconder: que “rechazado” no es “error”. Si los dos comparten pantalla, el usuario aprende a ignorar los dos. El practicante no mejora con un reglamento; mejora cuando el reglamento se ejecuta en cada entrega.
Una función de IA se diagnostica como cualquier otra, con una diferencia: hay que mirar también lo que el modelo no respondió.
| Herramienta | Qué se mira | Cómo se ve el síntoma |
|---|---|---|
| Logs de error con contexto | Identificador de solicitud, modelo, versión del prompt y ruta en cada fallo. | Si solo dice “falló la IA”, no se puede reproducir; con el identificador se reconstruye la traza completa. |
| RUM por ruta | Latencia y errores de usuarios reales, separados por pantalla y dispositivo. | Una ruta con p95 de 8 s se ve aunque el promedio global esté bien; el promedio la esconde. |
| Tasa de cancelación | Porcentaje de generaciones canceladas y en qué estado se cancelaron. | Mucha cancelación antes del primer token es un problema de espera percibida, no del modelo. |
| Latencia p95 del modelo | La cola de la distribución, comparada por modelo y por tamaño de entrada. | Un p95 que triplica la mediana significa que una de cada veinte personas espera el triple; esa es la que se va. |
| Tasa de rechazadas | Cuántas respuestas descarta la persona que revisa y por qué motivo. | Si sube, el problema es de calidad o de criterio; si es cero, probablemente nadie está revisando. |
“If you cannot measure it, it is a demo.”
“Every AI feature needs a state for the human saying no.”
“A feature flag is how you turn it off without a deploy.”
Comprueba que lo tienes
Cuatro preguntas. Al comprobar se marca la lección como completada.
Tu componente solo distingue “cargando” y “listo”. El modelo corta por límite de tokens y devuelve texto a medias. ¿Qué muestra la interfaz?
Por qué: el estado parcial existe aunque el código no lo nombre, y al no tener su propia pantalla se confunde con el éxito. El usuario actúa sobre una respuesta truncada creyendo que está entera.
¿Por qué conviene poder cancelar mientras el modelo sigue generando?
Por qué: la generación se cobra por token producido, no por token leído, así que cada segundo de más es costo real. Cancelar también evita que la interfaz se llene de texto que nadie pidió y que tapa el siguiente intento.
Un cambio de prompt “se siente mejor”. ¿Cómo decides si sale a producción?
Por qué: sin casos fijos solo mides los ejemplos que te acuerdas de probar, y esos son justo los que ya sabías que funcionaban. El conjunto convierte “se siente mejor” en una afirmación que puede fallar.
El modelo empieza a responder con un p95 de 40 segundos. ¿Qué haces primero?
Por qué: primero se corta el daño y se mantiene la tarea posible por otra vía; investigar puede esperar treinta minutos, la persona que está intentando trabajar no. Subir el timeout solo alarga la espera, y cambiar de modelo sin medir mezcla dos causas en el mismo incidente.