Cree servidores MCP de larga duración en Amazon Bedrock AgentCore con la integración de Strands Agents

Los agentes de IA están evolucionando rápidamente de meras interfaces de chat a trabajadores autónomos sofisticados que manejan tareas complejas que requieren mucho tiempo. A medida que las organizaciones implementan agentes para entrenar modelos de aprendizaje automático (ML), procesar grandes conjuntos de datos y ejecutar simulaciones extendidas, el protocolo de contexto modelo (MCP) se ha convertido en un estándar para las integraciones agente-servidor. Pero persiste un desafío crítico: estas operaciones pueden tardar minutos u horas en completarse, superando con creces los plazos de sesión típicos. Al utilizar Amazon Bedrock AgentCore y Strands Agents para implementar la administración de estado persistente, puede permitir una ejecución fluida de tareas entre sesiones en entornos de producción. Imagine a su agente de IA iniciando un trabajo de procesamiento de datos de varias horas, su usuario cerrando su computadora portátil y el sistema recuperando sin problemas los resultados completos cuando el usuario regresa días después, con visibilidad completa del progreso de la tarea, los resultados y los errores. Esta capacidad transforma a los agentes de IA de asistentes conversacionales en trabajadores autónomos confiables que pueden manejar operaciones a escala empresarial. Sin estos patrones arquitectónicos, encontrará errores de tiempo de espera, utilización ineficiente de recursos y posible pérdida de datos cuando las conexiones finalicen inesperadamente.

En esta publicación, le brindamos un enfoque integral para lograrlo. Primero, presentamos una estrategia de mensajes contextuales que mantiene una comunicación continua entre servidores y clientes durante operaciones extendidas. A continuación, desarrollamos un marco de gestión de tareas asincrónicas que permite a sus agentes de IA iniciar procesos de larga duración sin bloquear otras operaciones. Finalmente, demostramos cómo combinar estas estrategias con Amazon Bedrock AgentCore y Strands Agents para crear agentes de IA listos para producción que puedan manejar operaciones complejas y que requieren mucho tiempo de manera confiable.

Enfoques comunes para manejar tareas de larga duración

Al diseñar servidores MCP para tareas de larga duración, es posible que se enfrente a una decisión arquitectónica fundamental: ¿debería el servidor mantener una conexión activa y proporcionar actualizaciones en tiempo real, o debería desacoplar la ejecución de la tarea de la solicitud inicial? Esta elección conduce a dos enfoques distintos: mensajería contextual y gestión de tareas asíncronas.

Usar mensajes contextuales

El enfoque de mensajería contextual mantiene una comunicación continua entre el servidor MCP y el cliente durante la ejecución de la tarea. Esto se logra mediante el uso del objeto de contexto integrado de MCP para enviar notificaciones periódicas al cliente. Este enfoque es óptimo para escenarios en los que las tareas normalmente se completan en 10 a 15 minutos y la conectividad de la red permanece estable. El enfoque de mensajería contextual ofrece estas ventajas:

Implementación sencilla No se requiere lógica de sondeo adicional Implementación sencilla del cliente Mínima sobrecarga

Usando la gestión de tareas asincrónicas

El enfoque de gestión de tareas asíncronas separa el inicio de tareas de la ejecución y la recuperación de resultados. Después de ejecutar la herramienta MCP, la herramienta devuelve inmediatamente un mensaje de inicio de tarea mientras la ejecuta en segundo plano. Este enfoque sobresale en escenarios empresariales exigentes donde las tareas pueden ejecutarse durante horas, los usuarios necesitan flexibilidad para desconectarse y volver a conectarse, y la confiabilidad del sistema es primordial. El enfoque de gestión de tareas asíncronas proporciona estos beneficios:

Verdadera operación de disparar y olvidar Desconexión segura del cliente mientras las tareas continúan procesándose Prevención de pérdida de datos mediante almacenamiento persistente Soporte para operaciones de larga duración (horas) Resiliencia contra interrupciones de la red Flujos de trabajo asincrónicos

Mensajería contextual

