Envío de notificaciones activas a los usuariosSend proactive notifications to users

se aplica a: SDK V4APPLIES TO: SDK v4

Normalmente, un bot envía un mensaje a un usuario directamente en respuesta a recibir un mensaje del usuario.Typically, a bot sends a message to a user directly in response to receiving a message from the user. En ocasiones, es posible que un bot tenga que enviar un mensaje proactivo , un mensaje en respuesta a la falta de originación del usuario.Occasionally, a bot might need to send a proactive message, a message in response to stimulus not originating from the user.

Los mensajes proactivos pueden ser útiles en diversos escenarios.Proactive messages can be useful in a variety of scenarios. Por ejemplo, si el usuario ha solicitado anteriormente al bot que supervise el precio de un producto, el bot puede alertar al usuario si el precio del producto ha descendido un 20 %.For example, if the user has previously asked the bot to monitor the price of a product, the bot can alert the user if the price of the product has dropped by 20%. O bien, si un bot necesita algo de tiempo para compilar una respuesta a la pregunta del usuario, puede informar al usuario del retraso y permitir que la conversación continúe mientras tanto.Or, if a bot requires some time to compile a response to the user's question, it may inform the user of the delay and allow the conversation to continue in the meantime. Cuando el bot termine de compilar la respuesta a la pregunta, compartirá esta información con el usuario.When the bot finishes compiling the response to the question, it will share that information with the user.

Nota

En este artículo se trata información sobre los mensajes proactivos para bots en general.This article covers information about proactive messages for bots in general. Para obtener información sobre los mensajes proactivos en Microsoft Teams, consulte:For information about proactive messages in Microsoft Teams, see:

RequisitosRequirements

Para poder enviar un mensaje proactivo, el bot necesita una referencia de conversación.Before you can send a proactive message, your bot needs a conversation reference. El bot puede recuperar la referencia de conversación de cualquier actividad que haya recibido del usuario, pero esto normalmente requiere que el usuario interactúe con el bot al menos una vez antes de que el bot pueda enviar un mensaje proactivo.Your bot can retrieve the conversation reference from any activity it has received from the user, but this typically requires the user to interact with the bot at least once before the bot can send a proactive message.

Muchos canales prohíben a un bot enviar mensajes a un usuario a menos que el usuario haya mensaje al bot al menos una vez.Many channels prohibit a bot from messaging a user unless the user has messaged the bot at least once. Algunos canales permiten excepciones.Some channels allow exceptions. Por ejemplo, el canal de Teams permite que el bot envíe un mensaje proactivo (o 1-on-1) a individuos en una conversación de grupo ya establecida que incluya el bot.For instance, the Teams channel allows your bot to send a proactive (or 1-on-1) message to individuals in an already established group conversation that includes the bot.

Requisitos previosPrerequisites

Acerca del ejemplo proactivoAbout the proactive sample

En general, un bot como aplicación tiene algunas capas:In general, a bot as an application has a few layers:

  • Aplicación web que puede aceptar solicitudes HTTP y admite específicamente un punto de conexión de mensajería.The web application that can accept HTTP requests and specifically supports a messaging endpoint.
  • Adaptador que controla la conectividad con los canales.An adapter that handles connectivity with the channels.
  • Un controlador para el turno, normalmente encapsulado en una clase de bot que controla el razonamiento conversacional de la aplicación de bot.A handler for the turn, typically encapsulated in a bot class that handles the conversational reasoning for the bot app.

En respuesta a un mensaje entrante del usuario, la aplicación llama al método de actividad de proceso del adaptador, que crea un contexto de turno y turno, llama a su canalización de middleware y, a continuación, llama al controlador de turnos del bot.In response to an incoming message from the user, the app calls the adapter's process activity method, which creates a turn and turn context, calls its middleware pipeline, and then calls the bot's turn handler.

Para iniciar un mensaje proactivo, la aplicación del bot debe poder recibir entradas adicionales.To initiate a proactive message, the bot application needs to be able to receive additional input. La lógica de aplicación para iniciar un mensaje proactivo está fuera del ámbito del SDK.The application logic for initiating a proactive message is outside the scope of the SDK. En este ejemplo, se usa un punto de conexión de notificación, además de un punto de conexión de mensajes estándar, para desencadenar el turno proactivo.For this sample, a notify endpoint, in addition to a standard messages endpoint, is used to trigger the proactive turn.

