共用方式為


使用對話框來取用技能

適用於: SDK v4

本文示範如何在技能消費者中使用 技能對話。 技能對話框會將活動從父 Bot 張貼至技能 Bot,並將技能回應傳回給使用者。 使用者存取的技能 bot 可以同時處理訊息和事件活動。 如需實作技能的範例技能指令清單和相關信息,請參閱如何在 技能中使用對話。

如需在對話外部使用技能 Bot 的相關信息,請參閱如何實作技能消費者

注意

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

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

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

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

必要條件

關於此範例

skills SkillDialog 範例包含兩個機器人專案的範例:

  • 對話根機器人使用技能對話類別來調用技能。
  • 對話 技能 Bot,它會使用對話來處理來自技能取用者的活動。

本文著重於如何使用 根 Bot 中的技能對話 類別來管理技能、傳送訊息和事件活動,以及取消技能。

如需有關建立技能取用者之其他層面的資訊,請參閱如何 實作技能取用者

如需對話技能 Bot 的相關信息,請參閱如何在 技能內使用對話。

資源

對於已部署的 Bot,Bot 對 Bot 驗證會要求每個參與的 Bot 都有有效的身分識別。 不過,您可以使用 Bot Framework 模擬器在本機測試技能和技能取用者,而不需要身分識別資訊。

應用程式設定

  1. 或者,將根 Bot 的身分識別資訊新增至組態檔。
  2. 將技能主機端點(服務或回呼 URL)新增至技能取用者應回復的技能。
  3. 為技能使用者將使用的每個技能新增項目。 每個項目都包含:
    • 技能使用者將用來識別每個技能的識別碼。
    • 技能 Bot 的應用程式或用戶端識別碼(可選)。
    • 技能的傳訊端點。

注意

如果技能或技能取用者指定身分識別,則兩者都必須。

DialogRootBot\appsettings.json

選擇性地新增根 Bot 的識別資訊,並將回應技能 Bot 的應用程式或用戶端識別碼新增至 BotFrameworkSkills 陣列。

{
  "MicrosoftAppType": "",
  "MicrosoftAppId": "",
  "MicrosoftAppPassword": "",
  "MicrosoftAppTenantId": "",

  "SkillHostEndpoint": "http://localhost:3978/api/skills/",
  "BotFrameworkSkills": [
    {
      "Id": "DialogSkillBot",
      "AppId": "",
      "SkillEndpoint": "http://localhost:39783/api/messages"
    }
  ]
}

對話框邏輯

Bot 的主要對話包含 此 Bot 所取用之每個技能的技能對話 。 技能對話會透過您各種技能相關物件來管理技能,例如 技能用戶端技能交談標識符處理站 物件。 主要對話也會示範如何根據使用者輸入取消技能(透過技能對話)。

此 Bot 使用的技能支援幾個不同的功能。 它可以預訂航班或取得城市的天氣。 此外,如果它收到上述任一內容以外的訊息,且已設定 LUIS 辨識器,則會嘗試解譯用戶的意圖。

備註

Language Understanding (LUIS) 將於 2025 年 10 月 1 日淘汰。 從 2023 年 4 月 1 日起,您將無法建立新的 LUIS 資源。 新版的語言理解現在已提供作為 Azure AI 語言的一部分。

對話式語言理解(CLU)是 Azure AI 語言的一項功能,是 LUIS 的更新版本。 如需 Bot Framework SDK 中語言理解支援的詳細資訊,請參閱 自然語言理解

