Festlegen des Ablaufs einer Konversation

GILT FÜR: SDK v4

Manchmal muss ein Bot eine Unterhaltung von vorne starten. Wenn ein Benutzer beispielsweise nach einem bestimmten Zeitraum nicht reagiert. In diesem Artikel werden zwei Methoden für das Ablaufen einer Unterhaltung beschrieben:

  • Verfolgen Sie das letzte Mal, wenn eine Nachricht von einem Benutzer empfangen wurde, und löschen Sie den Status, wenn die Zeit größer als eine vorkonfigurierte Dauer bis zur nächsten Nachricht eines Benutzers ist. Weitere Informationen finden Sie im Abschnitt Benutzerinteraktionsablauf.
  • Verwenden Sie ein Speicherebenen-Feature wie das Time-to-Live-Feature (TTL) von Cosmos DB, um den Zustand nach einer vorkonfigurierten Zeitspanne automatisch zu löschen. Weitere Informationen finden Sie im Abschnitt Speicherablauf.

Hinweis

Die JavaScript-, C#- und Python-SDKs für Bot Framework werden weiterhin unterstützt, das Java-SDK wird jedoch eingestellt und der langfristige Support endet im November 2023.

Bestehende Bots, die mit dem Java SDK erstellt wurden, werden weiterhin funktionieren.

Wenn Sie einen neuen Bot erstellen möchten, sollten Sie den Einsatz von Power Virtual Agents in Betracht ziehen und sich über die Auswahl der richtigen Chatbot-Lösung informieren.

Weitere Informationen finden Sie unter Die Zukunft des Bot-Design.

Voraussetzungen

Informationen zu diesem Beispiel

Der Beispielcode in diesem Artikel beginnt mit der Struktur eines Bots mit mehreren Durchläufen und erweitert die Funktionalität des Bots anschließend durch Hinzufügen von zusätzlichem Code (in den folgenden Abschnitten enthalten). Dieser erweiterte Code veranschaulicht, wie der Unterhaltungszustand nach Ablauf eines bestimmten Zeitraums gelöscht wird.

Ablauf der Benutzerinteraktion

Diese Art der ablaufenden Unterhaltung wird durch Hinzufügen einer Eigenschaft für den letzten Zugriff zum Unterhaltungszustand des Bots erreicht. Dieser Eigenschaftswert wird dann vor der Verarbeitung von Aktivitäten mit der aktuellen Zeit innerhalb des Aktivitätshandlers verglichen.

Hinweis

In diesem Beispiel wird eine Zeitüberschreitung von 30 Sekunden verwendet, um dieses Muster einfacher zu testen.

appsettings.json

Fügen Sie zunächst eine ExpireAfterSeconds-Einstellung zu „appsettings.json“ hinzu:

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

Bots\DialogBot.cs

Fügen Sie dann ExpireAfterSeconds-, LastAccessedTimeProperty- und DialogStateProperty-Felder zur Botklasse hinzu und initialisieren Sie sie im Konstruktor des Bots. Fügen Sie dem Konstruktor auch einen IConfiguration-Parameter hinzu, mit dem der ExpireAfterSeconds-Wert abgerufen werden soll.

Anstatt den Eigenschafts-Accessor für den Dialogstatus inline in der OnMessageActivityAsync-Methode zu erstellen, wird er zur Initialisierungszeit erstellt und aufgezeichnet. Der Bot benötigt den Statuseigenschaftsaccessor nicht nur zum Ausführen des Dialogfelds, sondern auch zum Löschen des Dialogzustands.

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

Fügen Sie schließlich Code zur OnTurnAsync-Methode des Bots hinzu, um den Dialogzustand zu löschen, wenn die Unterhaltung zu alt ist.

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

Speicherablauf

Cosmos DB bietet ein Gültigkeitsdauer-Feature (Time to Live, TTL), das es Ihnen ermöglicht, Objekte nach einer bestimmten Zeitspanne automatisch aus einem Container zu löschen. Dies kann innerhalb des Azure-Portal oder während der Containererstellung (mit den sprachspezifischen Cosmos DB SDKs) konfiguriert werden.

Das Bot Framework SDK macht keine TTL-Konfigurationseinstellung verfügbar. Containerinitialisierung kann jedoch überschrieben werden und das Cosmos DB SDK kann verwendet werden, um TTL vor der Bot-Framework-Speicherinitialisierung zu konfigurieren.

Beginnen Sie mit einer neuen Kopie des Beispiels Multi-Turn-Prompt und fügen Sie das Microsoft.Bot.Builder.Azure-NuGet-Paket dem Projekt hinzu.

appsettings.json

Aktualisieren Sie „appsettings.json“, um Cosmos-DB-Speicheroptionen einzuschließen:

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

Beachten Sie die beiden ContainerIds, eine für UserState und eine für ConversationState. Die Standard-TTL wird für den ConversationState-Container festgelegt, aber nicht für UserState.

CosmosDbStorageInitializerHostedService.cs

Erstellen Sie als dann eine CosmosDbStorageInitializerHostedService-Klasse, die den Container mit dem konfigurierten Gültigkeitsdauer-Objekt erstellt.

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

Aktualisieren Sie schließlich Startup.cs, um den Speicherinitialisierer und Cosmos DB für den Zustand zu verwenden:

// 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 löscht jetzt automatisch Unterhaltungszustands-Datensätze nach 30 Sekunden Inaktivität.

Weitere Informationen finden Sie unter Konfigurieren von Gültigkeitsdauer in Azure Cosmos DB.

So testen Sie den Bot

  1. Installieren Sie Bot Framework Emulator, sofern noch nicht geschehen.
  2. Führen Sie das Beispiel lokal auf Ihrem Computer aus.
  3. Starten Sie den Emulator, stellen Sie eine Verbindung zu Ihrem Bot her und senden Sie eine Nachricht an ihn.
  4. Warten Sie nach einer der Eingabeaufforderungen 30 Sekunden, bevor Sie antworten.