使用分支和迴圈建立進階交談流程

適用於: SDK v4

您可以使用對話框連結庫來建立複雜的交談流程。 本文涵蓋如何管理分支和迴圈的複雜交談,以及如何在對話的不同部分之間傳遞自變數。

注意

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

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

針對新的 Bot 建置,請考慮使用 Power Virtual Agents ,並閱讀 選擇正確的聊天機器人解決方案

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

必要條件

關於此範例

此範例代表可註冊使用者的 Bot,以從清單中檢閱最多兩家公司。 Bot 會使用三個元件對話來管理交談流程。 每個元件對話都包含瀑布式對話,以及收集使用者輸入所需的任何提示。 下列各節會更詳細地說明這些對話框。 它會使用交談狀態來管理其對話,並使用用戶狀態來儲存使用者的相關信息,以及他們想要檢閱的公司。

Bot 衍生自活動處理程式。 和許多範例 Bot 一樣,它歡迎使用者、使用對話來處理來自使用者的訊息,並在回合結束前儲存使用者和交談狀態。

若要使用對話框,請安裝 Microsoft.Bot.Builder.Dialogs NuGet 套件。

C# 範例的類別圖表。

定義使用者配置檔

使用者配置檔將包含對話框、使用者名稱、年齡和選取檢閱的公司所收集的資訊。

UserProfile.cs

/// <summary>Contains information about a user.</summary>
public class UserProfile
{
    public string Name { get; set; }

    public int Age { get; set; }

    // The list of companies the user wants to review.
    public List<string> CompaniesToReview { get; set; } = new List<string>();

建立對話框

此 Bot 包含三個對話盒:

  • 主要對話框會啟動整體程序,然後摘要收集的資訊。
  • 最上層對話框會根據用戶的年齡收集用戶資訊,並包含分支邏輯。
  • [檢閱選取] 對話框可讓使用者反覆選取要檢閱的公司。 它會使用循環邏輯來執行此動作。

主要對話框

主要對話框有兩個步驟:

  1. 啟動最上層對話框。
  2. 擷取並摘要最上層對話方塊收集的使用者配置檔、將該資訊儲存至用戶狀態,然後發出主對話結尾的訊號。

Dialogs\MainDialog.cs

private async Task<DialogTurnResult> InitialStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    return await stepContext.BeginDialogAsync(nameof(TopLevelDialog), null, cancellationToken);
}

private async Task<DialogTurnResult> FinalStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    var userInfo = (UserProfile)stepContext.Result;

    string status = "You are signed up to review "
        + (userInfo.CompaniesToReview.Count is 0 ? "no companies" : string.Join(" and ", userInfo.CompaniesToReview))
        + ".";

    await stepContext.Context.SendActivityAsync(status);

    var accessor = _userState.CreateProperty<UserProfile>(nameof(UserProfile));
    await accessor.SetAsync(stepContext.Context, userInfo, cancellationToken);

    return await stepContext.EndDialogAsync(null, cancellationToken);
}

最上層對話框

最上層對話框有四個步驟:

  1. 要求用戶的名稱。
  2. 要求用戶的年齡。
  3. 根據使用者的年齡,啟動 [檢閱選取] 對話框或進入下一個步驟。
  4. 最後,感謝用戶參與並傳回收集到的資訊。

第一個步驟會在對話狀態中建立空的使用者配置檔。 對話框會以空的配置檔開頭,並在配置檔進行時將資訊新增至配置檔。 結束時,最後一個步驟會傳回收集到的資訊。

在第三個 (開始選取) 步驟中,對話流程會根據使用者的年齡進行分支。

