Compartir a través de


Expiración de una conversación

SE APLICA A: SDK v4

A veces, un bot necesita reiniciar una conversación desde el principio. Por ejemplo, si un usuario no responde después de un período de tiempo determinado. En este artículo se describen dos métodos para expirar una conversación:

  • Realice un seguimiento de la última vez que se recibió un mensaje de un usuario y borre el estado si la hora es mayor que una longitud preconfigurada al recibir el siguiente mensaje del usuario. Para más información, consulte la sección de expiración de la interacción del usuario.
  • Use una característica de capa de almacenamiento, como el período de vida (TTL) de Cosmos DB, para borrar automáticamente el estado después de un período de tiempo preconfigurado. Para más información, consulte la sección de expiración de almacenamiento.

Nota:

Para crear agentes con su elección de servicios de inteligencia artificial, orquestación y conocimientos, considere la posibilidad de usar el SDK de agentes de Microsoft 365. El SDK de agentes admite C#, JavaScript o Python. Puede obtener más información sobre el SDK de agentes en aka.ms/agents. Si busca una plataforma de agente basada en SaaS, considere Microsoft Copilot Studio. Si tiene un bot existente creado con Bot Framework SDK, puede actualizar el bot al SDK de agentes. Puede revisar los cambios principales y las actualizaciones en la guía de migración del Bot Framework SDK al SDK de Agentes. Las incidencias de soporte técnico del SDK de Bot Framework ya no se atenderán a partir del 31 de diciembre de 2025.

Requisitos previos

Acerca de este ejemplo

El código de ejemplo de este artículo comienza con la estructura de un bot de varios turnos, y amplía la funcionalidad de ese bot añadiendo código adicional (proporcionado en las siguientes secciones). Este código extendido muestra cómo borrar el estado de la conversación después de que haya transcurrido un período de tiempo determinado.

Expiración de la interacción del usuario

Este tipo de conversación de expiración se logra agregando una propiedad de hora de último acceso al estado de conversación del bot. A continuación, este valor de propiedad se compara con la hora actual dentro del controlador de actividad antes de procesar las actividades.

Nota:

En este ejemplo se usa un tiempo de espera de 30 segundos para facilitar la prueba de este patrón.

appsettings.json

En primer lugar, agregue una configuración ExpireAfterSeconds a appsettings.json:

{
  "MicrosoftAppId": "",
  "MicrosoftAppPassword": "",
  "ExpireAfterSeconds": 30
}

Bots\DialogBot.cs

A continuación, agregue los campos ExpireAfterSeconds, LastAccessedTimeProperty y DialogStateProperty a la clase bot e inicialícelos en el constructor del bot. Agregue también un parámetro IConfiguration al constructor con el que se va a recuperar el valor ExpireAfterSeconds.

En lugar de crear el descriptor de acceso de la propiedad de estado del cuadro de diálogo insertado en el método OnMessageActivityAsync, va a crearlo y registrarlo en el momento de la inicialización. El bot necesitará el descriptor de acceso de propiedad de estado no solo para ejecutar el cuadro de diálogo, sino también para borrar el estado del diálogo.

protected readonly int ExpireAfterSeconds;
protected readonly IStatePropertyAccessor<DateTime> LastAccessedTimeProperty;
protected readonly IStatePropertyAccessor<DialogState> DialogStateProperty;

// Existing fields omitted...

public DialogBot(IConfiguration configuration, ConversationState conversationState, UserState userState, T dialog, ILogger<DialogBot<T>> logger)
{
    ConversationState = conversationState;
    UserState = userState;
    Dialog = dialog;
    Logger = logger;

    ExpireAfterSeconds = configuration.GetValue<int>("ExpireAfterSeconds");
    DialogStateProperty = ConversationState.CreateProperty<DialogState>(nameof(DialogState));
    LastAccessedTimeProperty = ConversationState.CreateProperty<DateTime>(nameof(LastAccessedTimeProperty));
}

Por último, agregue código al método OnTurnAsync del bot para borrar el estado del diálogo si la conversación es demasiado antigua.

public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default)
{
    // Retrieve the property value, and compare it to the current time.
    var lastAccess = await LastAccessedTimeProperty.GetAsync(turnContext, () => DateTime.UtcNow, cancellationToken).ConfigureAwait(false);
    if ((DateTime.UtcNow - lastAccess) >= TimeSpan.FromSeconds(ExpireAfterSeconds))
    {
        // Notify the user that the conversation is being restarted.
        await turnContext.SendActivityAsync("Welcome back!  Let's start over from the beginning.").ConfigureAwait(false);

        // Clear state.
        await ConversationState.ClearStateAsync(turnContext, cancellationToken).ConfigureAwait(false);
    }

    await base.OnTurnAsync(turnContext, cancellationToken).ConfigureAwait(false);

    // Set LastAccessedTime to the current time.
    await LastAccessedTimeProperty.SetAsync(turnContext, DateTime.UtcNow, cancellationToken).ConfigureAwait(false);

    // Save any state changes that might have occurred during the turn.
    await ConversationState.SaveChangesAsync(turnContext, false, cancellationToken).ConfigureAwait(false);
    await UserState.SaveChangesAsync(turnContext, false, cancellationToken).ConfigureAwait(false);
}