技能指令清單(C#、JavaScriptJavaPython)描述技能可執行的動作、其輸入和輸出參數,以及技能的端點。 請注意,技能可以處理 「BookFlight」 或 「GetWeather」 事件。 它也可以處理訊息。

主要對話框的程式碼如下:

主要對話繼承自 元件對話 類別。 如需元件對話的詳細資訊,請參閱如何 管理對話複雜度

初始化主要對話框

主要對話包含對話(用於管理技能外部的對話流程)和技能對話(用於管理技能)。 瀑布包含下列步驟,在接下來的幾節中會更詳細地說明。

  1. 提示用戶選取要使用的技能。 (根機器人會取用一個技能。)
  2. 提示用戶選取要用於該技能的動作。 (技能機器人定義了三個動作。)
  3. 根據所選動作,使用初始活動啟動所選技能。
  4. 技能完成後,如果有的話,顯示結果。 然後,重新啟動瀑布。

DialogRootBot\Dialogs\MainDialog.cs

MainDialog 類別衍生自 ComponentDialog。 除了交談狀態之外,對話還需要根 Bot 的身分識別,以及技能交談標識碼處理站、技能 HTTP 用戶端和技能設定對象的參考。

對話建構函式會檢查其輸入參數、新增技能對話、新增提示和瀑布式對話來管理技能外部的對話流程,並建立屬性存取子來追蹤作用中的技能,如果有的話。

建構函式會呼叫 AddSkillDialogs 輔助方法,為組態檔中包含的每個技能建立 SkillDialog,正如從組態檔讀取到 SkillsConfiguration 物件一樣。

// Helper method that creates and adds SkillDialog instances for the configured skills.
private void AddSkillDialogs(ConversationState conversationState, SkillConversationIdFactoryBase conversationIdFactory, SkillsConfiguration skillsConfig, string botId)
{
    foreach (var skillInfo in _skillsConfig.Skills.Values)
    {
        // Create the dialog options.
        var skillDialogOptions = new SkillDialogOptions
        {
            BotId = botId,
            ConversationIdFactory = conversationIdFactory,
            SkillClient = _auth.CreateBotFrameworkClient(),
            SkillHostEndpoint = skillsConfig.SkillHostEndpoint,
            ConversationState = conversationState,
            Skill = skillInfo
        };

        // Add a SkillDialog for the selected skill.
        AddDialog(new SkillDialog(skillDialogOptions, skillInfo.Id));
    }
}

選取技能

在第一個步驟中,主要對話框會提示使用者要呼叫哪些技能,並使用 「SkillPrompt」 選擇提示來取得答案。 (此 Bot 只定義一個技能。

DialogRootBot\Dialogs\MainDialog.cs

// Render a prompt to select the skill to call.
private async Task<DialogTurnResult> SelectSkillStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    // Create the PromptOptions from the skill configuration which contain the list of configured skills.
    var messageText = stepContext.Options?.ToString() ?? "What skill would you like to call?";
    var repromptMessageText = "That was not a valid choice, please select a valid skill.";
    var options = new PromptOptions
    {
        Prompt = MessageFactory.Text(messageText, messageText, InputHints.ExpectingInput),
        RetryPrompt = MessageFactory.Text(repromptMessageText, repromptMessageText, InputHints.ExpectingInput),
        Choices = _skillsConfig.Skills.Select(skill => new Choice(skill.Value.Id)).ToList()
    };

    // Prompt the user to select a skill.
    return await stepContext.PromptAsync("SkillPrompt", options, cancellationToken);
}

選取技能動作

在下一個步驟中,主要對話框:

  1. 儲存用戶選取之技能的相關信息。
  2. 提示使用者要使用哪一個技能動作,並使用 「SkillActionPrompt」 選擇提示來取得答案。
    • 它會使用協助程式方法來取得要從中選擇的動作清單。
    • 如果使用者的輸入不符合其中一個選項,則與此提示相關聯的提示驗證器預設會傳送訊息給技能。

此 Bot 中包含的選項可協助測試為此技能定義的動作。 更通常,您會從技能指令清單讀取選項,並根據該清單向使用者呈現選項。

DialogRootBot\Dialogs\MainDialog.cs

// Render a prompt to select the action for the skill.
private async Task<DialogTurnResult> SelectSkillActionStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    // Get the skill info based on the selected skill.
    var selectedSkillId = ((FoundChoice)stepContext.Result).Value;
    var selectedSkill = _skillsConfig.Skills.FirstOrDefault(s => s.Value.Id == selectedSkillId).Value;

    // Remember the skill selected by the user.
    stepContext.Values[_selectedSkillKey] = selectedSkill;

    // Create the PromptOptions with the actions supported by the selected skill.
    var messageText = $"Select an action # to send to **{selectedSkill.Id}** or just type in a message and it will be forwarded to the skill";
    var options = new PromptOptions
    {
        Prompt = MessageFactory.Text(messageText, messageText, InputHints.ExpectingInput),
        Choices = GetSkillActions(selectedSkill)
    };

    // Prompt the user to select a skill action.
    return await stepContext.PromptAsync("SkillActionPrompt", options, cancellationToken);
}
// Helper method to create Choice elements for the actions supported by the skill.
private IList<Choice> GetSkillActions(BotFrameworkSkill skill)
{
    // Note: the bot would probably render this by reading the skill manifest.
    // We are just using hardcoded skill actions here for simplicity.

    var choices = new List<Choice>();
    switch (skill.Id)
    {
        case "DialogSkillBot":
            choices.Add(new Choice(SkillActionBookFlight));
            choices.Add(new Choice(SkillActionBookFlightWithInputParameters));
            choices.Add(new Choice(SkillActionGetWeather));
            break;
    }

    return choices;
}
// This validator defaults to Message if the user doesn't select an existing option.
private Task<bool> SkillActionPromptValidator(PromptValidatorContext<FoundChoice> promptContext, CancellationToken cancellationToken)
{
    if (!promptContext.Recognized.Succeeded)
    {
        // Assume the user wants to send a message if an item in the list is not selected.
        promptContext.Recognized.Value = new FoundChoice { Value = SkillActionMessage };
    }

    return Task.FromResult(true);
}

