Impostare la scadenza di una conversazione

SI APPLICA A: SDK v4

Un bot a volte deve riavviare una conversazione dall'inizio. Ad esempio, se un utente non risponde dopo un determinato periodo di tempo. Questo articolo descrive due metodi per la scadenza di una conversazione:

  • Tenere traccia dell'ultima volta che un messaggio è stato ricevuto da un utente e cancellare lo stato se l'ora è maggiore di una lunghezza preconfigurata al momento della ricezione del messaggio successivo dall'utente. Per altre informazioni, vedere la sezione scadenza dell'interazione dell'utente.
  • Usare una funzionalità del livello di archiviazione, ad esempio Cosmos DB Time To Live (TTL), per cancellare automaticamente lo stato dopo un periodo di tempo preconfigurato. Per altre informazioni, vedere la sezione relativa alla scadenza dell'archiviazione.

Nota

Gli SDK JavaScript, C# e Python di Bot Framework continueranno a essere supportati, ma Java SDK verrà ritirato con il supporto finale a lungo termine che termina a novembre 2023.

I bot esistenti creati con Java SDK continueranno a funzionare.

Per la creazione di nuovi bot, è consigliabile usare Microsoft Copilot Studio e leggere le informazioni sulla scelta della soluzione copilota appropriata.

Per altre informazioni, vedere Il futuro della compilazione di bot.

Prerequisiti

Informazioni sull'esempio

Il codice di esempio in questo articolo inizia con la struttura di un bot a più turni ed estende la funzionalità del bot aggiungendo codice aggiuntivo (fornito nelle sezioni seguenti). Questo codice esteso illustra come cancellare lo stato della conversazione dopo un determinato periodo di tempo.

Scadenza interazione utente

Questo tipo di conversazione in scadenza viene ottenuto aggiungendo una proprietà dell'ora dell'ultimo accesso allo stato della conversazione del bot. Questo valore della proprietà viene quindi confrontato con l'ora corrente all'interno del gestore attività prima dell'elaborazione delle attività.

Nota

In questo esempio viene usato un timeout di 30 secondi per semplificare il test di questo modello.

appsettings.json

Aggiungere prima di tutto un'impostazione ExpireAfterSeconds a appsettings.json:

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

Bots\DialogBot.cs

ExpireAfterSecondsAggiungere quindi i campi , LastAccessedTimePropertye DialogStateProperty alla classe bot e inizializzarli nel costruttore del bot. Aggiungere anche un IConfiguration parametro al costruttore con cui recuperare il ExpireAfterSeconds valore.

Anziché creare la funzione di accesso alla proprietà dello stato del OnMessageActivityAsync dialogo inline nel metodo , è necessario crearla e registrarla in fase di inizializzazione. Il bot richiederà la funzione di accesso alla proprietà di stato non solo per eseguire il dialogo, ma anche per cancellare lo stato del dialogo.

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));
}

Aggiungere infine il codice al metodo del OnTurnAsync bot per cancellare lo stato del dialogo se la conversazione è troppo vecchia.

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);
}

Scadenza archiviazione

Cosmos DB offre una funzionalità TTL (Time To Live) che consente di eliminare automaticamente gli elementi da un contenitore dopo un determinato periodo di tempo. Questa operazione può essere configurata dall'interno del portale di Azure o durante la creazione di contenitori (usando gli SDK di Cosmos DB specifici del linguaggio).

Bot Framework SDK non espone un'impostazione di configurazione TTL. È tuttavia possibile eseguire l'override dell'inizializzazione del contenitore e l'SDK di Cosmos DB può essere usato per configurare la durata (TTL) prima dell'inizializzazione dell'archiviazione di Bot Framework.

Iniziare con una nuova copia dell'esempio di richiesta a più turni e aggiungere il Microsoft.Bot.Builder.Azure pacchetto NuGet al progetto.

appsettings.json

Aggiornare appsettings.json per includere le opzioni di archiviazione di 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>"
}

Si notino i due ContainerId, uno per UserState e uno per ConversationState. La durata (TTL) predefinita è impostata nel ConversationState contenitore, ma non in UserState.

CosmosDbStorageInitializerHostedService.cs

Creare quindi una CosmosDbStorageInitializerHostedService classe che creerà il contenitore con il time to live configurato.

// 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

Infine, aggiornare Startup.cs per usare l'inizializzatore di archiviazione e Cosmos DB per lo stato:

// 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 eliminerà automaticamente i record di stato della conversazione dopo 30 secondi di inattività.

Per altre informazioni, vedere Configurare la durata in Azure Cosmos DB

Per testare il bot

  1. Se non è già stato fatto, installare Bot Framework Emulator.
  2. Eseguire l'esempio in locale nel computer.
  3. Avviare l'emulatore, connettersi al bot e inviare un messaggio.
  4. Dopo una delle richieste, attendere 30 secondi prima di rispondere.