En respuesta a una solicitud GET en este punto de conexión de notificación, la aplicación llama al método de conversación continue del adaptador, que se comporta de forma similar al método de actividad de proceso.In response to a GET request on this notify endpoint, the app calls the adapter's continue conversation method, which behaves similarly to the the process activity method. El método continue conversation:The continue conversation method:

  • Toma una referencia de conversación adecuada para el usuario y el método de devolución de llamada que se usará para el turno proactivo.Takes an appropriate conversation reference for the user and the callback method to use for the proactive turn.
  • Crea una actividad de evento y el contexto de turno para el turno proactivo.Creates an event activity and turn context for the proactive turn.
  • Llama a la canalización de middleware del adaptador.Calls the adapter's middleware pipeline.
  • Llama al método de devolución de llamada proporcionado.Calls the provided callback method.
  • El contexto de turno usa la referencia de conversación para enviar cualquier mensaje al usuario.The turn context uses the conversation reference to send any messages to the user.

El ejemplo tiene un bot, un punto de conexión de mensajes y un punto de conexión de notificación adicional que se usa para enviar mensajes proactivos al usuario, como se muestra en la ilustración siguiente.The sample has a bot, a messages endpoint, and an additional notify endpoint that is used to send proactive messages to the user, as shown in the following illustration.

Bot proactivo

Recuperación y almacenamiento de la referencia de la conversaciónRetrieve and store conversation reference

Cuando el emulador se conecta al bot, recibe dos actividades de actualización de conversación.When the Emulator connects to the bot, the bot receives two conversation update activities. En el controlador de actividad de actualización de conversación del bot, la referencia de la conversación se recupera y almacena en un diccionario, como se muestra a continuación.In the bot's conversation update activity handler, the conversation reference is retrieved and stored in a dictionary as shown below.

Bots\ProactiveBot.csBots\ProactiveBot.cs

private void AddConversationReference(Activity activity)
{
    var conversationReference = activity.GetConversationReference();
    _conversationReferences.AddOrUpdate(conversationReference.User.Id, conversationReference, (key, newValue) => conversationReference);
}

protected override Task OnConversationUpdateActivityAsync(ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
    AddConversationReference(turnContext.Activity as Activity);

    return base.OnConversationUpdateActivityAsync(turnContext, cancellationToken);
}

La referencia de conversación incluye una propiedad de conversación que describe la conversación en la que existe la actividad.The conversation reference includes a conversation property that describes the conversation in which the activity exists. La conversación incluye una propiedad de usuario que enumera los usuarios que participan en la conversación y una propiedad de dirección URL de servicio que indica dónde se pueden enviar las respuestas a la actividad actual.The conversation includes a user property that lists the users participating in the conversation, and a service URL property that indicates where replies to the current activity may be sent. Para enviar mensajes proactivos a los usuarios se necesita una referencia de conversación válida.A valid conversation reference is needed to send proactive messages to users. (Para el canal de Teams, la dirección URL del servicio se asigna a un servidor regionalizado).(For the Teams channel, the service URL maps to a regionalized server.)

Nota

En un escenario real, las referencias de conversación persistirían en una base de datos, en lugar de usar un objeto en memoria.In a real-world scenario you would persist conversation references in a database instead of using an object in memory.

Envío de mensajes proactivosSend proactive message

El segundo controlador, el controlador de notificación, es responsable de enviar el mensaje proactivo al usuario.The second controller, the notify controller, is responsible for sending the proactive message to the user. Usa los pasos siguientes para generar un mensaje proactivo.It uses the following steps to generate a proactive message.

  1. Recupera la referencia de la conversación a la que se va a enviar el mensaje proactivo.Retrieves the reference for the conversation to which to send the proactive message.
  2. Llama al método continue conversation del adaptador, proporcionando la referencia de conversación y el delegado de controlador de turnos que se va a usar.Calls the adapter's continue conversation method, providing the conversation reference and the turn handler delegate to use. (El método continue conversation genera un contexto de turno para la conversación a la que se hace referencia y, a continuación, llama al delegado de controlador de turnos especificado).(The continue conversation method generates a turn context for the referenced conversation and then calls the specified turn handler delegate.)
  3. En el delegado, usa el contexto de turno para enviar el mensaje proactivo.In the delegate, uses the turn context to send the proactive message. En este caso, el delegado se define en el controlador de notificación y envía el mensaje proactivo al usuario.Here, the delegate is defined on the notify controller, and it sends the proactive message to the user.

