Situación — un laboratorio propio con un sistema sintético
Esto es un laboratorio propio. El sistema de referencia es sintético: un motor de liquidación de siniestros de hogar construido para este laboratorio en Java 8, con los defectos típicos de una migración a Java moderno introducidos a propósito, y su equivalente en Java 21. No hay cliente, no hay datos reales ni un caso de producción detrás. Se publica como ejercicio de método, no como resultado de un proyecto.
La pregunta que lo motiva es la que se hace cualquier responsable cuando un agente de IA propone el código nuevo de una aplicación heredada: el agente puede producir una versión que compila y que parece correcta en minutos, pero ¿quién demuestra que hace lo mismo que la anterior? La documentación funcional de estos sistemas suele ser parcial o inexistente, así que no hay especificación contra la que comparar. Lo único fiable es lo que el sistema viejo hace.
El laboratorio añade una capa de equivalencia a lo ya construido en el proyecto 044: las llamadas del agente al modelo pasan por la pasarela de gobierno de IA de aquel proyecto, y este añade la parte que la pasarela no cubre, que es comprobar el resultado de lo que el modelo genera.
Retos
- Registrar el comportamiento real del sistema actual, no el que debería tener: un conjunto de 5.000 expedientes generado por rangos de negocio, con semilla fija para que cualquier ejecución sea reproducible al céntimo
- Comparar las dos versiones desplegadas, no dos clases en local: lo que demuestra algo sobre lo que se va a servir es la comparación entre dos revisiones vivas
- Clasificar cada divergencia por causa raíz, con su impacto económico, en lugar de entregar un recuento de fallos que nadie pueda interpretar
- Convertir el control de cambios en una condición técnica: que el tráfico no pueda pasar a la versión nueva con el acta en rojo, y que saltarse esa puerta sea un acto deliberado, con nombre y registrado
- Evitar que el árbitro dependa del agente: el agente escribe el código, pero no controla ni los casos ni la comparación
- Garantizar que un acta verde de un entorno anterior no pueda abrir el tráfico de un entorno nuevo
Solución — Cinco piezas entre el agente y el tráfico
La solución es un circuito corto, repetible y sin dependencias externas más allá de un JDK y Python, que se despliega en Azure como infraestructura como código y se destruye al terminar.
// DOS REVISIONES — El sistema viejo y el nuevo, vivos a la vez
- Una sola aplicación en Azure Container Apps con dos revisiones etiquetadas (
legacyymoderno), cada una con su propia URL. El tráfico de producción permanece entero en la versión vieja mientras el arnés interroga a las dos por separado - Imágenes construidas dentro de Azure con Azure Container Registry (
az acr build), sin necesidad de Docker en la máquina del operador - Comprobación de que cada revisión responde por sí misma: el arnés verifica una cabecera de versión en cada respuesta y aborta si una revisión contesta por la otra, porque un reparto de tráfico mal configurado produciría un acta que compara una revisión consigo misma y sale verde
// ARNÉS — Caracterización con semilla fija
- 5.000 expedientes generados a partir de rangos de negocio plausibles (capital asegurado, porcentaje de daño, franquicia, antigüedad, fechas de siniestro y de pago)
- El arnés se ejecuta antes de que el agente toque nada: no se documenta lo que la aplicación debería hacer, se registra lo que hace
- Comparación campo a campo del total liquidado y de los días de demora, con cada divergencia explicada y con su impacto económico
// ACTA Y PUERTA — Un veredicto que mueve el tráfico
- El acta resume casos ejecutados, idénticos y divergentes, causas raíz, impacto económico total y un veredicto explícito
- La puerta de promoción deniega el cambio de tráfico y sale con código de error mientras el acta tenga divergencias sin resolver; el tráfico sigue entero en la versión vieja
- Forzar la promoción existe, pero queda escrita en el acta con quién, cuándo y qué divergencias se ignoraron. Poder saltarse la puerta no es un defecto; lo importante es que sea un acto deliberado y con nombre
- Rollback en un comando: el tráfico vuelve a la revisión vieja
// DIFERENCIA CONTROLADA — Equivalente no es lo mismo que idéntico
- Una divergencia puede aprobarse si negocio la acepta de forma concreta: una causa raíz, un número de casos, un impacto económico estimado y un responsable que firma
- El alcance es estricto: la excepción cubre esa forma exacta, no una familia de casos. Si aparece otra divergencia, el veredicto vuelve a ser negativo
- Huella de procedencia: el arnés registra contra qué URLs se ejecutó y la puerta la compara con el entorno actual antes de decidir, de modo que un acta de un despliegue anterior no pueda aprobar uno nuevo
Resultados
Los números son los de una ejecución real con un modelo de lenguaje sobre un sistema sintético con semilla fija; no son un benchmark ni una promesa de lo que ocurrirá con un sistema real. Con otro modelo, otro prompt o otro sistema, las cifras serán distintas; lo que se mantiene es el método.
Lo que falló y lo que aprendimos
- El agente a veces empeora el código al iterar. En una ejecución con una segunda ronda, el agente introdujo días de demora negativos y el arnés rechazó el resultado. Es la razón de que el árbitro sea independiente del agente
- La primera versión de la puerta promocionó con el acta en rojo. El parámetro de entrada y una variable local se llamaban igual salvo por las mayúsculas, y PowerShell no las distingue: asignar el objeto JSON lo convirtió en texto sin avisar y la puerta leyó cero divergencias. Se corrigió y, además, la puerta comprueba ahora que el acta se ha leído de verdad: si las propiedades esperadas vienen vacías, aborta. Un acta que no se puede leer no es un acta limpia
- El acta sobrevive al entorno. Al destruir y redesplegar, el fichero del acta se queda en disco y la puerta lo habría leído tal cual. De ahí la huella de procedencia
- Los fallos graves aparecen en el segundo despliegue. Por eso el ensayo incluye destruir y volver a desplegar, y el espacio de trabajo de registros se purga antes de borrar el grupo para que el nombre no quede reservado
- Prompt Shields es una capa, no una garantía. En la pasarela del proyecto 044, con cuatro variantes de instrucción escondida en el código, la ruta de documentos bloqueó las cuatro y la ruta de prompt de usuario, tres
- Un falso positivo real: un reintento legítimo con rutas de disco dentro del mensaje recibió un 403. El agente limpia ahora las rutas antes de reenviar errores
- Hay un límite de unos 10.000 caracteres por ventana en la pasarela: el código enviado al modelo debe caber o hay que trocearlo
Alcance de laboratorio
Es un entorno de laboratorio efímero y se comporta como tal. Cuatro limitaciones que no trasladaría a producción:
- Red pública en los servicios de seguridad y de modelo (almacén de secretos, Foundry, Content Safety), aceptable en un entorno que se destruye, no en uno que sirve tráfico real
- Un API Management en nivel Developer, sin SLA, adecuado para una prueba y no para una carga de trabajo con compromisos de servicio
- Un sistema de referencia sintético: demuestra el método, no el rendimiento del agente sobre código real, que es más grande, tiene más dependencias y peor documentación
- Un único tipo de transformación (Java 8 a Java 21 en un núcleo de cálculo). Otras migraciones, como cambios de base de datos o de plataforma, exigen otros arneses
El entorno está destruido o programado para destruirse, por lo que no se enlaza a ninguna URL del laboratorio.
Patrón de arquitectura
Agente de modernización ──► pasarela de gobierno de IA ──► modelo
│ propone código nuevo
▼
┌─────────────────────────────────────────────┐
│ Container Apps · una aplicación, 2 revisiones │
│ «legacy» (Java 8) «moderno» (Java 21) │
└───────────────┬─────────────────────────────┘
│ mismos 5.000 expedientes (semilla fija)
▼
Arnés de caracterización ──► comparador ──► ACTA
│ veredicto + procedencia
▼
Puerta de promoción (mueve el tráfico)
· acta limpia / excepción firmada → pasa
· acta en rojo → deniega (forzar queda registrado)
Dos revisiones de una misma aplicación conviven en Azure Container Apps. Un arnés ejecuta el mismo conjunto de expedientes contra las dos, un comparador clasifica las divergencias y emite el acta, y una puerta de promoción solo mueve el tráfico si el acta lo permite o si una diferencia controlada ha sido firmada.
- Caracteriza antes de transformar — la referencia debe registrarse con el sistema viejo antes de que el agente genere una sola línea, y debe ser reproducible (semilla fija) y versionada.
- El árbitro es independiente del agente — si quien escribe el código también puede tocar los casos o la comparación, puede cerrar la brecha por el camino equivocado.
- Compara lo desplegado, no lo compilado — la equivalencia que importa es entre las dos revisiones que se van a servir, y hay que comprobar que cada una responde por sí misma.
- Un acta debe llevar su procedencia — sin saber contra qué entorno se generó, un resultado verde de ayer puede abrir el tráfico de hoy.
- Equivalente no es idéntico — define de antemano qué es una diferencia controlada: concreta, acotada, con impacto estimado y firmada por quien responde del proceso de negocio.
- La puerta debe fallar cerrada — si el acta no se puede leer, la decisión es no promover; y saltarse la puerta debe ser un acto con nombre y registro.
Artículo relacionado
El agente moderniza en minutos; lo que no puede hacer es firmar que el resultado es equivalente. El agente no puede firmar el acta →