啟動技能

在下一個步驟中,將出現主要對話框:

  1. 擷取用戶選取之技能與技能活動的相關信息。
  2. 使用輔助方法來建立最初傳送至技能的活動。
  3. 建立用來啟動技能對話框的對話框選項。 這包括要傳送的初始活動。
  4. 在呼叫技能之前儲存狀態。 (這是必要的,因為技能回應可能會來到技能用戶的不同實例。)
  5. 開始技能對話框,傳入用來呼叫的技能 ID 及選項。

DialogRootBot\Dialogs\MainDialog.cs

// Starts the SkillDialog based on the user's selections.
private async Task<DialogTurnResult> CallSkillActionStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    var selectedSkill = (BotFrameworkSkill)stepContext.Values[_selectedSkillKey];

    Activity skillActivity;
    switch (selectedSkill.Id)
    {
        case "DialogSkillBot":
            skillActivity = CreateDialogSkillBotActivity(((FoundChoice)stepContext.Result).Value, stepContext.Context);
            break;

        // We can add other case statements here if we support more than one skill.
        default:
            throw new Exception($"Unknown target skill id: {selectedSkill.Id}.");
    }

    // Create the BeginSkillDialogOptions and assign the activity to send.
    var skillDialogArgs = new BeginSkillDialogOptions { Activity = skillActivity };

    // Save active skill in state.
    await _activeSkillProperty.SetAsync(stepContext.Context, selectedSkill, cancellationToken);

    // Start the skillDialog instance with the arguments. 
    return await stepContext.BeginDialogAsync(selectedSkill.Id, skillDialogArgs, cancellationToken);
}

摘要說明技能結果

在最後一個步驟中,主要對話框:

  1. 如果技能傳回值,請向用戶顯示結果。
  2. 從對話狀態清除使用中的技能。
  3. 從對話狀態中移除已啟用的技能屬性。
  4. 重新啟動自身(主要對話框)。

DialogRootBot\Dialogs\MainDialog.cs

// The SkillDialog has ended, render the results (if any) and restart MainDialog.
private async Task<DialogTurnResult> FinalStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    var activeSkill = await _activeSkillProperty.GetAsync(stepContext.Context, () => null, cancellationToken);

    // Check if the skill returned any results and display them.
    if (stepContext.Result != null)
    {
        var message = $"Skill \"{activeSkill.Id}\" invocation complete.";
        message += $" Result: {JsonConvert.SerializeObject(stepContext.Result)}";
        await stepContext.Context.SendActivityAsync(MessageFactory.Text(message, message, inputHint: InputHints.IgnoringInput), cancellationToken: cancellationToken);
    }

    // Clear the skill selected by the user.
    stepContext.Values[_selectedSkillKey] = null;

    // Clear active skill in state.
    await _activeSkillProperty.DeleteAsync(stepContext.Context, cancellationToken);

    // Restart the main dialog with a different message the second time around.
    return await stepContext.ReplaceDialogAsync(InitialDialogId, $"Done with \"{activeSkill.Id}\". \n\n What skill would you like to call?", cancellationToken);
}

允許使用者取消技能

主要對話會覆寫on continue dialog 方法的預設行為,以允許使用者取消目前的功能(如果有的話)。 在函式內:

  • 如果有作用中的技能,且用戶傳送「中止」訊息,請取消所有對話框,並將主要對話排入佇列,以從頭開始重新啟動。
  • 然後,呼叫 on continue dialog 方法的基本實現,以繼續處理目前的回合。

