Nota 52 · Microsoft Foundry (12/12)

Los hosted agents de Foundry siguen necesitando una puerta de entrada

Los hosted agents llevan el runtime de tu agente a Foundry, no tu puerta de entrada. Cuándo dejar un prompt agent y qué debe seguir controlando tu backend.

30 de octubre de 2026 10 min de lectura

Puntos clave

  • Un hosted agent mueve el runtime: tu código, en un contenedor, con su propia identidad y su propio endpoint. No mueve el inicio de sesión, los roles de la app ni qué usuario puede abrir qué sesión.
  • Saca un agente de un prompt agent solo cuando el propio agente necesite código que un prompt agent no puede expresar. Un despliegue más cómodo no es un motivo.
  • La credencial con la que llama tu backend fija el ámbito de aislamiento. Si llamas con la identidad propia de la app y sin cabecera de usuario, todos los usuarios caen en un mismo ámbito.
  • El aislamiento por usuario para tus propios usuarios necesita una cabecera de usuario y un rol personalizado, e incluso así la plataforma no separa a los usuarios delegados entre sí. Eso lo hace tu mapa de sesiones.
  • Los guardrails pueden fallar en abierto mientras todo devuelve HTTP 200. Prueba un prompt que deba bloquearse en cada protocolo antes de confiar en ellos.
  • Una versión por endpoint, sin reparto de tráfico: el rollout y la fijación de versiones siguen en tu puerta de entrada.

Ahora que los hosted agents de Foundry están disponibles de forma general, la pregunta obvia para cualquiera que opere una web app de agentes es: ¿podemos quitar ya nuestro backend? Foundry ejecutará nuestro código, le dará una identidad y un endpoint y lo escalará a cero. ¿Para qué mantener un App Service delante?

Todavía no he movido ningún agente al runtime hospedado. En las apps de agentes que construyo, los agentes son prompt agents detrás de nuestro propio backend, y "hosted" existe en el catálogo de agentes como valor de runtime aparcado, detrás de un flag. Este post explica por qué está aparcado, qué haría que lo activara y por qué el backend se queda en cualquier caso.

Modelo con nombre: el runtime se mueve, la puerta de entrada se queda

  • Plano de runtime (puede pasar a Foundry): el código que ejecuta el agente, su sandbox, su escalado, su identidad de agente, sus guardrails y sus reglas de salida.
  • Plano de la puerta de entrada (sigue siendo tuyo): quién es el usuario, qué puede usar, qué sesiones y conversaciones son suyas, qué versión recibe y qué le muestra el producto.
  • La junta entre ambos: una llamada por usuario, con una credencial que le dice a Foundry quién es ese usuario.

Dos planos uno junto a otro: la puerta de entrada que conservas se encarga del inicio de sesión y los roles de la app, el mapa de usuario a sesión, el índice de conversaciones y su reanudación, la fijación de versiones y el rollout, las aprobaciones, las citas y la auditoría, y las vistas de uso y coste; el runtime del hosted agent que ejecuta Foundry se encarga de tu código en un contenedor, la identidad y el endpoint del agente, el sandbox por sesión, el escalado a cero, los guardrails y las reglas de salida, y los protocolos; una flecha entre ambos lleva una llamada por usuario con un token de usuario o una cabecera de usuario

Figura 1. Los hosted agents sustituyen el panel de la derecha. Nada de lo que hay a la izquierda se mueve con él.

Contexto y restricción

Foundry Agent Service tiene tres tipos de agente (overview). Los prompt agents son configuración: instrucciones, un modelo y herramientas, y Foundry los ejecuta. Los hosted agents son tu código, en cualquier framework, empaquetado como un contenedor que Foundry ejecuta con un endpoint gestionado, escalado y una identidad de agente dedicada de Microsoft Entra (hosted agents).

Por puerta de entrada me refiero al backend entre el navegador y Foundry: inicia la sesión del usuario, comprueba los roles de la app, decide a qué agentes y sesiones puede llegar, transmite la respuesta en streaming y la muestra. El post 21 y el post 38 explican por qué existe esa capa. Este post trata de si los hosted agents cambian esa respuesta. El estado de los productos que sigue es a octubre de 2026.

Diseño

1. Decide por lo que necesita el agente, no por la comodidad del despliegue

Learn enumera cuándo elegir hosted agents en lugar de prompt agents. Reducido a las preguntas que hago sobre un agente:

  • ¿Necesita su propia orquestación, o un grafo de framework, que las instrucciones y las herramientas no pueden expresar?
  • ¿Necesita un protocolo o un canal que el prompt agent no habla?
  • ¿Necesita archivos y estado de trabajo en un sandbox que sobrevivan entre turnos?
  • ¿Se ejecuta durante mucho tiempo, o en segundo plano, más allá de una solicitud normal?
  • ¿Necesita sus propias reglas de salida para las llamadas salientes?

Si todas las respuestas son no, un prompt agent te da menos de lo que responsabilizarte. Un hosted agent trae una imagen que construir y parchear, un registro que proteger y CPU y memoria que dimensionar. El dimensionamiento es por sesión y la facturación cuenta CPU y memoria en todas las sesiones activas, así que, como dice Learn, sobredimensionar multiplica el coste por tu concurrencia. Las sesiones inactivas escalan a cero tras un timeout que tú fijas, y una reanudación en frío forma parte de tu experiencia de usuario.

