Casi todo lo que se publica sobre gobierno de IA generativa describe una arquitectura y se detiene ahí. El diagrama sale limpio, las cajas encajan y la conclusión es que el problema está resuelto. Este artículo tiene dos mitades: la primera cuenta qué construí y por qué; la segunda, qué se rompió. La segunda es la que importa, porque tres de los trece fallos son imposibles de encontrar si solo despliegas una vez, y otros tres no los detecta ninguna prueba automática.
El encargo era preparar una demo de gobierno de IA para una sesión ejecutiva con directivos del sector financiero. No una presentación: algo desplegado, funcionando y proyectable en directo. Lo construí en un laboratorio de Azure y lo destruí después. Todo lo que sigue ocurrió de verdad, en una tarde.
El problema no es el modelo. Es la puerta.
En una entidad regulada, la conversación sobre IA generativa ya no va de si el modelo es suficientemente bueno. Los de 2026 lo son de sobra para el backoffice. Va de cuatro preguntas que un CISO hace en el primer minuto y que casi ninguna prueba de concepto sabe responder: quién entra, qué se le permite, dónde se ejecuta y qué queda escrito.
Fíjate en que ninguna es una pregunta sobre el modelo. Son preguntas sobre la puerta. Y la puerta, en la mayoría de los pilotos, no existe: cada equipo llama al endpoint con una clave compartida por Teams, sin cuota, sin registro y sin nadie capaz de decir a fin de mes qué área ha gastado qué.
Una torre de control de IA es esa puerta. Se pone delante de lo que el cliente ya tiene desplegado, sin sustituir nada.
Seis piezas, y por qué cada una
Una pasarela como punto único de acceso. Azure API Management delante del modelo. Ningún consumidor habla directamente con la inferencia. Esto es lo que hace posible todo lo demás: sin un punto de paso obligatorio no hay control que aplicar.
Identidad por unidad de negocio, no una clave para todos. Un producto de APIM por área —Riesgos, Clientes, Operaciones— cada uno con su suscripción. Una clave compartida no es una identidad: no se puede revocar por equipo, ni auditar, ni someter a acceso condicional. Y sin identidad no hay las otras tres respuestas.
La pasarela se autentica contra el modelo con su propia identidad gestionada. Ninguna clave del modelo circula por la red ni vive en un fichero de configuración. La cuenta de inferencia tiene la autenticación local desactivada: solo Entra ID.
Guardrails antes de gastar un token. Azure AI Content Safety con Prompt Shields evalúa la entrada antes de que llegue al modelo. Un intento de inyección se corta en la puerta y consume cero tokens. Que consuma cero no es un detalle de coste: es la diferencia entre un control preventivo y un informe post mortem.
Cuota por área, en tokens por minuto. Riesgos 5.000, Clientes 2.000, Operaciones 1.000. Es un control de seguridad y de coste a la vez, y es lo que convierte «la factura de IA» en algo que un comité puede repartir.
El expediente se escribe solo. Cada llamada deja una fila en Log Analytics con la unidad responsable, el modelo, la región y el veredicto. El artículo 12 del AI Act pide registros; la diferencia entre cumplirlo y no cumplirlo es si el expediente se construye en el momento de la llamada o el día que aparece el supervisor.
Las tres cosas que hay que poder enseñar
Una demo de gobierno se sostiene sobre tres momentos, y los tres son fallos controlados:
- La consulta legítima pasa y devuelve, en cabeceras visibles, quién preguntó, con qué modelo, en qué región y cuánta cuota le queda.
- El intento de manipulación se bloquea con un mensaje legible que explica por qué, no con un error genérico de la plataforma.
- La cuota se agota y el área se queda fuera, mientras las demás siguen operando.
Enseñar solo el primero es enseñar un chatbot. El valor está en los otros dos.
Hasta aquí la parte que se puede diseñar en una pizarra. Ahora la que no.
Al tercer intento salió limpio. Ese fue el problema.
Los dos primeros despliegues murieron por errores de plataforma: los arreglé y al tercero todo subió, las pruebas pasaron y el entorno quedó funcionando. Si me hubiera parado ahí —como se para la mayoría de las pruebas de concepto— habría entregado algo que parecía terminado.
Volví a desplegar sobre el mismo entorno, sin cambiar nada relevante. Falló. Lo arreglé, volví a desplegar, falló otra vez. Trece fallos en total, en cuatro familias. Ninguna es exótica: son la clase de cosa que le pasa a cualquiera que monte esto.
Familia 1 — Los que solo existen la segunda vez
La iniciativa de Azure Policy que impone el gobierno bloqueó el despliegue de la propia demo. La regla exigía desactivar la autenticación local en toda cuenta de servicios cognitivos, y la cuenta de Content Safety no puede cumplirla: la pasarela la invoca con una credencial de backend, y un backend no admite identidad gestionada. El primer despliegue coló de milagro porque la política se asigna al final, cuando esa cuenta ya existía. A partir de ahí, cualquier redespliegue moría.
Detrás había dos más de la misma familia. Al corregir la política añadí un parámetro nuevo sin valor por defecto: Azure Policy rechaza eso en definiciones que ya existen, porque dejaría las asignaciones vivas con un parámetro sin resolver. Y el Key Vault, con protección de purga y siete días de retención, sobrevive al borrado del entorno; como su nombre se deriva de forma determinista del grupo de recursos, al reconstruir el entorno la semana siguiente el nombre está ocupado por un vault fantasma y la creación falla.
Ninguno de los tres es visible en un despliegue limpio desde cero. Los tres son caminos de código que solo se recorren cuando algo ya existe.
Familia 2 — Los que ninguna prueba automática ve
Escribí un script de pruebas que ejercitaba los tres momentos de la demo contra el endpoint. Daba verde en los tres. La demo estaba rota.
En la pasarela, la respuesta de bloqueo se construye desde cero para poder devolver un JSON legible. Al construirla desde cero se pierden las cabeceras CORS que añade la política del gateway. Resultado: el navegador rechazaba el 403 del guardrail y el 429 de la cuota antes de que el JavaScript pudiera leerlos, y la consola mostraba «Failed to fetch». Los dos momentos que sostienen la demo eran los dos únicos que fallaban.
El script no lo veía porque PowerShell no implementa CORS. El fallo existía solo en el navegador, que es exactamente el único sitio donde ocurre la demo.
De la misma familia: la tabla del registro tenía escrito un guion fijo para todo lo que no fuera un 200, así que las filas bloqueadas salían sin región justo en la pantalla donde se habla de soberanía. Y el botón que agota la cuota usaba el área seleccionada en ese momento: con la de cuota más alta, doce llamadas se quedaban al borde del límite y, repartidas en casi un minuto, caían en dos ventanas distintas sin llegar a agotar nada. El tercer momento de la demo funcionaba o no según qué botón hubieras pulsado antes. Una moneda al aire delante de la sala.
Familia 3 — Los que contradicen el discurso
El modelo estaba desplegado en Global Standard. Ese tipo de despliegue procesa la inferencia en cualquier región de Azure del mundo; solo el dato en reposo se queda en la geografía. Es decir: la demo argumentaba soberanía europea, la política de gobierno denegaba servicios de IA fuera de la UE, y el modelo enrutaba fuera de la UE. Cambiarlo a Data Zone Standard —inferencia dentro del EU Data Boundary— fue una palabra en la plantilla, y la cuota disponible lo permitía de sobra.
En la misma línea, la etiqueta «Sweden Central (EU Data Boundary)» que se proyecta en pantalla estaba escrita a mano en la política. El script de despliegue aceptaba otras regiones. Una demo sobre dónde se ejecuta la inferencia podía mostrar, con toda la confianza del mundo, una región que no era la real.
Este es el tipo de fallo que no rompe nada. Simplemente convierte tu argumento en algo que no se sostiene si alguien mira.
Familia 4 — Los que la plataforma no perdona
Los aburridos, pero los que consumen la tarde. El cifrado con clave del cliente exigía la versión de la clave y el mensaje de error se quejaba de otra cosa. Una métrica de consumo llevaba una dimensión personalizada sin valor, y las dimensiones personalizadas lo exigen. Y el manejador de errores accedía al objeto de respuesta sin comprobar que existiera: cuando el error ocurre antes de llamar al backend ese objeto es nulo, la excepción se produce dentro del propio manejador y la pasarela devuelve un 500 opaco en lugar del 429 preparado. Debajo había un segundo problema en el mismo sitio: el orden de evaluación es producto antes que API, así que la variable con el nombre del área todavía no existía cuando saltaba la cuota.
Lo que me llevo, y lo que te llevarías tú
La conclusión incómoda
La arquitectura de este montaje es discutible en los detalles, pero no tiene ningún misterio: una pasarela, identidades, guardrails, cuotas y registro. Cualquiera con experiencia en Azure la dibuja en una servilleta.
La distancia entre esa servilleta y algo que aguanta quince minutos delante de un comité no está en el diseño. Está en trece fallos: tres que solo existen si despliegas por segunda vez, tres que ninguna prueba automática puede ver, dos que no rompían nada y simplemente convertían el argumento en falso, y cinco de plataforma. Esa distancia es, casi exactamente, la diferencia entre un piloto que impresiona en la demo y una plataforma que alguien puede operar.
Y es la parte que nunca sale en el diagrama.
Nota de transparencia: el entorno se desplegó en un laboratorio de Azure y se destruyó al terminar. Coste total por debajo de 20 €. Sin evento, partner ni fecha real asociados a esta demo — «una entidad regulada» cubre el caso sin comprometer nada.