Dialogs\TopLevelDialog.cs

            stepContext.Values[UserInfo] = new UserProfile();

            var promptOptions = new PromptOptions { Prompt = MessageFactory.Text("Please enter your name.") };

            // Ask the user to enter their name.
            return await stepContext.PromptAsync(nameof(TextPrompt), promptOptions, cancellationToken);
        }

        private async Task<DialogTurnResult> AgeStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            // Set the user's name to what they entered in response to the name prompt.
            var userProfile = (UserProfile)stepContext.Values[UserInfo];
            userProfile.Name = (string)stepContext.Result;

            var promptOptions = new PromptOptions { Prompt = MessageFactory.Text("Please enter your age.") };

            // Ask the user to enter their age.
            return await stepContext.PromptAsync(nameof(NumberPrompt<int>), promptOptions, cancellationToken);
        }

        private async Task<DialogTurnResult> StartSelectionStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            // Set the user's age to what they entered in response to the age prompt.
            var userProfile = (UserProfile)stepContext.Values[UserInfo];
            userProfile.Age = (int)stepContext.Result;

            if (userProfile.Age < 25)
            {
                // If they are too young, skip the review selection dialog, and pass an empty list to the next step.
                await stepContext.Context.SendActivityAsync(
                    MessageFactory.Text("You must be 25 or older to participate."),
                    cancellationToken);
                return await stepContext.NextAsync(new List<string>(), cancellationToken);
            }
            else
            {
                // Otherwise, start the review selection dialog.
                return await stepContext.BeginDialogAsync(nameof(ReviewSelectionDialog), null, cancellationToken);
            }
        }

        private async Task<DialogTurnResult> AcknowledgementStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            // Set the user's company selection to what they entered in the review-selection dialog.
            var userProfile = (UserProfile)stepContext.Values[UserInfo];
            userProfile.CompaniesToReview = stepContext.Result as List<string> ?? new List<string>();

            // Thank them for participating.
            await stepContext.Context.SendActivityAsync(
                MessageFactory.Text($"Thanks for participating, {((UserProfile)stepContext.Values[UserInfo]).Name}."),
                cancellationToken);

            // Exit the dialog, returning the collected user information.
            return await stepContext.EndDialogAsync(stepContext.Values[UserInfo], cancellationToken);
        }
    }
}

檢閱選取對話框

[檢閱選取] 對話框有兩個步驟:

  1. 要求用戶選擇要檢閱或 done 完成的公司。
    • 如果對話是以任何初始信息啟動,則資訊可透過 瀑布步驟內容的options 屬性取得。 [檢閱選取] 對話框可以自行重新啟動,並使用此對話框讓用戶選擇一個以上的公司進行檢閱。
    • 如果使用者已選取要檢閱的公司,則會從可用的選項中移除該公司。
    • done已新增選項,讓使用者提早結束迴圈。
  2. 視需要重複此對話框或結束。
    • 如果使用者選擇要檢閱的公司,請將它新增至其清單。
    • 如果使用者已選擇兩家公司或他們選擇結束,請結束對話框並傳回收集的清單。
    • 否則,請重新啟動對話方塊,使用其清單的內容初始化對話方塊。

Dialogs\ReviewSelectionDialog.cs

private async Task<DialogTurnResult> SelectionStepAsync(
    WaterfallStepContext stepContext,
    CancellationToken cancellationToken)
{
    // Continue using the same selection list, if any, from the previous iteration of this dialog.
    var list = stepContext.Options as List<string> ?? new List<string>();
    stepContext.Values[CompaniesSelected] = list;

    // Create a prompt message.
    string message;
    if (list.Count is 0)
    {
        message = $"Please choose a company to review, or `{DoneOption}` to finish.";
    }
    else
    {
        message = $"You have selected **{list[0]}**. You can review an additional company, " +
            $"or choose `{DoneOption}` to finish.";
    }

    // Create the list of options to choose from.
    var options = _companyOptions.ToList();
    options.Add(DoneOption);
    if (list.Count > 0)
    {
        options.Remove(list[0]);
    }

    var promptOptions = new PromptOptions
    {
        Prompt = MessageFactory.Text(message),
        RetryPrompt = MessageFactory.Text("Please choose an option from the list."),
        Choices = ChoiceFactory.ToChoices(options),
    };

    // Prompt the user for a choice.
    return await stepContext.PromptAsync(nameof(ChoicePrompt), promptOptions, cancellationToken);
}