Nota

Aunque cada canal debe usar una dirección URL de servicio estable, la dirección URL puede cambiar con el tiempo.While each channel should use a stable service URL, the URL can change over time. Para obtener más información sobre la dirección URL del servicio, vea las secciones Estructura de actividad básica y Dirección URL de servicio del esquema de Bot Framework actividad.For more information about the service URL, see the Basic activity structure and Service URL sections of the Bot Framework Activity Schema.

Si cambia la dirección URL del servicio, las referencias de conversación anteriores ya no serán válidas y las llamadas para continuar la conversación generarán un error o una excepción.If the service URL changes, previous conversation references will no longer be valid and calls to continue conversation will generate an error or exception. En este caso, el bot deberá adquirir una nueva referencia de conversación para el usuario antes de poder volver a enviar mensajes proactivos.In this case, your bot will need to acquire a new conversation reference for the user before it can send proactive messages again.

Controllers\NotifyController .csControllers\NotifyController .cs

Cada vez que se solicita la página de notificación del bot, el controlador de notificación recupera las referencias de conversación del diccionario.Each time the bot's notify page is requested, the notify controller retrieves the conversation references from the dictionary. Luego, el controlador usa los métodos ContinueConversationAsync y BotCallback para enviar el mensaje proactivo.The controller then uses the ContinueConversationAsync and BotCallback methods to send the proactive message.

[Route("api/notify")]
[ApiController]
public class NotifyController : ControllerBase
{
    private readonly IBotFrameworkHttpAdapter _adapter;
    private readonly string _appId;
    private readonly ConcurrentDictionary<string, ConversationReference> _conversationReferences;

    public NotifyController(IBotFrameworkHttpAdapter adapter, IConfiguration configuration, ConcurrentDictionary<string, ConversationReference> conversationReferences)
    {
        _adapter = adapter;
        _conversationReferences = conversationReferences;
        _appId = configuration["MicrosoftAppId"] ?? string.Empty;
    }

    public async Task<IActionResult> Get()
    {
        foreach (var conversationReference in _conversationReferences.Values)
        {
            await ((BotAdapter)_adapter).ContinueConversationAsync(_appId, conversationReference, BotCallback, default(CancellationToken));
        }
        
        // Let the caller know proactive messages have been sent
        return new ContentResult()
        {
            Content = "<html><body><h1>Proactive messages have been sent.</h1></body></html>",
            ContentType = "text/html",
            StatusCode = (int)HttpStatusCode.OK,
        };
    }

    private async Task BotCallback(ITurnContext turnContext, CancellationToken cancellationToken)
    {
        await turnContext.SendActivityAsync("proactive hello");
    }
}

Para enviar un mensaje proactivo, el adaptador requiere un identificador de la aplicación para el bot.To send a proactive message, the adapter requires an app ID for the bot. En un entorno de producción, puede usar el identificador de la aplicación del bot.In a production environment, you can use the bot's app ID. Para probar el bot localmente con el emulador, puede usar la cadena vacía ("").To test the bot locally with the Emulator, you can use the empty string ("").

Prueba del botTest your bot

  1. Si aún no lo ha hecho, instale Bot Framework Emulator.If you have not done so already, install the Bot Framework Emulator.
  2. Ejecute el ejemplo localmente en la máquina.Run the sample locally on your machine.
  3. Inicie el emulador y conéctese al bot.Start the Emulator and connect to your bot.
  4. Cargue la página de api o notificación del bot.Load to your bot's api/notify page. Esto generará un mensaje proactivo en el emulador.This will generate a proactive message in the Emulator.

Información adicionalAdditional information

