대화를 사용하여 스킬 사용

적용 대상: SDK v4

이 문서에서는 기술 소비자 내에서 기술 대화 상자를 사용하는 방법을 보여 줍니다. 기술 대화 상자는 부모 봇의 활동을 기술 봇에 게시하고 사용자에게 기술 응답을 반환합니다. 이 소비자가 액세스하는 스킬 봇은 메시지 및 이벤트 활동을 모두 처리할 수 있습니다. 샘플 기술 매니페스트 및 기술 구현에 대한 자세한 내용은 기술 내에서 대화 상자를 사용하는 방법을 참조하세요.

대화 상자 외부에서 기술 봇을 사용하는 방법에 대한 자세한 내용은 기술 소비자를 구현하는 방법을 참조하세요.

참고 항목

Bot Framework JavaScript, C#및 Python SDK는 계속 지원되지만 Java SDK는 2023년 11월에 종료되는 최종 장기 지원으로 사용 중지됩니다. 이 리포지토리 내의 중요한 보안 및 버그 수정만 수행됩니다.

Java SDK를 사용하여 빌드된 기존 봇은 계속 작동합니다.

새 봇 빌드의 경우 Power Virtual Agents 사용을 고려하고 올바른 챗봇 솔루션을 선택하는 방법을 읽어 보세요.

자세한 내용은 봇 빌드의 미래를 참조 하세요.

필수 조건

이 샘플 정보

skillDialog 기술 샘플에는 두 개의 봇에 대한 프로젝트가 포함되어 있습니다.

  • ‘대화 루트 봇’은 ‘스킬 대화’ 클래스를 사용하여 스킬을 사용합니다.
  • 대화 상자 기술 봇대화 상자를 사용하여 기술 소비자의 활동을 처리합니다.

이 문서에서는 루트 봇에서 기술 대화 상자 클래스를 사용하여 기술을 관리하고, 메시지 및 이벤트 활동을 보내고, 기술을 취소하는 방법에 중점을 둡니다.

기술 소비자를 만드는 다른 측면에 대한 자세한 내용은 기술 소비자를 구현하는 방법을 참조하세요.

대화 기술 봇에 대한 자세한 내용은 기술 내에서 대화 상자를 사용하는 방법을 참조하세요.

리소스

배포된 봇의 경우 봇-봇 인증을 사용하려면 참여하는 각 봇에 유효한 ID가 있어야 합니다. 그러나 ID 정보 없이 Bot Framework Emulator를 사용하여 기술 및 기술 소비자를 로컬로 테스트할 수 있습니다.

애플리케이션 구성

  1. 필요에 따라 루트 봇의 ID 정보를 구성 파일에 추가합니다.
  2. 기술이 기술 소비자에게 회신해야 하는 기술 호스트 엔드포인트(서비스 또는 콜백 URL)를 추가합니다.
  3. 기술 소비자가 사용할 각 기술에 대한 항목을 추가합니다. 각 항목에는 다음이 포함됩니다.
    • 기술 소비자가 각 기술을 식별하는 데 사용할 ID입니다.
    • 필요에 따라 기술 봇의 앱 또는 클라이언트 ID입니다.
    • 기술의 메시징 엔드포인트입니다.

참고 항목

기술 또는 기술 소비자가 ID를 지정하는 경우 둘 다 있어야 합니다.

DialogRootBot\appsettings.json

필요에 따라 루트 봇의 ID 정보를 추가하고 에코 기술 봇의 앱 또는 클라이언트 ID를 배열에 BotFrameworkSkills 추가합니다.

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

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

대화 논리

봇의 기본 대화 상자에는 이 봇이 사용하는 각 기술에 대한 기술 대화 상자가 포함되어 있습니다. 스킬 대화는 ‘스킬 클라이언트’ 및 ‘스킬 대화 ID 팩터리’ 개체와 같은 다양한 스킬 관련 개체를 통해 스킬을 관리합니다. 기본 대화 상자에서는 사용자 입력에 따라 기술 대화 상자를 통해 기술을 취소하는 방법도 보여 줍니다.

이 봇에서 사용하는 기술은 몇 가지 다른 기능을 지원합니다. 그것은 비행을 예약하거나 도시의 날씨를 얻을 수 있습니다. 또한 이러한 컨텍스트 외부에서 메시지를 수신하고 LUIS 인식기가 구성된 경우 사용자의 의도를 해석하려고 시도합니다.

참고 항목

LUIS(Language Understanding)는 2025년 10월 1일에 사용 중지됩니다. 2023년 4월 1일부터 새 LUIS 리소스를 만들 수 없습니다. 이제 최신 버전의 언어 이해가 Azure AI Language의 일부로 제공됩니다.

Azure AI Language의 기능인 CLU(대화형 언어 이해)는 업데이트된 LUIS 버전입니다. Bot Framework SDK의 언어 이해 지원에 대한 자세한 내용은 자연어 이해를 참조하세요.