DialogRootBot\Dialogs\MainDialog.cs

protected override async Task<DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc, CancellationToken cancellationToken = default)
{
    // This is an example on how to cancel a SkillDialog that is currently in progress from the parent bot.
    var activeSkill = await _activeSkillProperty.GetAsync(innerDc.Context, () => null, cancellationToken);
    var activity = innerDc.Context.Activity;
    if (activeSkill != null && activity.Type == ActivityTypes.Message && activity.Text.Equals("abort", StringComparison.OrdinalIgnoreCase))
    {
        // Cancel all dialogs when the user says abort.
        // The SkillDialog automatically sends an EndOfConversation message to the skill to let the
        // skill know that it needs to end its current dialogs, too.
        await innerDc.CancelAllDialogsAsync(cancellationToken);
        return await innerDc.ReplaceDialogAsync(InitialDialogId, "Canceled! \n\n What skill would you like to call?", cancellationToken);
    }

    return await base.OnContinueDialogAsync(innerDc, cancellationToken);
}

活動處理程序邏輯

由於每個回合的技能邏輯都是由主要對話處理,所以活動處理程式看起來會像其他對話範例一樣。

DialogRootBot\Bots\RootBot.cs

public class RootBot<T> : ActivityHandler
    where T : Dialog
private readonly ConversationState _conversationState;
private readonly Dialog _mainDialog;

public RootBot(ConversationState conversationState, T mainDialog)
{
    _conversationState = conversationState;
    _mainDialog = mainDialog;
}
public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default)
{
    if (turnContext.Activity.Type != ActivityTypes.ConversationUpdate)
    {
        // Run the Dialog with the Activity.
        await _mainDialog.RunAsync(turnContext, _conversationState.CreateProperty<DialogState>("DialogState"), cancellationToken);
    }
    else
    {
        // Let the base class handle the activity.
        await base.OnTurnAsync(turnContext, cancellationToken);
    }

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

服務註冊

使用技能對話所需的服務,與一般技能取用者所需的服務相同。 如需了解對必要服務的討論,請參閱如何 實作技能使用者

測試根機器人

您可以在模擬環境中測試技能消費者,就像普通 bot 一樣;不過,您需要同時執行技能和技能消費者 bot。 如需如何設定技能的資訊,請參閱如何使用 技能 內的對話框。

下載並安裝最新的 Bot Framework 模擬器

  1. 在本機上執行對話技能機器人和對話根機器人。 如果您需要指示,請參閱範例的 C#JavaScriptJavaPython
  2. 使用模擬器來測試 Bot。
    • 當您第一次加入交談時,Bot 會顯示歡迎訊息,並詢問您想要呼叫的技能。 此範例的技能 Bot 只有一個技能。
    • 選取 DialogSkillBot
  3. 然後,Bot 會要求您選擇技能的動作。 選擇 [BookFlight]。
    1. 答覆提示。
    2. 技能完成後,根機器人會顯示預訂細節,然後再次提示您想呼叫的技能。
  4. 再次選取 DialogSkillBot 和 “BookFlight”。
    1. 回答第一個提示,然後輸入「中止」以中斷技能。
    2. 根機器人會取消技能,並提示您選擇想要呼叫的技能。

深入瞭解偵錯

由於技能與技能取用者之間的資料流動已經過驗證,因此在偵錯這類 Bot 時會需要額外的步驟。

  • 技能使用者及其直接或間接使用的所有技能都必須處於運行狀態。
  • 如果 Bot 在本機執行,且任何 Bot 都有應用程式識別碼和密碼,則所有 Bot 都必須具有有效的標識碼和密碼。
  • 如果所有 Bot 都已部署,請查看如何使用 devtunnel 從任何頻道偵錯 Bot。
  • 如果某些 Bot 在本機執行,並且有些 Bot 已部署,請參閱如何偵錯技能或技能使用者。

否則,您可以偵錯技能取用者或技能,就像偵錯其他 Bot 一樣。 如需詳細資訊,請參閱偵錯一個 Bot使用 Bot Framework 模擬器進行偵錯

其他資訊

瞭解如何實作技能取用者,以瞭解技能取用者的一般實作方法。