private async Task<DialogTurnResult> LoopStepAsync(
    WaterfallStepContext stepContext,
    CancellationToken cancellationToken)
{
    // Retrieve their selection list, the choice they made, and whether they chose to finish.
    var list = stepContext.Values[CompaniesSelected] as List<string>;
    var choice = (FoundChoice)stepContext.Result;
    var done = choice.Value == DoneOption;

    if (!done)
    {
        // If they chose a company, add it to the list.
        list.Add(choice.Value);
    }

    if (done || list.Count >= 2)
    {
        // If they're done, exit and return their list.
        return await stepContext.EndDialogAsync(list, cancellationToken);
    }
    else
    {
        // Otherwise, repeat this dialog, passing in the list from this iteration.
        return await stepContext.ReplaceDialogAsync(InitialDialogId, list, cancellationToken);
    }
}

執行對話框

dialog Bot 類別會擴充活動處理程式,並包含執行對話的邏輯。 對話框 和歡迎 Bot 類別會擴充對話 Bot ,以在使用者加入交談時也歡迎使用者。

Bot 的回合處理程式會重複三個對話所定義的交談流程。 收到來自使用者的訊息時:

  1. 它會執行主要對話框。
    • 如果對話框堆疊是空的,這會啟動主要對話。
    • 否則,對話仍在中間處理中,這會繼續使用中的對話方塊。
  2. 它會儲存狀態,以便保存使用者、交談和對話狀態的任何更新。

Bots\DialogBot.cs

public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
    await base.OnTurnAsync(turnContext, cancellationToken);

    // Save any state changes that might have occurred during the turn.
    await ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
    await UserState.SaveChangesAsync(turnContext, false, cancellationToken);
}

protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
    Logger.LogInformation("Running dialog with Message Activity.");

    // Run the Dialog with the new message Activity.
    await Dialog.RunAsync(turnContext, ConversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
}

註冊 Bot 的服務

視需要建立和註冊服務:

  • Bot 的基本服務:配接器和 Bot 實作。
  • 用於管理狀態的服務:記憶體、用戶狀態和交談狀態。
  • Bot 將使用的根對話。

Startup.cs

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpClient().AddControllers().AddNewtonsoftJson(options =>
    {
        options.SerializerSettings.MaxDepth = HttpHelper.BotMessageSerializerSettings.MaxDepth;
    });

    // Create the Bot Framework Authentication to be used with the Bot Adapter.
    services.AddSingleton<BotFrameworkAuthentication, ConfigurationBotFrameworkAuthentication>();

    // Create the Bot Adapter with error handling enabled.
    services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>();

    // Create the storage we'll be using for User and Conversation state. (Memory is great for testing purposes.)
    services.AddSingleton<IStorage, MemoryStorage>();

    // Create the User state. (Used in this bot's Dialog implementation.)
    services.AddSingleton<UserState>();

注意

記憶體記憶體記憶體僅供測試之用,不適用於生產環境。 請務必針對生產 Bot 使用持續性類型的記憶體。

測試聊天機器人

  1. 如果您尚未這麼做,請安裝 Bot Framework 模擬器

  2. 在本機電腦上執行範例。

  3. 啟動模擬器、連線至 Bot,並傳送訊息,如下所示。

    與複雜對話 Bot 交談的範例文字記錄。

其他資源

如需如何實作對話的簡介,請參閱 實作循序對話流程,其使用單一瀑布式對話和一些提示來詢問使用者一系列問題。

對話框連結庫包含提示的基本驗證。 您也可以新增自訂驗證。 如需詳細資訊,請參閱 使用對話框提示收集用戶輸入。

若要簡化對話程式代碼並重複使用多個 Bot,您可以將對話集的部分定義為個別類別。 如需詳細資訊,請參閱 重複使用對話方塊

下一步