共用方式為


建立您自己的提示以收集使用者輸入

適用於: SDK v4

Bot 與使用者之間的交談通常涉及詢問(提示)使用者取得資訊、剖析使用者的回應,然後針對該資訊採取行動。 您的 Bot 應該追蹤交談的內容,以便管理其行為,並記住先前問題的解答。 Bot 的狀態 是其追蹤以適當回應傳入訊息的資訊。

提示

對話框連結庫提供內建提示,提供使用者可以使用的更多功能。 您可以在實作循序對話流程一文中找到這些提示的範例。

注意

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

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

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

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

必要條件

關於範例程序代碼

範例 Bot 會詢問使用者一系列問題、驗證其部分答案,以及儲存其輸入。 下圖顯示 Bot、使用者配置檔和交談流程類別之間的關聯性。

C# 範例的類別圖表。

  • Bot UserProfile 將收集之使用者信息的類別。
  • 類別 ConversationFlow ,用來控制收集使用者資訊時的交談狀態。
  • 用於追蹤交談所在位置的內部 ConversationFlow.Question 列舉。

用戶狀態會追蹤使用者的名稱、年齡和所選日期,而交談狀態將會追蹤您上次詢問使用者的內容。 由於您不打算部署此 Bot,因此您會將使用者和交談狀態設定為使用 記憶體記憶體

您可以使用 Bot 的訊息回合處理程式加上使用者和交談狀態屬性來管理交談流程和輸入集合。 在您的 Bot 中,您將記錄在訊息回合處理程式的每個反覆項目期間收到的狀態屬性資訊。

建立交談和用戶物件

在啟動時建立使用者和交談狀態物件,並在 Bot 建構函式中透過相依性插入加以取用。

Startup.cs

// 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.
services.AddSingleton<UserState>();

// Create the Conversation state.
services.AddSingleton<ConversationState>();

Bots/CustomPromptBot.cs

private readonly BotState _userState;
private readonly BotState _conversationState;

public CustomPromptBot(ConversationState conversationState, UserState userState)
{
    _conversationState = conversationState;
    _userState = userState;
}

建立屬性存取子

建立使用者配置檔和交談流程屬性的屬性存取子,然後呼叫 GetAsync 以從狀態擷取屬性值。

Bots/CustomPromptBot.cs

protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
    var conversationStateAccessors = _conversationState.CreateProperty<ConversationFlow>(nameof(ConversationFlow));
    var flow = await conversationStateAccessors.GetAsync(turnContext, () => new ConversationFlow(), cancellationToken);

    var userStateAccessors = _userState.CreateProperty<UserProfile>(nameof(UserProfile));
    var profile = await userStateAccessors.GetAsync(turnContext, () => new UserProfile(), cancellationToken);

在回合結束之前,呼叫 SaveChangesAsync 以寫入記憶體的任何狀態變更。

    await _conversationState.SaveChangesAsync(turnContext, false, cancellationToken);
    await _userState.SaveChangesAsync(turnContext, false, cancellationToken);
}

訊息回合處理程式

處理訊息活動時,訊息處理程式會使用協助程式方法來管理交談並提示使用者。 協助程式方法會在下一節中說明。

Bots/CustomPromptBot.cs

protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
    var conversationStateAccessors = _conversationState.CreateProperty<ConversationFlow>(nameof(ConversationFlow));
    var flow = await conversationStateAccessors.GetAsync(turnContext, () => new ConversationFlow(), cancellationToken);

    var userStateAccessors = _userState.CreateProperty<UserProfile>(nameof(UserProfile));
    var profile = await userStateAccessors.GetAsync(turnContext, () => new UserProfile(), cancellationToken);

    await FillOutUserProfileAsync(flow, profile, turnContext, cancellationToken);

    // Save changes.
    await _conversationState.SaveChangesAsync(turnContext, false, cancellationToken);
    await _userState.SaveChangesAsync(turnContext, false, cancellationToken);
}

填寫使用者配置檔

Bot 會根據 Bot 在上一回合中詢問的問題,提示使用者提供資訊。 輸入是使用驗證方法剖析。

每個驗證方法都遵循類似的設計:

  • 傳回值表示輸入是否為這個問題的有效答案。
  • 如果通過驗證,它會產生剖析和正規化值以儲存。
  • 如果驗證失敗,它會產生訊息,Bot 可以再次要求資訊。

下列章節將說明驗證方法。

Bots/CustomPromptBot.cs