Comencemos explorando el enfoque de mensajería contextual, que proporciona una solución sencilla para manejar operaciones moderadamente largas mientras se mantienen conexiones activas. Este enfoque se basa directamente en las capacidades existentes de MCP y requiere una infraestructura adicional mínima, lo que lo convierte en un excelente punto de partida para ampliar los límites de tiempo de procesamiento de su agente. Imagine que ha creado un servidor MCP para un agente de IA que ayuda a los científicos de datos a entrenar modelos de aprendizaje automático. Cuando un usuario le pide al agente que entrene un modelo complejo, el proceso subyacente puede tardar entre 10 y 15 minutos, mucho más que el límite de tiempo de espera HTTP típico de 30 segundos a 2 minutos en la mayoría de los entornos. Sin una estrategia adecuada, la conexión se cortaría, la operación fallaría y el usuario quedaría frustrado. En una implementación de transporte HTTP Streamable para cliente MCP, estas restricciones de tiempo de espera son particularmente limitantes. Cuando la ejecución de la tarea excede el límite de tiempo de espera, la conexión se cancela y el flujo de trabajo del agente se interrumpe. Aquí es donde entra en juego la mensajería contextual. El siguiente diagrama ilustra el flujo de trabajo al implementar el enfoque de mensajería contextual. La mensajería contextual utiliza el objeto de contexto integrado de MCP para enviar señales periódicas desde el servidor al cliente MCP, manteniendo activa la conexión durante operaciones más largas. Piense en ello como enviar mensajes de "latido" que ayudan a evitar que la conexión se agote.

Figura 1: Ilustración del flujo de trabajo en el enfoque de mensajería contextual

A continuación se muestra un ejemplo de código para implementar la mensajería contextual:

from mcp.server.fastmcp import Context, FastMCP import asyncio mcp = FastMCP(host="0.0.0.0", stateless_http=True) @mcp.tool() async def model_training(model_name: str, epochs: int, ctx: Context) -> str: """Ejecutar una tarea con actualizaciones de progreso.""" for i in range(epochs): # Simular entrenamiento de larga duración progreso del trabajo = (i + 1) / épocas en espera asyncio.sleep(5) espera ctx.report_progress( progreso=progreso, total=1.0, mensaje=f"Paso {i + 1}/{épocas}", ) devuelve f"{nombre_modelo} entrenamiento completado. El artefacto del modelo se almacena en s3://templocation/model.pickle. La puntuación de entrenamiento del modelo es 0,87, la puntuación de validación es 0,82." si __name__ == "__main__": mcp.run(transport="streamable-http")

El elemento clave aquí es el parámetro Contexto en la definición de la herramienta. Cuando incluye un parámetro con la anotación de tipo Contexto, FastMCP inyecta automáticamente este objeto, brindándole acceso a métodos como ctx.info() y ctx.report_progress(). Estos métodos envían mensajes al cliente conectado sin finalizar la ejecución de la herramienta.

Las llamadas report_progress() dentro del bucle de entrenamiento sirven como mensajes de latido críticos, asegurando que la conexión MCP permanezca activa durante todo el período de procesamiento extendido.

En muchos escenarios del mundo real, el progreso exacto no se puede cuantificar fácilmente, como cuando se procesan conjuntos de datos impredecibles o se realizan llamadas API externas. En estos casos, puedes implementar un sistema de latidos basado en el tiempo:

desde mcp.server.fastmcp import Context, FastMCP import time import asyncio mcp = FastMCP(host="0.0.0.0", stateless_http=True) @mcp.tool() async def model_training(model_name: str, epochs: int, ctx: Context) -> str: """Ejecutar una tarea con actualizaciones de progreso.""" done_event = asyncio.Event() start_time = time.time() async def timer(): mientras no done_event.is_set(): transcurrido = time.time() – start_time await ctx.info(f"Procesando…: {elapsed:.1f} segundos transcurridos") await asyncio.sleep(5) # Verifique cada 5 segundos return timer_task = asyncio.create_task(timer()) ## main tarea###################################### para i en el rango (épocas): # Simular el progreso del trabajo de entrenamiento de tiempo de ejecución prolongado = (i + 1) / las épocas esperan asyncio.sleep(5) ################################################### Señalar al cronómetro para que se detenga y limpie done_event.set() await timer_task total_time = time.time() – start_time print(f"⏱️ Tiempo total de procesamiento: {total_time:.2f} segundos") return f"{model_name} entrenamiento completado El artefacto del modelo se almacena en s3://templocation/model.pickle. La puntuación de entrenamiento del modelo es 0,87 y la puntuación de validación es 0,82. si __name__ == "__main__": mcp.run(transport="streamable-http")

Este patrón crea un temporizador asincrónico que se ejecuta junto con su tarea principal y envía actualizaciones de estado periódicas cada pocos segundos. El uso de asyncio.Event() para la coordinación facilita el apagado limpio del temporizador cuando se completa el trabajo principal.

