Mensaje & Comunicación
Un agente en Saptiva-Agents puede reaccionar, enviar y publicar mensajes, y los mensajes son el único medio a través del cual los agentes pueden comunicarse entre sí.
Mensajes
Los mensajes son objetos serializables y pueden definirse utilizando:
Una subclase de
pydantic.BaseModel
, oUn
dataclass
Manejadores de Mensajes
Cuando un agente recibe un mensaje, el runtime invoca el manejador de mensajes del agente (on_message()
), el cual debe implementar la lógica para manejarlo.
Si el mensaje no puede ser manejado, el agente debe lanzar CantHandleException
.
La clase base
BaseAgent
no implementa manejo de mensajes, por lo tanto, no se recomienda implementar directamenteon_message()
salvo para casos avanzados.
Se recomienda usar la clase RoutedAgent
, que proporciona capacidad incorporada de enrutamiento de mensajes.
Enrutamiento de Mensajes por Tipo
La clase RoutedAgent
permite asociar tipos de mensajes a funciones manejadoras usando el decorador @message_handler
.
Prueba el agente con TextMessage
y ImageMessage
.
El runtime crea automáticamente una instancia de MyAgent
con el ID de agente AgentId("my_agent", "default")
al entregar el primer mensaje.
Enrutamiento de Mensajes del Mismo Tipo
A veces queremos manejar un mismo tipo de mensaje con diferentes funciones, por ejemplo, según el remitente. Para eso usamos match
en @message_handler
.
En el ejemplo anterior, el primer ImageMessage
no es manejado porque el campo source
del mensaje no coincide con la condición de coincidencia (match
) del manejador.
Mensajería Directa
Hay dos formas de comunicación en Saptiva-Agents:
Mensajería Directa: el mensaje va a un agente específico.
Broadcast: el mensaje se publica en un topic y lo reciben múltiples agentes.
Veamos primero la mensajería directa. Para enviar un mensaje directo a otro agente, dentro de un manejador de mensajes se utiliza el método saptiva_agents.core.BaseAgent.send_message()
, y desde el entorno de ejecución se utiliza el método saptiva_agents.core.AgentRuntime.send_message()
. Al esperar (await
) estas llamadas, se devolverá el valor de retorno del manejador de mensajes del agente receptor. Si el manejador del agente receptor devuelve None
, también se devolverá None
.
Solicitud/Respuesta
La mensajería directa puede utilizarse para escenarios de solicitud/respuesta, donde el emisor espera una respuesta del receptor. El receptor puede responder al mensaje devolviendo un valor desde su manejador de mensajes. Puedes pensar en esto como una llamada a función entre agentes.
Por ejemplo, considera los siguientes agentes:
Ambas salidas son producidas por el manejador de mensajes del OuterAgent
, sin embargo, la segunda salida se basa en la respuesta del InnerAgent
.
En términos generales, la mensajería directa es adecuada para escenarios en los que el emisor y el receptor están estrechamente acoplados: se crean juntos y el emisor está vinculado a una instancia específica del receptor. Por ejemplo, un agente ejecuta llamadas a herramientas enviando mensajes directos a una instancia de ToolAgent
, y utiliza las respuestas para formar un bucle de acción-observación.
Broadcast
La difusión (broadcast) es, en esencia, el modelo de publicación/suscripción con temas (topics) y suscripciones. Consulta Topic and Subscription para conocer los conceptos clave.
La diferencia principal entre la mensajería directa y la difusión es que broadcast no puede usarse en escenarios de solicitud/respuesta. Cuando un agente publica un mensaje, es una acción unidireccional: no puede recibir una respuesta de ningún otro agente, incluso si el manejador del agente receptor retorna un valor.
Suscribirse y Publicar en Temas (Topics)
La suscripción basada en tipo (type-based subscription) mapea los mensajes publicados en temas de un tipo específico de tema (topic type) hacia agentes de un tipo específico de agente (agent type).
Para que un agente que hereda de RoutedAgent
se suscriba a un tema de cierto tipo, puedes usar el decorador de clase type_subscription()
.
El siguiente ejemplo muestra una clase ReceiverAgent
que se suscribe a temas del tipo "default"
usando el decorador type_subscription()
, y que imprime los mensajes recibidos.
Usa modelo publish/subscribe con topics. No puede usarse para solicitar respuesta.
Para publicar un mensaje desde el handler de un agente, usa el método publish_message()
y especifica un TopicId
. Esta llamada debe ser awaited para permitir que el runtime programe la entrega del mensaje a todos los suscriptores, pero siempre devolverá None
.
Si un agente lanza una excepción mientras maneja un mensaje publicado, esta será registrada en los logs, pero no será propagada de vuelta al agente que publicó el mensaje.
El siguiente ejemplo muestra un BroadcastingAgent
que publica un mensaje a un tema al recibir un mensaje.
Como se muestra en el ejemplo anterior, también puedes publicar directamente a un tema utilizando el método publish_message()
del runtime, sin necesidad de crear una instancia de agente.
Según la salida, puedes ver que el agente receptor recibió dos mensajes: uno fue publicado a través del runtime y el otro fue publicado por el agente emisor (broadcasting agent).
Default Topic y Subscriptions
En el ejemplo anterior, usamos TopicId
y TypeSubscription
para especificar el tema (topic) y las suscripciones respectivamente. Esta es la forma adecuada para muchos escenarios.
Sin embargo, cuando existe un único ámbito de publicación, es decir, todos los agentes publican y se suscriben a todos los mensajes transmitidos, podemos usar las clases convenientes DefaultTopicId
y default_subscription()
para simplificar nuestro código.
DefaultTopicId
sirve para crear un tema que utiliza "default"
como valor predeterminado para el tipo de tema y la clave del agente emisor como valor predeterminado para el origen del tema. default_subscription()
se utiliza para crear una suscripción de tipo que se suscribe al tema por defecto.
Podemos simplificar BroadcastingAgent
usando DefaultTopicId
y default_subscription()
.
Última actualización