Ulyssify bloquea apps y sitios web que te distraen. Tiene un asistente, Anka, que configura los bloqueos por ti en lenguaje natural. La semana pasada falló de una forma muy instructiva:
El sitio había ido a parar a otra lista, con otro comportamiento. El asistente confirmó algo que nunca ocurrió y, cuando se le cuestionó, adivinó.
El diagnóstico tentador es "el modelo no es lo bastante inteligente". En lugar de eso, rastreamos la conversación y encontramos algo mejor: ningún modelo, de ningún tamaño, habría podido responder correctamente. Los datos nunca estuvieron en su contexto. Se perdieron en dos lugares.
Primera fuga: la vista que el agente tiene de tus datos se vuelve obsoleta
Nuestras pantallas de Configuración nunca se quedan atrás, porque muestran lo que sea que devuelva el backend. La vista del asistente era distinta: una función de resumen que alguien escribió a mano, con unos pocos campos, el día en que se lanzó la función. Cuando más tarde el producto incorporó horarios con horas reales, nadie actualizó ese resumen, y nada obligaba a nadie a hacerlo.
Así que el asistente no podía ver que ya existía un horario de medianoche, y propuso reconstruir cosas que el usuario ya tenía. No era estupidez. Era ceguera.
La solución: la paridad es una prueba, no una promesa
Dejamos de confiar en que alguien se acordara. Ahora una prueba de CI lee los campos reales que muestra la UI y exige que cada uno de ellos se le muestre al asistente o se excluya con un motivo por escrito. Si agregas un campo a la UI sin decidir qué pasa con el asistente, la compilación falla en rojo con un mensaje que te dice qué hacer.
Segunda fuga: el asistente narraba su plan, no el resultado
El error de la lista equivocada era peor. El servidor había ejecutado la acción y había guardado exactamente lo que pasó, incluida la lista en la que realmente quedó el sitio. Pero el mensaje de seguimiento del asistente se armaba a partir de su propio plan anterior, más un genérico "ejecutado correctamente". La verdad guardada se descartaba un paso antes de que el modelo la viera.
Ahora el seguimiento se construye a partir del resultado guardado: la lista real, el estado real, los ids reales. Si algo termina en un lugar inesperado, el asistente lo dice, porque eso es lo que se le informó. Y nada de la solicitud puede inyectarse en ese mensaje; cada dato lo genera el servidor.
La parte que nunca falló: dos puertas, un solo control
Una propiedad evitó que esta fuera una historia peligrosa en lugar de una vergonzosa, y es la pieza de nuestro diseño que defenderíamos con más firmeza. El asistente no tiene su propia API. Sus acciones entran al backend una capa por debajo de HTTP y ejecutan exactamente las mismas funciones con controles que ejecuta un clic humano.
Esto importa por quién es el adversario. En un mecanismo de compromiso, la persona más motivada para burlar un bloqueo es el propio usuario, a la 1 a.m., negociando con sus propias decisiones pasadas. Si el asistente tuviera su propia vía de escritura, cada prompt sería un posible resquicio. Como comparte la vía humana, cualquier cosa que afloje el cumplimiento queda en cola detrás del propio período de espera del usuario, sin importar cómo se haya formulado la solicitud. El asistente podía equivocarse. No podía ser una forma de saltarse el bloqueo.
Fíjate en lo que esto no es: no es "pedirle permiso a un humano antes de actuar", algo que ya está bien cubierto en otros lados. Es una afirmación más fuerte sobre la plomería. "El asistente puede hacer todo lo que puede hacer un humano" debería significar paridad de capacidades, no una superficie de API paralela, porque un humano tampoco puede saltarse el período de espera.
La mitad de la aprobación está bien cubierta en el campo: 12-Factor Agents defiende mantener a un humano en el ciclo, y la guía de Anthropic para escribir herramientas para agentes trata sobre devolverle al modelo resultados significativos y con mucha señal. Las afirmaciones sobre la plomería (que la vía de escritura del agente ES la vía humana con controles, y que sus confirmaciones se reconstruyen a partir de la verdad guardada en el servidor) son la parte que no hemos visto documentada, así que la estamos documentando.
Cerramos el ciclo convirtiendo el incidente en una prueba permanente: la configuración exacta de esa conversación ahora es un fixture, y CI verifica que el contexto del asistente contenga todos los datos necesarios para acertar.
- Un resumen de tus datos escrito a mano ya está obsoleto. Haz que la paridad entre la UI y el agente sea una prueba que falle, no una promesa que alguien cumpla.
- Dale al modelo resultados del servidor, nunca su propio plan. Un agente que narra intenciones terminará confirmando una ficción.
- Haz pasar las escrituras del agente por las mismas rutas de código con controles que los clics humanos. Así, un agente confundido resulta vergonzoso, nunca peligroso.
- Arregla lo que el modelo puede ver antes de debatir qué tan inteligente es. Un modelo más grande razonando sobre datos que faltan solo confabula con una prosa más bonita.