Cuándo utilizar mensajes contextuales

La mensajería contextual funciona mejor cuando:

Las tareas tardan entre 1 y 15 minutos en completarse* Las conexiones de red son generalmente estables La sesión del cliente puede permanecer activa durante toda la operación Necesita actualizaciones de progreso en tiempo real durante el procesamiento Las tareas tienen tiempos de ejecución finitos y predecibles con condiciones de finalización claras

*Nota: “15 minutos” se basa en el tiempo máximo para solicitudes sincrónicas que ofrece Amazon Bedrock AgentCore. Puede encontrar más detalles sobre las cuotas de servicio de Bedrock AgentCore en Cuotas para Amazon Bedrock AgentCore. Si la infraestructura que aloja al agente no implementa límites de tiempo estrictos, tenga mucho cuidado al utilizar este enfoque para tareas que podrían bloquearse o ejecutarse indefinidamente. Sin las protecciones adecuadas, una tarea bloqueada podría mantener una conexión abierta indefinidamente, lo que provocaría el agotamiento de los recursos, procesos que no responden y, potencialmente, problemas de estabilidad en todo el sistema.

Aquí hay algunas limitaciones importantes a considerar:

Se requiere conexión continua: la sesión del cliente debe permanecer activa durante toda la operación. Si el usuario cierra su navegador o la red se cae, el trabajo se pierde. Consumo de recursos: mantener las conexiones abiertas consume recursos del servidor y del cliente, lo que potencialmente aumenta los costos de las operaciones de larga duración. Dependencia de la red: la inestabilidad de la red aún puede interrumpir el proceso y requerir un reinicio completo. Límites de tiempo de espera máximos: la mayoría de las infraestructuras tienen límites de tiempo de espera estrictos que no se pueden eludir con mensajes de latido.

Por lo tanto, para operaciones verdaderamente de larga duración que pueden llevar horas o para escenarios en los que los usuarios necesitan desconectarse y volver a conectarse más tarde, necesitará el enfoque de administración de tareas asincrónicas más sólido.

Gestión de tareas asíncronas

A diferencia del enfoque de mensajería contextual donde los clientes deben mantener conexiones continuas, el patrón de gestión de tareas asíncronas sigue un modelo de "disparar y olvidar":

Inicio de tarea: el cliente realiza una solicitud para iniciar una tarea e inmediatamente recibe un ID de tarea. Procesamiento en segundo plano: el servidor ejecuta el trabajo de forma asincrónica, sin necesidad de conexión del cliente. Comprobación de estado: el cliente puede volver a conectarse cuando quiera para comprobar el progreso utilizando el ID de la tarea. Recuperación de resultados: cuando se completan, los resultados permanecen disponibles para su recuperación siempre que el cliente se vuelva a conectar.

La siguiente figura ilustra el flujo de trabajo en el enfoque de gestión de tareas asincrónicas.

Diagrama de secuencia que muestra la arquitectura del Protocolo de contexto modelo (MCP) con manejo de tareas asíncrono. Seis componentes: usuario, agente (procesador de IA), servidor MCP, herramienta MCP (ejecutor de tareas), herramienta de verificación de tareas (verificador de estado) y caché (almacenamiento de resultados). Flujo: El usuario consulta al Agente → El agente solicita el servidor MCP → El servidor invoca la herramienta MCP → El usuario recibe un aviso inmediato con el ID de la tarea → La herramienta se ejecuta y almacena el resultado en la caché → El usuario verifica el estado de la tarea a través del Agente → El agente solicita la herramienta Verificar tarea a través del servidor MCP → La herramienta Verificar tarea recupera el resultado de la caché usando el ID de la tarea → El resultado regresa a través del Servidor al Agente → El Agente responde al Usuario. Demuestra procesamiento asincrónico con seguimiento de tareas y almacenamiento en caché.

Figura 2: Ilustración del flujo de trabajo en un enfoque de gestión de tareas asíncrono

Este patrón refleja cómo interactúa con los sistemas de procesamiento por lotes en entornos empresariales: envíe un trabajo, desconéctelo y vuelva a consultarlo más tarde cuando sea conveniente. A continuación se muestra una implementación práctica que demuestra estos principios:

desde mcp.server.fastmcp import Context, FastMCP import asyncio import uuid desde escribir import Dict, Any mcp = FastMCP(host="0.0.0.0", stateless_http=True) # tareas de almacenamiento de tareas: Dict[str, Dict[str, Any]] = {} async def _execute_model_training( task_id: str, model_name: str, epochs: int ): """Ejecución de tarea en segundo plano.""" task[task_id]["status"] = "running" for i in range(epochs): tareas[task_id]["progress"] = (i + 1) / epochs await asyncio.sleep(2) task[task_id]["result"] = f"{model_name} entrenamiento completado. El artefacto del modelo se almacena en s3://templocation/model.pickle. El modelo La puntuación de entrenamiento es 0,87 y la puntuación de validación es 0,82". tareas[task_id]["estado"] = "completado" @mcp.tool() def model_training( model_name: str, epochs: int = 10 ) -> str: """Iniciar tarea de entrenamiento del modelo.""" task_id = str(uuid.uuid4()) tareas[task_id] = { "status": "iniciado", "progreso": 0.0, "task_type": "model_training" } asyncio.create_task(_execute_model_training(task_id, model_name, epochs)) return f"La tarea de entrenamiento del modelo se inició con el ID de tarea: {task_id}. Vuelve a consultar más tarde para monitorear el estado de finalización y recuperar los resultados". @mcp.tool() def check_task_status(task_id: str) -> Dict[str, Any]: """Verificar el estado de una tarea en ejecución.""" si task_id no está en tareas: return {"error": "tarea no encontrada"} tarea = tareas[task_id] return { "task_id": task_id, "status": tarea["status"], "progress": tarea["progress"], "task_type": task.get("task_type", "unknown") } @mcp.tool() def get_task_results(task_id: str) -> Dict[str, Any]: """Obtener resultados de una tarea completada.""" si task_id no está en las tareas: return {"error": "tarea no encontrada"} task = tareas[task_id] if task["status"] != "completed": return {"error": f"tarea no completada. Estado actual: {tarea['status']}"} return { "task_id": task_id, "status": tarea["status"], "resultado": tarea["resultado"] } if __name__ == "__main__": mcp.run(transport="streamable-http")

Esta implementación crea un sistema de gestión de tareas con tres herramientas MCP distintas:

model_training(): el punto de entrada que inicia una nueva tarea. En lugar de realizar el trabajo directamente,: Genera un identificador de tarea único usando el Identificador único universal (UUID) Crea un registro de tarea inicial en el diccionario de almacenamiento Inicia el procesamiento real como una tarea en segundo plano usando asyncio.create_task() Regresa inmediatamente con el ID de la tarea, lo que permite al cliente desconectarse check_task_status(): permite a los clientes monitorear el progreso a su conveniencia al: Buscar la tarea por ID en el diccionario de almacenamiento Devolver el estado actual y la información de progreso Proporcionar un manejo de errores adecuado para las tareas faltantes get_task_results(): recupera los resultados completados cuando están listos al: Verificar que la tarea existe y está completa. Devolver los resultados almacenados durante el procesamiento en segundo plano. Proporcionar mensajes de error claros cuando los resultados no están listos.

El trabajo real ocurre en la función privada _execute_model_training(), que se ejecuta de forma independiente en segundo plano después de que se completa la solicitud inicial del cliente. Actualiza el estado y el progreso de la tarea en el almacenamiento compartido a medida que avanza, haciendo que esta información esté disponible para verificaciones de estado posteriores.

Limitaciones a considerar

Aunque el enfoque de gestión de tareas asíncronas ayuda a resolver problemas de conectividad, introduce su propio conjunto de limitaciones:

Fricción en la experiencia del usuario: el enfoque requiere que los usuarios verifiquen manualmente el estado de las tareas, recuerden los ID de las tareas en todas las sesiones y soliciten resultados explícitamente, lo que aumenta la complejidad de la interacción. Almacenamiento de memoria volátil: el uso de almacenamiento en memoria (como en nuestro ejemplo) significa que las tareas y los resultados se pierden si el servidor se reinicia, lo que hace que la solución no sea adecuada para la producción sin almacenamiento persistente. Restricciones del entorno sin servidor: en entornos efímeros sin servidor, las instancias finalizan automáticamente después de períodos de inactividad, lo que provoca que el estado de la tarea en memoria se pierda permanentemente. Esto crea una situación paradójica en la que la solución diseñada para manejar operaciones de larga duración se vuelve vulnerable a la duración exacta que pretende soportar. A menos que los usuarios realicen controles periódicos para ayudar a evitar los límites de tiempo de las sesiones, tanto las tareas como los resultados podrían desaparecer.