Si una respuesta es sí para un agente, ese agente se mueve. No la app.

Camino de decisión para un agente: cinco preguntas sobre orquestación propia, un protocolo o canal propio, archivos y estado en el sandbox, trabajo de larga duración y reglas de salida por agente; cualquier sí mueve ese agente a un runtime hospedado, todo no lo mantiene como prompt agent; una barra debajo indica que, en cualquier caso, la puerta de entrada conserva el inicio de sesión, los roles, el mapa de sesiones, el rollout y la UX del producto

Figura 2. La pregunta es por agente. La respuesta fija un campo del catálogo, no la arquitectura.

2. El runtime es un campo por agente, no un interruptor para toda la app

Esta es la decisión de diseño que mantendría con independencia de la hoja de ruta de la plataforma. Cada agente de nuestro catálogo lleva cómo se ejecuta. Hoy todas las entradas dicen prompt agent. El valor hosted existe, detrás de un flag, sin que nada lo use. Cuando un agente lo necesite, cambia una entrada y la puerta de entrada enruta las llamadas de ese agente a su endpoint hospedado. El inicio de sesión, los roles, las citas, las trazas y la lista de conversaciones están diseñados para que no les importe dónde se ejecuta el agente, así que no deberían cambiar. Las aprobaciones de herramientas son lo que volvería a probar, porque el código propio puede generarlas de otra manera.

La alternativa, decidir de entrada "somos una app de hosted agents", ata el producto a una elección de runtime que solo necesitan algunos agentes. El post 36 muestra el patrón de flags y overlays que uso para esto.

3. La credencial con la que llama tu backend es una decisión de diseño

Los hosted agents aíslan las sesiones por identidad del llamante de forma predeterminada: cada llamante lista y gestiona solo sus propias sesiones (isolate sessions per user). Suena a que la plataforma ha hecho tu autorización por ti. No es así. Depende de quién cree Foundry que es el llamante, y eso lo decide tu backend:

  • Reenviar el usuario. El backend llama en nombre del usuario que ha iniciado sesión, así que Foundry ve a ese usuario. El aislamiento es por usuario, y las herramientas pueden actuar con el propio acceso del usuario mediante la delegación de usuario por conexión (user delegation).
  • Llamar como la app, sin cabecera de usuario. Foundry ve un solo llamante. Las sesiones de todos los usuarios quedan en un mismo ámbito, y no hay contexto de usuario en el que las herramientas puedan delegar.
  • Llamar como la app, con cabecera de usuario. El backend envía un identificador de usuario estable en x-ms-user-identity. Las sesiones quedan acotadas a ese valor. La identidad que llama necesita una data action que no incluye ningún rol integrado, así que creas un rol personalizado para ella; sin él, la llamada devuelve 403. La página de delegación añade que un servicio que llama en nombre de muchos usuarios debería enviar este valor por usuario, para que los usuarios no compartan el estado de inicio de sesión OAuth de las herramientas.

La tercera forma tiene una arista afilada. La advertencia de Learn: dentro de la delegación, la plataforma no separa a un usuario delegado de otro. Solo separa a los llamantes delegados de los no delegados. Enruta a dos usuarios al mismo ID de sesión y podrán ver los datos del otro. La página de sesiones lo dice claramente: la clave de aislamiento "is a partitioning value, not an authentication or authorization mechanism" (manage sessions). Learn también señala que una identidad con el rol Foundry User en el proyecto puede listar y gestionar todas las sesiones del agente. Ten claro quién lo tiene.

He visto la misma trampa con prompt agents. Cuando nuestro backend llama con su propia managed identity, Foundry ve un solo llamante, así que la lista de conversaciones de un usuario tiene que salir de nuestro propio índice por usuario, no de Foundry. Los hosted agents no eliminan ese índice. Lo hacen más importante.

4. Una sesión no es una conversación

Los hosted agents separan dos cosas que las interfaces de chat tienden a mezclar (manage sessions). Una sesión es el sandbox: compute y un sistema de archivos persistente. Una conversación es el historial de mensajes y llamadas a herramientas. En el protocolo Responses, reutilizar un ID de sesión no reproduce el historial; la continuidad viene de la respuesta anterior o de un ID de conversación. En el protocolo Invocations, la plataforma no guarda ningún historial.

Así que la puerta de entrada sigue encargándose del índice de conversaciones: qué conversaciones pertenecen a qué usuario, sus títulos y cómo reanudar una cuando se corta el stream. El post 7 explica por qué ese reloj está separado de la interfaz, y el post 47, dónde vive el índice. Los hosted agents añaden una tercera cosa que mapear: qué sesión pertenece a qué conversación y a qué usuario.

Una regla más de la misma página: los archivos subidos a una sesión acaban en el directorio home del agente. Trátalos como no fiables y nunca cargues desde ahí código, plugins ni configuración.

5. El rollout sigue siendo cosa tuya

