共用方式為


讓交談過期

適用於: SDK v4

Bot 有時需要從頭重新啟動交談。 例如,如果使用者在特定時段後沒有回應。 本文說明兩種過期交談的方法:

  • 追蹤上次從使用者收到訊息的時間,並在收到使用者下一則訊息時,如果時間大於預先設定的長度,則清除狀態。 如需詳細資訊,請參閱 用戶互動到期 一節。
  • 使用儲存層功能,例如 Cosmos DB 存留時間(TTL),在預先設定的時間長度之後自動清除狀態。 如需詳細資訊,請參閱 記憶體到期 一節。

注意

Bot Framework JavaScript、C# 和 Python SDK 將會繼續受到支援,不過,Java SDK 即將淘汰,最終長期支援將於 2023 年 11 月結束。

使用 Java SDK 建置的現有 Bot 將繼續運作。

針對新的 Bot 建置,請考慮使用 Microsoft Copilot Studio ,並閱讀 選擇正確的 Copilot 解決方案

如需詳細資訊,請參閱 Bot 建置的未來。

必要條件

關於此範例

本文中的範例程式代碼從多回合 Bot 的結構開始,並藉由新增其他程式代碼來擴充該 Bot 的功能(如下列各節提供)。 此延伸程式代碼示範如何在經過特定時間週期之後清除交談狀態。

用戶互動到期日

這種類型的過期交談是藉由將上次存取的時間屬性新增至 Bot 的交談狀態來完成。 接著,這個屬性值會與處理活動之前活動處理程式內的目前時間進行比較。

注意

此範例會使用 30 秒的逾時來輕鬆測試此模式。

appsettings.json

首先,將設定新增 ExpireAfterSeconds 至appsettings.json:

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

Bots\DialogBot.cs

接下來,將、 LastAccessedTimePropertyDialogStateProperty 欄位新增ExpireAfterSeconds至 Bot 類別,並在 Bot 的建構函式中將其初始化。 此外,將參數新增 IConfiguration 至要擷取 ExpireAfterSeconds 值的建構函式。

您不是在 方法中 OnMessageActivityAsync 內嵌建立對話框狀態屬性存取子,而是在初始化時建立和錄製它。 Bot 不僅需要狀態屬性存取子來執行對話,還需要清除對話狀態。

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

最後,將程式代碼新增至 Bot 的 OnTurnAsync 方法,以在對話太舊時清除對話狀態。

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

記憶體到期日

Cosmos DB 提供存留時間 (TTL) 功能,可讓您在特定時段後自動從容器中刪除專案。 這可以從 Azure 入口網站 或容器建立期間設定(使用語言特定的Cosmos DB SDK)。

Bot Framework SDK 不會公開 TTL 組態設定。 不過,可以覆寫容器初始化,而 Cosmos DB SDK 可用來在 Bot Framework 記憶體初始化之前設定 TTL。

從多回合提示範例的新複本開始,並將 NuGet 套件新增Microsoft.Bot.Builder.Azure至專案。

appsettings.json

更新appsettings.json以包含 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>"
}

請注意兩個 ContainerId,一個用於 UserState ,另一個用於 ConversationState。 預設的 TTL 是在容器上 ConversationState 設定,但未在 上設定 UserState

CosmosDbStorageInitializerHostedService.cs

接下來,建立類別 CosmosDbStorageInitializerHostedService ,以使用設定的存留時間建立容器。

// 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 以使用記憶體初始化運算式和 Cosmos DB 的狀態:

// 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 現在會在閒置 30 秒後自動刪除交談狀態記錄。

如需詳細資訊,請參閱 設定 Azure Cosmos DB 中的存留時間

測試 Bot

  1. 如果您尚未這麼做,請安裝 Bot Framework 模擬器
  2. 在本機電腦上執行範例。
  3. 啟動模擬器、連線至 Bot,並將訊息傳送給 Bot。
  4. 在其中一個提示之後,等候 30 秒後再回應。