Avanzando hacia una solución sólida

Para abordar estas limitaciones críticas, debe incluir persistencia externa que sobreviva tanto a los reinicios del servidor como a las terminaciones de instancias. Aquí es donde la integración con servicios de almacenamiento dedicados se vuelve esencial. Al utilizar sistemas de almacenamiento de memoria de agentes externos, puede cambiar fundamentalmente dónde y cómo se mantiene la información de las tareas. En lugar de depender de la memoria volátil del servidor MCP, este enfoque utiliza servicios de almacenamiento de memoria de agente externo persistente que permanecen disponibles independientemente del estado del servidor.

La innovación clave en este enfoque mejorado es que cuando el servidor MCP ejecuta una tarea de larga duración, escribe los resultados provisionales o finales directamente en la memoria externa, como la memoria Amazon Bedrock AgentCore a la que el agente puede acceder, como se ilustra en la siguiente figura. Esto ayuda a crear resiliencia contra dos tipos de fallas en tiempo de ejecución:

La instancia que ejecuta el servidor MCP se puede finalizar debido a la inactividad después de completar la tarea. La instancia que aloja el agente se puede reciclar en entornos efímeros sin servidor.

Diagrama de secuencia que muestra la arquitectura del Protocolo de contexto modelo (MCP) con sincronización basada en eventos y administración de memoria. Cinco componentes: usuario, agente (procesador de IA), memoria AgentCore (almacenamiento de eventos), servidor MCP y herramienta MCP (ejecutor de tareas). Flujo: El usuario consulta al Agente → El agente solicita el servidor MCP con sincronización de eventos a la memoria AgentCore → El servidor invoca la herramienta MCP → La herramienta envía un aviso inmediato → El usuario recibe una notificación → La herramienta se ejecuta y genera el resultado, agregando el evento a la memoria AgentCore → Se producen múltiples operaciones de sincronización de eventos entre el Agente y la memoria AgentCore → El usuario verifica el estado de la tarea → El agente recupera información a través de Sincronización de eventos → El agente responde al usuario. Demuestra una arquitectura basada en eventos con administración de memoria sincronizada en todas las sesiones del agente.

Figura 3. Integración de MCP con memoria externa

Con el almacenamiento de memoria externa, cuando los usuarios vuelven a interactuar con el agente (ya sea minutos, horas o días después), el agente puede recuperar los resultados de la tarea completada del almacenamiento persistente. Este enfoque minimiza las dependencias del tiempo de ejecución: incluso si se finalizan tanto el servidor MCP como las instancias del agente, los resultados de la tarea permanecen conservados de forma segura y accesibles cuando sea necesario.

La siguiente sección explorará cómo implementar esta sólida solución utilizando Amazon Bedrock AgentCore Runtime como entorno de alojamiento sin servidor, AgentCore Memory para almacenamiento de memoria de agente persistente y el marco de Strands Agents para organizar estos componentes en un sistema cohesivo que mantiene el estado de las tareas a través de los límites de la sesión.

Implementación de Amazon Bedrock AgentCore y Strands Agents

Antes de profundizar en los detalles de la implementación, es importante comprender las opciones de implementación disponibles para los servidores MCP en Amazon Bedrock AgentCore. Existen dos enfoques principales: Amazon Bedrock AgentCore Gateway y AgentCore Runtime. AgentCore Gateway tiene un tiempo de espera de 5 minutos para invocaciones, lo que lo hace inadecuado para alojar servidores MCP que proporcionan herramientas que requieren tiempos de respuesta extendidos u operaciones de larga duración. AgentCore Runtime ofrece mucha más flexibilidad con un tiempo de espera de solicitud de 15 minutos (para solicitudes sincrónicas) y una duración máxima ajustable de la sesión (para procesos asincrónicos; la duración predeterminada es de 8 horas) y un tiempo de espera de sesión inactiva. Aunque puede alojar un servidor MCP en un entorno de servidor tradicional para un tiempo de ejecución ilimitado, AgentCore Runtime proporciona un equilibrio óptimo para la mayoría de los escenarios de producción. Obtendrá beneficios sin servidor, como escalado automático, precios de pago por uso y sin administración de infraestructura, mientras que la duración máxima ajustable de la sesión cubre la mayoría de las tareas de larga ejecución del mundo real, desde el procesamiento de datos y la capacitación de modelos hasta la generación de informes y simulaciones complejas. Puede utilizar este enfoque para crear agentes de IA sofisticados sin la sobrecarga operativa de administrar servidores y, al mismo tiempo, reservar implementaciones con servidor solo para los raros casos que realmente requieren ejecuciones de varios días. Para obtener más información sobre las cuotas de servicio de AgentCore Runtime y AgentCore Gateway, consulte Cuotas para Amazon Bedrock AgentCore.