Un endpoint de hosted agent sirve una versión cada vez, le envía todo el tráfico y no reparte el tráfico entre versiones (hosted agents). Cada sesión se vincula a una versión al crearse, y version_indicator fija una sesión a una versión concreta para que los turnos posteriores la mantengan después de que publiques otra más nueva.

Eso te da las piezas de un rollout, no el rollout. Un canary, un grupo piloto en la nueva versión o un rollback que no toca las conversaciones en curso son decisiones sobre usuarios, así que pertenecen a la puerta de entrada, que es la que conoce a los usuarios. El eval gate del post 48 se ejecuta antes de publicar una versión; la puerta de entrada decide quién la recibe primero.

6. Prueba el bloqueo, no el despliegue

Los guardrails de los hosted agents se asocian a la definición del agente, y la página de guardrails enumera varias formas en que fallan sin dar error (guardrails):

  • Un nombre de política que no existe: en muchas suscripciones el agente se despliega, aparece como activo y no filtra nada.
  • El protocolo Invocations sin invocations_moderation: la política queda inerte, las solicitudes pasan sin filtrar y el agente devuelve HTTP 200.
  • El protocolo Invocations WebSocket: la moderación de contenido no está disponible.
  • Un cambio de política: los sandboxes en ejecución no lo recogen. Despliegas una nueva versión del agente e inicias o reanudas una sesión.

El streaming añade un trabajo a la puerta de entrada. Un prompt bloqueado en la entrada se rechaza antes de cualquier evento. Pero en el protocolo Invocations, una salida bloqueada a mitad de un stream llega como un evento de error dentro de una respuesta HTTP 200, y puede que el texto anterior ya esté en pantalla. Learn lo dice directamente: un estado 200 por sí solo no significa que la respuesta haya superado la política. La interfaz tiene que tratar ese evento como final y decir que la respuesta se detuvo, no dejar media respuesta con aspecto de completa.

Los controles de salida para hosted agents están en preview y, en palabras de Learn, complementan tus propios controles de red en lugar de sustituirlos.

Puntos en los que un hosted agent falla en abierto mientras devuelve éxito: un nombre de política que no existe, el protocolo Invocations sin ajustes de moderación, el protocolo WebSocket sin moderación, un stream bloqueado que devuelve HTTP 200 con un evento de error tras un texto parcial, una identidad de app que llama sin cabecera de usuario y dos usuarios delegados enrutados a un mismo ID de sesión

Figura 3. Cada uno de estos casos devuelve éxito. La prueba es un prompt que debería bloquearse y un usuario que debería rechazarse.

7. Qué haría que activara el flag

El día en que un agente necesite un grafo de framework, archivos de sandbox entre turnos o trabajo que dure más que una solicitud, la entrada de ese agente en el catálogo pasa a hosted. Antes, tres comprobaciones: el backend llama con una credencial que lleva al usuario, un prompt que debe bloquearse se bloquea en el protocolo que usa ese agente y un segundo usuario no puede llegar a la sesión del primero a través de nuestra API. Ninguna de esas comprobaciones trata del runtime hospedado. Todas tratan de la puerta de entrada.

Errores comunes

Quitar el backend porque el runtime se ha movido. El inicio de sesión, los roles y el mapa de sesiones nunca estuvieron en el runtime.

Llamar como la app sin cabecera de usuario. Todos los usuarios comparten un mismo ámbito de aislamiento.

Reutilizar un ID de sesión entre usuarios. La plataforma no separa a los usuarios delegados entre sí.

Tratar el ID de sesión como la conversación. No reproduce el historial.

Confiar en un guardrail porque el despliegue salió bien. Prueba en cada protocolo un prompt que deba bloquearse.

Tratar un HTTP 200 como éxito en un stream. Gestiona el evento de error.

Dimensionar cada sesión para el peor caso. La factura se multiplica por la concurrencia.

Convertir el runtime en un interruptor para toda la app. Haz que sea un campo por agente.

Úsalo tal cual o adáptalo

Úsalo tal cual

  • Las cinco preguntas por agente, y mover solo el agente que responde que sí.
  • El runtime como campo del catálogo de agentes, detrás de un flag hasta que un agente lo necesite.
  • Un índice de conversaciones y sesiones por usuario en tu propio almacén, comprobado en cada llamada.
  • Una sesión por usuario, nunca compartida entre usuarios delegados salvo que lo hayas diseñado así.
  • Una prueba con un prompt que deba bloquearse en cada protocolo como parte de cada release.

Adáptalo antes de usarlo

  • Reenviar el usuario o enviar una cabecera de usuario desde la app: depende de si tus usuarios inician sesión con Entra y de qué necesitan hacer tus herramientas en nombre del usuario.
  • Cómo fijas versiones para un grupo piloto, dado que no hay reparto de tráfico.
  • El timeout de inactividad y el dimensionamiento de las sesiones, medidos con una carga representativa en lugar de estimados.
  • Si un stream detenido retira el texto parcial o lo marca, según lo que tus usuarios puedan haber copiado ya.

Relacionado

Deja que Foundry ejecute el agente. Sigue decidiendo tú quién puede hablar con él.