Expiración de almacenamiento

Cosmos DB proporciona una función de tiempo de vida (TTL) que le permite eliminar elementos automáticamente de un contenedor después de un determinado período de tiempo. Esto se puede configurar desde Azure Portal o durante la creación del contenedor (mediante los SDK de Cosmos DB específicos del lenguaje).

El SDK de Bot Framework no expone una configuración de TTL. Sin embargo, la inicialización del contenedor se puede invalidar y el SDK de Cosmos DB se puede usar para configurar TTL antes de la inicialización del almacenamiento de Bot Framework.

Comience con una copia nueva del ejemplo de aviso de varios turnos y agregue el paquete NuGet Microsoft.Bot.Builder.Azure al proyecto.

appsettings.json

Actualice appsettings.json para incluir las opciones de almacenamiento de Cosmos DB:

{
  "MicrosoftAppId": "",
  "MicrosoftAppPassword": "",

  "CosmosDbTimeToLive": 30,
  "CosmosDbEndpoint": "<endpoint-for-your-cosmosdb-instance>",
  "CosmosDbAuthKey": "<your-cosmosdb-auth-key>",
  "CosmosDbDatabaseId": "<your-database-id>",
  "CosmosDbUserStateContainerId": "<no-ttl-container-id>",
  "CosmosDbConversationStateContainerId": "<ttl-container-id>"
}

Observe los dos ContainerIds, uno para UserState y otro para ConversationState. El TTL predeterminado se establece en el contenedor ConversationState, pero no en UserState.

CosmosDbStorageInitializerHostedService.cs

A continuación, cree una clase CosmosDbStorageInitializerHostedService, que creará el contenedor con el período de vida configurado.

// Add required using statements...

public class CosmosDbStorageInitializerHostedService : IHostedService
{
    readonly CosmosDbPartitionedStorageOptions _storageOptions;
    readonly int _cosmosDbTimeToLive;

    public CosmosDbStorageInitializerHostedService(IConfiguration config)
    {
        _storageOptions = new CosmosDbPartitionedStorageOptions()
        {
            CosmosDbEndpoint = config["CosmosDbEndpoint"],
            AuthKey = config["CosmosDbAuthKey"],
            DatabaseId = config["CosmosDbDatabaseId"],
            ContainerId = config["CosmosDbConversationStateContainerId"]
        };

        _cosmosDbTimeToLive = config.GetValue<int>("CosmosDbTimeToLive");
    }

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        using (var client = new CosmosClient(
            _storageOptions.CosmosDbEndpoint,
            _storageOptions.AuthKey,
            _storageOptions.CosmosClientOptions ?? new CosmosClientOptions()))
        {
            // Create the contaier with the provided TTL
            var containerResponse = await client
                .GetDatabase(_storageOptions.DatabaseId)
                .DefineContainer(_storageOptions.ContainerId, "/id")
                .WithDefaultTimeToLive(_cosmosDbTimeToLive)
                .WithIndexingPolicy().WithAutomaticIndexing(false).Attach()
                .CreateIfNotExistsAsync(_storageOptions.ContainerThroughput)
                .ConfigureAwait(false);
        }
    }

    public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}

Startup.cs

Por último, actualice Startup.cs para usar el inicializador de almacenamiento y Cosmos DB para el estado:

// Existing code omitted...

// commented out MemoryStorage, since we are using CosmosDbPartitionedStorage instead
// services.AddSingleton<IStorage, MemoryStorage>();

// Add the Initializer as a HostedService (so it's called during the app service startup)
services.AddHostedService<CosmosDbStorageInitializerHostedService>();

// Create the storage options for User state
var userStorageOptions = new CosmosDbPartitionedStorageOptions()
{
    CosmosDbEndpoint = Configuration["CosmosDbEndpoint"],
    AuthKey = Configuration["CosmosDbAuthKey"],
    DatabaseId = Configuration["CosmosDbDatabaseId"],
    ContainerId = Configuration["CosmosDbUserStateContainerId"]
};

// Create the User state. (Used in this bot's Dialog implementation.)
services.AddSingleton(new UserState(new CosmosDbPartitionedStorage(userStorageOptions)));

// Create the storage options for Conversation state
var conversationStorageOptions = new CosmosDbPartitionedStorageOptions()
{
    CosmosDbEndpoint = Configuration["CosmosDbEndpoint"],
    AuthKey = Configuration["CosmosDbAuthKey"],
    DatabaseId = Configuration["CosmosDbDatabaseId"],
    ContainerId = Configuration["CosmosDbConversationStateContainerId"]
};

// Create the Conversation state. (Used by the Dialog system itself.)
services.AddSingleton(new ConversationState(new CosmosDbPartitionedStorage(conversationStorageOptions)));

// Existing code omitted...

Cosmos DB eliminará automáticamente los registros de estado de conversación después de 30 segundos de inactividad.

Para obtener más información, consulte Configurar el tiempo de vida en Azure Cosmos DB

Prueba del bot

  1. Si aún no lo ha hecho, instale Bot Framework Emulator.
  2. Ejecute el ejemplo localmente en la máquina.
  3. Inicie Emulator, conéctese al bot y envíele un mensaje.
  4. Después de una de las solicitudes, espere 30 segundos antes de responder.