A continuación, analizamos la implementación, que se ilustra en el siguiente diagrama. Esta implementación consta de dos componentes interconectados: el servidor MCP que ejecuta tareas de larga duración y escribe los resultados en AgentCore Memory, y el agente que gestiona el flujo de conversación y recupera esos resultados cuando es necesario. Esta arquitectura crea una experiencia perfecta donde los usuarios pueden desconectarse durante procesos largos y regresar más tarde para encontrar los resultados esperándolos.

Diagrama de arquitectura que muestra el sistema AgentCore Runtime con tres componentes principales y sus interacciones. Izquierda: el usuario interactúa con el Agente (icono de signo de dólar) dentro de AgentCore Runtime, intercambiando consultas y respuestas. El agente se conecta al cliente MCP que envía tareas y recibe resultados de la herramienta. Centro derecha: AgentCore Runtime contiene el servidor MCP con el componente Herramientas. Abajo a la izquierda: Bedrock LLM (icono de cerebro) se conecta al Agente. Abajo en el centro: el componente AgentCore Memory almacena datos de la sesión. Tres flujos de interacción numerados: (1) el cliente MCP se conecta al servidor MCP utilizando el token de portador, el tipo de contenido y los ID de sesión/memoria/actor en el encabezado de la solicitud; (2) Las herramientas escriben los resultados en la memoria AgentCore al finalizar la tarea utilizando ID de sesión/memoria/actor para una continuidad perfecta entre desconexiones; (3) El agente se sincroniza con AgentCore Memory cuando se agregan nuevas conversaciones para la recuperación oportuna de los resultados generados por la herramienta. Demuestra una arquitectura integrada para el procesamiento de tareas basado en agentes con memoria persistente y capacidades LLM.

Implementación del servidor MCP

Examinemos cómo la implementación de nuestro servidor MCP utiliza AgentCore Memory para lograr persistencia:

desde mcp.server.fastmcp importar contexto, FastMCP importar asyncio importar uuid desde escribir importar Dict, cualquier importar json desde bedrock_agentcore.memory importar MemoryClient mcp = FastMCP(host="0.0.0.0", stateless_http=True) agentcore_memory_client = MemoryClient() async def _execute_model_training( model_name: str, epochs: int, session_id: str, actor_id: str, Memory_id: str): """Ejecución de tarea en segundo plano.""" para i en el rango (épocas): await asyncio.sleep(2) intente: respuesta = agentcore_memory_client.create_event( Memory_id=memory_id, actor_id=actor_id, session_id=session_id, mensajes=[ ( json.dumps({ "message": { "role": "usuario", "content": [ { "text": f"{model_name} entrenamiento completado. El artefacto del modelo se almacena en s3://templocation/model.pickle. La puntuación de entrenamiento del modelo es 0,87, la puntuación de validación es 0,82." } ] }, "message_id": 0 }), 'USER' ) ] ) print(response) excepto Excepción como e: print(f"Error al guardar memoria: {e}") return @mcp.tool() def model_training( model_name: str, epochs: int, ctx: Context ) -> str: """Iniciar tarea de entrenamiento del modelo.""" print(ctx.request_context.request.headers) mcp_session_id = ctx.request_context.request.headers.get("mcp-session-id", "") temp_id_list = mcp_session_id.split("@@@") session_id = temp_id_list[0]id_memoria = lista_id_temp[1]actor_id = lista_id_temp[2]asyncio.create_task(_execute_model_training( model_name, epochs, session_id, actor_id, Memory_id ) ) return f"Modelo {model_name}Se ha iniciado la tarea de entrenamiento. El total de épocas de entrenamiento son {épocas}. Los resultados se actualizarán una vez que se complete el entrenamiento." si __name__ == "__main__": mcp.run(transport="streamable-http")

La implementación se basa en dos componentes clave que permiten la persistencia y la gestión de sesiones.

