Delen via


Een gesprek laten verlopen

VAN TOEPASSING OP: SDK v4

Een bot moet soms vanaf het begin een gesprek opnieuw starten. Als een gebruiker bijvoorbeeld na een bepaalde periode niet reageert. In dit artikel worden twee methoden beschreven voor het verlopen van een gesprek:

  • Houd de laatste keer bij dat een bericht van een gebruiker is ontvangen en controleer of de tijd groter is dan een vooraf geconfigureerde lengte bij het ontvangen van het volgende bericht van de gebruiker. Zie de sectie verlooptijd van gebruikersinteractie voor meer informatie.
  • Gebruik een functie voor opslaglagen, zoals Cosmos DB Time To Live (TTL), om de status automatisch te wissen na een vooraf geconfigureerde tijdsduur. Zie de sectie verlooptijd van de opslag voor meer informatie.

Notitie

De Sdk's voor Bot Framework JavaScript, C# en Python blijven ondersteund, maar de Java SDK wordt buiten gebruik gesteld met definitieve langetermijnondersteuning die eindigt op november 2023.

Bestaande bots die zijn gebouwd met de Java SDK blijven functioneren.

Voor het bouwen van nieuwe bots kunt u Microsoft Copilot Studio gebruiken en lezen over het kiezen van de juiste copilot-oplossing.

Zie De toekomst van botbouw voor meer informatie.

Vereisten

Over dit voorbeeld

De voorbeeldcode in dit artikel begint met de structuur van een bot met meerdere bochten en breidt de functionaliteit van die bot uit door extra code toe te voegen (in de volgende secties). Deze uitgebreide code laat zien hoe u de gespreksstatus wist nadat een bepaalde periode is verstreken.

Verlooptijd van gebruikersinteractie

Dit type verlopende gesprek wordt bereikt door een laatst geopende tijdeigenschap toe te voegen aan de gespreksstatus van de bot. Deze eigenschapswaarde wordt vervolgens vergeleken met de huidige tijd binnen de activiteitshandler voordat de activiteiten worden verwerkt.

Notitie

In dit voorbeeld wordt een time-out van 30 seconden gebruikt om dit patroon gemakkelijker te testen.

appsettings.json

Voeg eerst een ExpireAfterSeconds instelling toe aan appsettings.json:

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

Bots\DialogBot.cs

Voeg ExpireAfterSecondsvervolgens velden LastAccessedTimePropertytoe DialogStateProperty aan de botklasse en initialiseer deze in de constructor van de bot. Voeg ook een IConfiguration parameter toe aan de constructor waarmee de ExpireAfterSeconds waarde moet worden opgehaald.

In plaats van de accessor voor dialoogvensterstatuseigenschappen inline te maken in de OnMessageActivityAsync methode, maakt en registreert u deze tijdens de initialisatie. De bot heeft niet alleen de toegangsrechten voor de statuseigenschap nodig om het dialoogvenster uit te voeren, maar ook om de status van het dialoogvenster te wissen.

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

Voeg ten slotte code toe aan de methode van OnTurnAsync de bot om de dialoogvensterstatus te wissen als het gesprek te oud is.

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

Verlooptijd van opslag

Cosmos DB biedt een TTL-functie (Time To Live) waarmee u items na een bepaalde periode automatisch uit een container kunt verwijderen. Dit kan worden geconfigureerd vanuit Azure Portal of tijdens het maken van containers (met behulp van de taalspecifieke Cosmos DB SDK's).

De Bot Framework SDK maakt geen TTL-configuratie-instelling beschikbaar. Container initialisatie kan echter worden overschreven en de Cosmos DB SDK kan worden gebruikt om TTL te configureren vóór de initialisatie van Bot Framework-opslag.

Begin met een nieuwe kopie van het voorbeeld met meerdere prompts en voeg het Microsoft.Bot.Builder.Azure NuGet-pakket toe aan het project.

appsettings.json

Werk appsettings.json bij om Cosmos DB-opslagopties op te nemen:

{
  "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>"
}

Let op de twee ContainerIds, één voor UserState en één voor ConversationState. De standaard-TTL is ingesteld op de ConversationState container, maar niet op UserState.

CosmosDbStorageInitializerHostedService.cs

Maak vervolgens een CosmosDbStorageInitializerHostedService klasse waarmee de container wordt gemaakt met de geconfigureerde 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

Startup.cs Werk ten slotte bij om de initialisatiefunctie voor opslag en Cosmos DB te gebruiken voor de status:

// 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 verwijdert nu automatisch gespreksstatusrecords na 30 seconden inactiviteit.

Zie Time to Live configureren in Azure Cosmos DB voor meer informatie

De bot testen

  1. Als u dit nog niet hebt gedaan, installeert u de Bot Framework Emulator.
  2. Voer het voorbeeld lokaal uit op uw computer.
  3. Start de emulator, maak verbinding met uw bot en verzend er een bericht naartoe.
  4. Wacht na een van de prompts 30 seconden voordat u reageert.