기술 매니페스트(C#, JavaScript, Java, Python)는 기술이 수행할 수 있는 작업, 입력 및 출력 매개 변수 및 기술의 엔드포인트를 설명합니다. 참고로, 이 기술은 “BookFlight” 또는 “GetWeather” 이벤트를 처리할 수 있습니다. 메시지를 처리할 수도 있습니다.

기본 대화 상자에는 다음을 위한 코드가 포함되어 있습니다.

기본 대화 상자는 구성 요소 대화 상자 클래스에서 상속됩니다. 구성 요소 대화에 대한 자세한 내용은 대화 복잡성 관리 방법을 참조하세요.

기본 대화 상자 초기화

기본 대화 상자에는 대화 상자(기술 외부의 대화 흐름 관리용) 및 기술 대화 상자(기술 관리용)가 포함됩니다. 폭포에는 다음 몇 섹션에서 자세히 설명된 다음 단계가 포함됩니다.

  1. 사용자에게 사용할 기술을 선택하라는 메시지를 표시합니다. (루트 봇은 하나의 기술을 사용합니다.)
  2. 사용자에게 해당 스킬에 사용할 작업을 선택하라는 메시지를 표시합니다. (기술 봇은 세 가지 작업을 정의합니다.)
  3. 선택한 작업을 기반으로 하는 초기 작업을 사용하여 선택한 스킬을 시작합니다.
  4. 기술이 완료되면 결과를 표시합니다(있는 경우). 그런 다음 폭포를 다시 시작합니다.

DialogRootBot\Dialogs\MainDialog.cs

MainDialog 클래스는 ComponentDialog에서 파생됩니다. 대화 상태 외에도 대화 상자에는 루트 봇의 ID와 기술 대화 ID 팩터리, 기술 HTTP 클라이언트 및 기술 구성 개체에 대한 참조가 필요합니다.

대화 상자 생성자는 입력 매개 변수를 검사 기술 대화 상자를 추가하고, 기술 외부의 대화 흐름을 관리하기 위한 프롬프트 및 폭포 대화 상자를 추가하고, 활성 기술을 추적하기 위한 속성 접근자를 만듭니다(있는 경우).

생성자는 AddSkillDialogs도우미 메서드인 호출하여 구성 파일에서 개체로 SkillsConfiguration 읽은 대로 구성 파일에 포함된 각 기술에 대해 만듭니 SkillDialog 다.

// 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" 선택 프롬프트를 사용하여 답변을 가져옵니다. (이 봇은 하나의 기술만 정의합니다.)

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" 선택 프롬프트를 사용하여 답변을 가져옵니다.
    • 도우미 메서드를 사용하여 선택할 작업 목록을 가져옵니다.
    • 사용자의 입력이 선택 항목 중 하나와 일치하지 않는 경우 이 프롬프트와 연결된 프롬프트 유효성 검사기에서 기본적으로 스킬에 메시지를 보냅니다.

이 봇에 포함된 선택 항목은 이 기술에 대해 정의된 작업을 테스트하는 데 도움이 될 수 있습니다. 일반적으로 기술 매니페스트에서 옵션을 읽고 해당 목록을 기반으로 사용자에게 옵션을 제공합니다.

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 대화 메서드의 기본 구현을 호출하여 현재 턴을 계속 처리합니다.

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 Framework Emulator를 다운로드하여 설치합니다.

  1. 대화 기술 봇 및 대화 루트 봇을 머신에서 로컬로 실행합니다. 지침이 필요한 경우 샘플의 README C#, JavaScript, Java, Python을 참조하세요.
  2. 에뮬레이터를 사용하여 봇을 테스트합니다.
    • 대화에 처음 참가하면 봇이 환영 메시지를 표시하고 어떤 기술을 호출할지 묻습니다. 이 샘플의 기술 봇에는 하나의 기술만 있습니다.
    • DialogSkillBot을 선택합니다.
  3. 그런 다음, 봇은 기술에 대한 작업을 선택하도록 요청합니다. "BookFlight"를 선택합니다.
    1. 프롬프트에 답변합니다.
    2. 기술이 완료되고 루트 봇이 예약 세부 정보를 표시한 후 호출하려는 기술에 대해 다시 확인합니다.
  4. DialogSkillBot을 다시 선택하고 "BookFlight"를 선택합니다.
    1. 첫 번째 프롬프트에 답변한 다음 “중단”을 입력하여 스킬을 중단합니다.
    2. 루트 봇은 스킬을 취소하고 호출하려는 스킬이 무엇인지 묻는 메시지를 표시합니다.

디버깅에 대한 자세한 정보

기술과 기술 소비자 간의 트래픽이 인증되므로 이러한 봇을 디버깅할 때 추가 단계가 있습니다.

  • 기술 소비자와 직접 또는 간접적으로 사용하는 모든 기술을 실행해야 합니다.
  • 봇이 로컬로 실행되고 앱 ID와 암호가 있는 봇이 있는 경우 모든 봇에는 유효한 ID와 암호가 있어야 합니다.
  • 봇이 모두 배포된 경우 ngrok사용하여 모든 채널에서 봇을 디버그하는 방법을 참조하세요.
  • 일부 봇이 로컬로 실행되고 일부 봇이 배포된 경우 기술 또는 기술 소비자를 디버그하는 방법을 알아보세요.

그렇지 않으면 다른 봇을 디버그하는 것처럼 기술 소비자 또는 기술을 디버그할 수 있습니다. 자세한 내용은 Bot Framework Emulator를 사용하여 봇 디버깅 및 디버그를 참조하세요.

추가 정보

일반적으로 기술 소비자를 구현하는 방법은 기술 소비자 를 구현하는 방법을 참조하세요.