El método agentcore_memory_client.create_event() sirve como puente entre la ejecución de la herramienta y el almacenamiento en memoria persistente. Cuando se completa una tarea en segundo plano, este método guarda los resultados directamente en la memoria del agente en AgentCore Memory utilizando el ID de memoria, el ID de actor y el ID de sesión especificados. A diferencia de los enfoques tradicionales donde los resultados pueden almacenarse temporalmente o requerir una recuperación manual, esta integración permite que los resultados de las tareas se conviertan en partes permanentes de la memoria conversacional del agente. Luego, el agente puede hacer referencia a estos resultados en interacciones futuras, creando una experiencia continua de creación de conocimiento a lo largo de múltiples sesiones. El segundo componente crucial implica extraer el contexto de la sesión a través de ctx.request_context.request.headers.get("mcp-session-id", ""). El "Mcp-Session-Id" es parte del protocolo MCP estándar. Puede utilizar este encabezado para pasar un identificador compuesto que contenga tres datos esenciales en un formato delimitado: session_id@@@memory_id@@@actor_id. Este enfoque permite que nuestra implementación recupere los identificadores de contexto necesarios a partir de un único valor de encabezado. Los encabezados se utilizan en lugar de variables de entorno por necesidad: estos identificadores cambian dinámicamente con cada conversación, mientras que las variables de entorno permanecen estáticas desde el inicio del contenedor. Esta elección de diseño es particularmente importante en escenarios de múltiples inquilinos donde un único servidor MCP maneja simultáneamente solicitudes de múltiples usuarios, cada uno con su propio contexto de sesión distinto.

Otro aspecto importante en este ejemplo implica el formato adecuado de los mensajes al almacenar eventos. Cada mensaje guardado en AgentCore Memory requiere dos componentes: el contenido y un identificador de función. Estos dos componentes deben formatearse de manera que se pueda reconocer el marco del agente. A continuación se muestra un ejemplo del marco de Strands Agents:

mensajes=[ (json.dumps({ "mensaje": { "rol": "usuario", "contenido": [ { "texto": } ] }, "message_id": 0 }), 'USUARIO') ]

El contenido es un objeto JSON interno (serializado con json.dumps()) que contiene los detalles del mensaje, incluida la función, el contenido del texto y el ID del mensaje. El identificador de función externo (USUARIO en este ejemplo) ayuda a AgentCore Memory a categorizar el origen del mensaje.

Implementación de agentes de Strands

La integración de Amazon Bedrock AgentCore Memory con Strands Agents es notablemente sencilla utilizando la clase AgentCoreMemorySessionManager del SDK de Bedrock AgentCore. Como se muestra en el siguiente ejemplo de código, la implementación requiere una configuración mínima: cree un AgentCoreMemoryConfig con sus identificadores de sesión, inicialice el administrador de sesión con esta configuración y páselo directamente al constructor de su agente. El administrador de sesiones maneja de forma transparente las operaciones de memoria detrás de escena, manteniendo el historial de conversaciones y el contexto en todas las interacciones mientras organiza los recuerdos utilizando la combinación de session_id, Memory_id y actor_id. Para obtener más información, consulte Administrador de sesión de memoria AgentCore.

from bedrock_agentcore.memory.integrations.strands.config import AgentCoreMemoryConfig from bedrock_agentcore.memory.integrations.strands.session_manager import AgentCoreMemorySessionManager @app.entrypoint async def strands_agent_main(carga útil, contexto): session_id = context.session_id si no es session_id: session_id = str(uuid.uuid4()) print(f"ID de sesión: {id_sesión}") id_memoria = carga útil.get("id_memoria") si no id_memoria: id_memoria = "" print(f"? ID de memoria: {id_memoria}") id_actor = carga útil.get("id_actor") si no id_actor: id_actor = "default" agentcore_memory_config = AgentCoreMemoryConfig( Memory_id=memory_id, session_id=session_id, actor_id=actor_id ) session_manager = AgentCoreMemorySessionManager( agentcore_memory_config=agentcore_memory_config ) user_input = payload.get("prompt") headers = { "autorización": f"Portador {bearer_token}", "Content-Type": "application/json", "Mcp-Session-Id": session_id + "@@@" + Memory_id + "@@@" + actor_id } # Conéctese a un servidor MCP usando transporte SSE streamable_http_mcp_client = MCPClient( lambda: streamablehttp_client( mcp_url, headers, timeout=30 ) ) con streamable_http_mcp_client: # Obtenga las herramientas del servidor MCP tools = streamable_http_mcp_client.list_tools_sync() # Crear un agente con estas herramientas agente = Agente (herramientas = herramientas, callback_handler=call_back_handler, session_manager=session_manager)