{
    var input = turnContext.Activity.Text?.Trim();
    string message;

    switch (flow.LastQuestionAsked)
    {
        case ConversationFlow.Question.None:
            await turnContext.SendActivityAsync("Let's get started. What is your name?", null, null, cancellationToken);
            flow.LastQuestionAsked = ConversationFlow.Question.Name;
            break;
        case ConversationFlow.Question.Name:
            if (ValidateName(input, out var name, out message))
            {
                profile.Name = name;
                await turnContext.SendActivityAsync($"Hi {profile.Name}.", null, null, cancellationToken);
                await turnContext.SendActivityAsync("How old are you?", null, null, cancellationToken);
                flow.LastQuestionAsked = ConversationFlow.Question.Age;
                break;
            }
            else
            {
                await turnContext.SendActivityAsync(message ?? "I'm sorry, I didn't understand that.", null, null, cancellationToken);
                break;
            }

        case ConversationFlow.Question.Age:
            if (ValidateAge(input, out var age, out message))
            {
                profile.Age = age;
                await turnContext.SendActivityAsync($"I have your age as {profile.Age}.", null, null, cancellationToken);
                await turnContext.SendActivityAsync("When is your flight?", null, null, cancellationToken);
                flow.LastQuestionAsked = ConversationFlow.Question.Date;
                break;
            }
            else
            {
                await turnContext.SendActivityAsync(message ?? "I'm sorry, I didn't understand that.", null, null, cancellationToken);
                break;
            }

        case ConversationFlow.Question.Date:
            if (ValidateDate(input, out var date, out message))
            {
                profile.Date = date;
                await turnContext.SendActivityAsync($"Your cab ride to the airport is scheduled for {profile.Date}.");
                await turnContext.SendActivityAsync($"Thanks for completing the booking {profile.Name}.");
                await turnContext.SendActivityAsync($"Type anything to run the bot again.");
                flow.LastQuestionAsked = ConversationFlow.Question.None;
                profile = new UserProfile();
                break;
            }
            else
            {
                await turnContext.SendActivityAsync(message ?? "I'm sorry, I didn't understand that.", null, null, cancellationToken);
                break;
            }
    }
}

剖析和驗證輸入

Bot 會使用下列準則來驗證輸入。

  • 名稱必須是非空白字串。 其正規化方式是修剪空格符。
  • 年齡必須介於 18 到 120 之間。 它會藉由傳回整數來正規化。
  • 日期必須是未來至少一小時的日期或時間。 只要傳回已剖析輸入的日期部分,即可將它正規化。

注意

針對年齡和日期輸入,此範例會使用 Microsoft/Recognizers-Text 連結庫來執行初始剖析。 這隻是剖析輸入的一種方式。 如需這些連結庫的詳細資訊,請參閱專案的 自述檔

Bots/CustomPromptBot.cs

private static bool ValidateName(string input, out string name, out string message)
{
    name = null;
    message = null;

    if (string.IsNullOrWhiteSpace(input))
    {
        message = "Please enter a name that contains at least one character.";
    }
    else
    {
        name = input.Trim();
    }

    return message is null;
}

private static bool ValidateAge(string input, out int age, out string message)
{
    age = 0;
    message = null;

    // Try to recognize the input as a number. This works for responses such as "twelve" as well as "12".
    try
    {
        // Attempt to convert the Recognizer result to an integer. This works for "a dozen", "twelve", "12", and so on.
        // The recognizer returns a list of potential recognition results, if any.

        var results = NumberRecognizer.RecognizeNumber(input, Culture.English);

        foreach (var result in results)
        {
            // The result resolution is a dictionary, where the "value" entry contains the processed string.
            if (result.Resolution.TryGetValue("value", out var value))
            {
                age = Convert.ToInt32(value);
                if (age >= 18 && age <= 120)
                {
                    return true;
                }
            }
        }

        message = "Please enter an age between 18 and 120.";
    }
    catch
    {
        message = "I'm sorry, I could not interpret that as an age. Please enter an age between 18 and 120.";
    }

    return message is null;
}

private static bool ValidateDate(string input, out string date, out string message)
{
    date = null;
    message = null;

    // Try to recognize the input as a date-time. This works for responses such as "11/14/2018", "9pm", "tomorrow", "Sunday at 5pm", and so on.
    // The recognizer returns a list of potential recognition results, if any.
    try
    {
        var results = DateTimeRecognizer.RecognizeDateTime(input, Culture.English);

        // Check whether any of the recognized date-times are appropriate,
        // and if so, return the first appropriate date-time. We're checking for a value at least an hour in the future.
        var earliest = DateTime.Now.AddHours(1.0);

        foreach (var result in results)
        {
            // The result resolution is a dictionary, where the "values" entry contains the processed input.
            var resolutions = result.Resolution["values"] as List<Dictionary<string, string>>;

            foreach (var resolution in resolutions)
            {
                // The processed input contains a "value" entry if it is a date-time value, or "start" and
                // "end" entries if it is a date-time range.
                if (resolution.TryGetValue("value", out var dateString)
                    || resolution.TryGetValue("start", out dateString))
                {
                    if (DateTime.TryParse(dateString, out var candidate)
                        && earliest < candidate)
                    {
                        date = candidate.ToShortDateString();
                        return true;
                    }
                }
            }
        }

        message = "I'm sorry, please enter a date at least an hour out.";
    }
    catch
    {
        message = "I'm sorry, I could not interpret that as an appropriate date. Please enter a date at least an hour out.";
    }

    return false;
}

在本機測試 Bot

下載並安裝 Bot Framework 模擬器 ,以在本機測試 Bot。

  1. 在本機電腦上執行範例。 如果您需要指示,請參閱 README C# 範例、JS 範例或 Python 範例檔案。
  2. 使用模擬器進行測試。

其他資源

Dialogs 連結庫 提供類別,可自動化管理交談的許多層面。

後續步驟