Además del ejemplo usado en este artículo, hay ejemplos adicionales disponibles en GitHub.Besides the sample used in this article, additional samples are available on GitHub.

Consideraciones de diseñoDesign considerations

Al implementar mensajes proactivos en un bot, no enviar varios mensajes proactivos en un breve lapso de tiempo.When implementing proactive messages in your bot, don't send several proactive messages within a short amount of time. Algunos canales imponen restricciones sobre la frecuencia con que un bot puede enviar mensajes al usuario, y deshabilitarán el bot si se infringen tales restricciones.Some channels enforce restrictions on how frequently a bot can send messages to the user, and will disable the bot if it violates those restrictions.

Un mensaje proactivo ad hoc es el tipo más simple de mensaje proactivo.An ad hoc proactive message is the simplest type of proactive message. El bot simplemente interpone el mensaje en la conversación cada vez que se desencadena, sin tener en cuenta si el usuario está implicado actualmente en otro tema de conversación con el bot, y no intentará cambiar la conversación de ninguna manera.The bot simply interjects the message into the conversation whenever it is triggered, without any regard for whether the user is currently engaged in a separate topic of conversation with the bot and will not attempt to change the conversation in any way.

Para controlar las notificaciones más fácilmente, considere otras formas de integrar la notificación en el flujo de conversación, como establecer una marca en el estado de la conversación o agregar la notificación a una cola.To handle notifications more smoothly, consider other ways to integrate the notification into the conversation flow, such as setting a flag in the conversation state or adding the notification to a queue.

Acerca del turno proactivoAbout the proactive turn

El método continue conversation usa la referencia de conversación y un controlador de devolución de llamada turn para:The continue conversation method uses the conversation reference and a turn callback handler to:

  1. Cree un turno en el que la aplicación del bot pueda enviar el mensaje proactivo.Create a turn in which the bot application can send the proactive message. El adaptador crea una event actividad para este turno, con su nombre establecido en "ContinueConversation".The adapter creates an event activity for this turn, with its name set to "ContinueConversation".
  2. Envíe el turno a través de la canalización de middleware del adaptador.Send the turn through the adapter's middleware pipeline.
  3. Llame al controlador de devolución de llamada de turno para realizar una lógica personalizada.Call the turn callback handler to perform custom logic.

En el ejemplo de mensajes proactivos, el controlador de devolución de llamada de turno se define en el controlador de notificación y envía el mensaje directamente a la conversación, sin enviar la actividad proactiva a través del controlador de turnos normal del bot.In the proactive messages sample, the turn callback handler is defined in the notify controller and sends the message directly to the conversation, without sending the proactive activity through the bot's normal turn handler. El código de ejemplo tampoco tiene acceso ni actualiza el estado del bot en el turno proactivo.The sample code also does not access or update the bot's state on the proactive turn.

Muchos bots tienen estado y usan el estado para administrar una conversación en varios turnos.Many bots are stateful and use state to manage a conversation over multiple turns. Cuando el método continue conversation crea un contexto de turno, el turno tendrá asociado el usuario y el estado de conversación correctos, y puede integrar los turnos proactivos en la lógica del bot.When the continue conversation method creates a turn context, the turn will have the correct user and conversation state associated with it, and you can integrate proactive turns into your bot's logic. Si necesita que la lógica del bot sea consciente del mensaje proactivo, tiene algunas opciones para hacerlo.If you need the bot logic to be aware of the proactive message, you have a few options for doing so. Puede hacer lo siguiente:You can:

  • Proporcione el controlador de turnos del bot como controlador de devolución de llamada de turno.Provide the bot's turn handler as the turn callback handler. A continuación, el bot recibirá la actividad de evento "ContinueConversation".The bot will then receive the "ContinueConversation" event activity.
  • Use primero el controlador de devolución de llamada de turno para agregar información al contexto de turno y, a continuación, llame al controlador de turnos del bot.Use the turn callback handler to add information to the turn context first, and then call the bot's turn handler.

En ambos casos, deberá diseñar la lógica del bot para controlar el evento proactivo.In both of these cases, you will need to design your bot logic to handle the proactive event.

Pasos siguientesNext steps