La gestión del contexto de la sesión es aquí especialmente elegante. El agente recibe identificadores de sesión a través de la carga útil y los parámetros de contexto proporcionados por AgentCore Runtime. Estos identificadores forman un puente contextual crucial que conecta las interacciones del usuario en múltiples sesiones. El session_id se puede extraer del objeto de contexto (generando uno nuevo si es necesario) y el Memory_id y el actor_id se pueden recuperar de la carga útil. Luego, estos identificadores se empaquetan en un encabezado HTTP personalizado (Mcp-Session-Id) que se pasa al servidor MCP durante el establecimiento de la conexión.

Para mantener esta experiencia persistente en múltiples interacciones, los clientes deben proporcionar constantemente los mismos identificadores al invocar al agente:

# invocar agentcore a través de boto3 boto3_response = agentcore_client.invoke_agent_runtime( agentRuntimeArn=agent_arn, qualifier="DEFAULT", payload=json.dumps( { "prompt": user_input, "actor_id": actor_id, "memory_id": Memory_id }), runtimeSessionId = session_id,)

Al proporcionar consistentemente el mismo Memory_id, actor_id y runtimeSessionId en todas las invocaciones, los usuarios pueden crear una experiencia de conversación continua donde los resultados de las tareas persisten independientemente de los límites de la sesión. Cuando un usuario regresa días después, el agente puede recuperar automáticamente tanto el historial de conversaciones como los resultados de las tareas que se completaron durante su ausencia.

Esta arquitectura representa un avance significativo en las capacidades de los agentes de IA: transforma operaciones de larga duración de procesos frágiles y dependientes de la conexión en tareas sólidas y persistentes que continúan funcionando independientemente del estado de la conexión. El resultado es un sistema que puede brindar asistencia de IA verdaderamente asincrónica, donde el trabajo complejo continúa en segundo plano y los resultados se integran perfectamente cada vez que el usuario regresa a la conversación.

Conclusión

En esta publicación, exploramos formas prácticas de ayudar a los agentes de IA a manejar tareas que tardan minutos o incluso horas en completarse. Ya sea que utilice el enfoque más sencillo de mantener vivas las conexiones o el método más avanzado de inyectar resultados de tareas en la memoria del agente, estas técnicas le permiten a su agente de IA abordar trabajos complejos y valiosos sin límites de tiempo frustrantes ni pérdida de resultados.

Le invitamos a probar estos enfoques en sus propios proyectos de agentes de IA. Comience con mensajes contextuales para tareas moderadas y luego pase a la administración asíncrona a medida que crezcan sus necesidades. Las soluciones que hemos compartido se pueden adaptar rápidamente a sus necesidades específicas, ayudándole a crear una IA que proporcione resultados confiables, incluso cuando los usuarios se desconectan y regresan días después. ¿Qué tareas de larga duración podrían realizar mejor sus asistentes de IA con estas técnicas?

Para obtener más información, consulte la documentación de Amazon Bedrock AgentCore y explore nuestro cuaderno de muestra.

Acerca de los autores

Haochen Xie es científico de datos sénior en el Centro de innovación de IA generativa de AWS. Es una persona común y corriente.

Flora Wang es científica aplicada en el Centro de innovación de IA generativa de AWS, donde trabaja con clientes para diseñar e implementar soluciones escalables de IA generativa que aborden sus desafíos comerciales únicos. Se especializa en técnicas de personalización de modelos y sistemas de IA basados ​​en agentes, ayudando a las organizaciones a aprovechar todo el potencial de la tecnología de IA generativa.

Yuan Tian es científico aplicado en el Centro de innovación de IA generativa de AWS, donde trabaja con clientes de diversas industrias (incluidas la atención médica, las ciencias biológicas, las finanzas y la energía) para diseñar e implementar soluciones de IA generativa, como sistemas agentes. Aporta una perspectiva interdisciplinaria única, combinando experiencia en aprendizaje automático con biología computacional.

Hari Prasanna Das es científico aplicado en el Centro de innovación de IA generativa de AWS, donde trabaja con clientes de AWS en diferentes sectores verticales para acelerar el uso de la IA generativa. Hari tiene un doctorado en Ingeniería Eléctrica y Ciencias de la Computación de la Universidad de California, Berkeley. Sus intereses de investigación incluyen IA generativa, aprendizaje profundo, visión por computadora y aprendizaje automático con uso eficiente de datos.