Share via


Förfalla en konversation

GÄLLER FÖR: SDK v4

En robot måste ibland starta om en konversation från början. Om en användare till exempel inte svarar efter en viss tidsperiod. I den här artikeln beskrivs två metoder för att förfalla en konversation:

  • Spåra den senaste gången ett meddelande togs emot från en användare och avmarkera tillståndet om tiden är större än en förkonfigurerad längd när nästa meddelande tas emot från användaren. Mer information finns i avsnittet för förfallodatum för användarinteraktion .
  • Använd en lagringslagerfunktion, till exempel Cosmos DB Time To Live (TTL), för att automatiskt rensa tillståndet efter en förkonfigurerad tidsperiod. Mer information finns i avsnittet om lagringsförfallodatum.

Kommentar

Bot Framework JavaScript-, C#- och Python-SDK:erna fortsätter att stödjas, men Java SDK dras tillbaka med slutligt långsiktigt stöd som slutar i november 2023.

Befintliga robotar som skapats med Java SDK fortsätter att fungera.

Om du vill skapa en ny robot bör du överväga att använda Power Virtual Agents och läsa om hur du väljer rätt chattrobotlösning.

Mer information finns i Framtiden för robotbygge.

Förutsättningar

Om det här exemplet

Exempelkoden i den här artikeln börjar med strukturen för en robot med flera svängar och utökar robotens funktioner genom att lägga till ytterligare kod (som finns i följande avsnitt). Den här utökade koden visar hur du rensar konversationstillståndet efter att en viss tidsperiod har passerat.

Förfallodatum för användarinteraktion

Den här typen av konversation som upphör att gälla uppnås genom att lägga till en senast använda tidsegenskap i robotens konversationstillstånd. Det här egenskapsvärdet jämförs sedan med den aktuella tiden i aktivitetshanteraren innan aktiviteter bearbetas.

Kommentar

I det här exemplet används en tidsgräns på 30 sekunder för att enkelt testa det här mönstret.

appsettings.json

Lägg först till en ExpireAfterSeconds inställning i appsettings.json:

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

Robotar\DialogBot.cs

Lägg sedan till ExpireAfterSecondsfälten , LastAccessedTimePropertyoch DialogStateProperty i robotklassen och initiera dem i robotens konstruktor. Lägg också till en IConfiguration parameter i konstruktorn som värdet ska hämtas ExpireAfterSeconds med.

I stället för att skapa dialogtillståndets egenskapsåtkomst infogad i OnMessageActivityAsync metoden skapar och registrerar du den vid initieringstillfället. Roboten behöver åtkomst till tillståndsegenskapen, inte bara för att köra dialogrutan, utan även för att rensa dialogtillståndet.

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

Lägg slutligen till kod i robotens OnTurnAsync metod för att rensa dialogtillståndet om konversationen är för gammal.

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

Lagringsförfallodatum

Cosmos DB innehåller en TTL-funktion (Time To Live) som gör att du kan ta bort objekt automatiskt från en container efter en viss tidsperiod. Detta kan konfigureras inifrån Azure-portalen eller när containern skapas (med hjälp av språkspecifika Cosmos DB-SDK:er).

Bot Framework SDK exponerar inte en TTL-konfigurationsinställning. Initiering av containrar kan dock åsidosättas och Cosmos DB SDK kan användas för att konfigurera TTL innan Bot Framework-lagringen initieras.

Börja med en ny kopia av exemplet med fråga med flera svar och lägg till Microsoft.Bot.Builder.Azure NuGet-paketet i projektet.

appsettings.json

Uppdatera appsettings.json för att inkludera Lagringsalternativ för 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>"
}

Observera de två ContainerId:erna, ett för UserState och ett för ConversationState. Standard-TTL är inställt på containern ConversationState , men inte på UserState.

CosmosDbStorageInitializerHostedService.cs

Skapa sedan en CosmosDbStorageInitializerHostedService klass som skapar containern med den konfigurerade Time To Live.

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

Slutligen uppdaterar du Startup.cs för att använda lagringsinitieraren och Cosmos DB för tillstånd:

// 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 tar nu automatiskt bort konversationstillståndsposter efter 30 sekunders inaktivitet.

Mer information finns i Konfigurera tid att leva i Azure Cosmos DB

Testa roboten

  1. Om du inte redan har gjort det installerar du Bot Framework-emulatorn.
  2. Kör exemplet lokalt på datorn.
  3. Starta emulatorn, anslut till roboten och skicka ett meddelande till den.
  4. Efter en av anvisningarna väntar du 30 sekunder innan du svarar.