분기 및 루프를 사용하여 고급 대화 흐름 만들기

적용 대상: SDK v4

대화 상자 라이브러리를 사용하여 복잡한 대화 흐름을 만들 수 있습니다. 이 문서에서는 분기 및 루프의 복잡한 대화를 관리하는 방법과 대화 상자의 여러 부분 간에 인수를 전달하는 방법을 설명합니다.

참고 항목

Bot Framework JavaScript, C#및 Python SDK는 계속 지원되지만 Java SDK는 2023년 11월에 종료되는 최종 장기 지원으로 사용 중지됩니다.

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

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

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

필수 조건

이 샘플 정보

이 샘플은 목록에서 최대 두 개의 회사를 검토하기 위해 사용자를 등록할 수 있는 봇을 나타냅니다. 봇은 세 가지 구성 요소 대화 상자를 사용하여 대화 흐름을 관리합니다. 각 구성 요소 대화 상자에는 폭포 대화 상자와 사용자 입력을 수집하는 데 필요한 프롬프트가 포함됩니다. 이러한 대화 상자는 다음 섹션에서 자세히 설명합니다. 대화 상태를 사용하여 대화 상자를 관리하고 사용자 상태를 사용하여 사용자 및 검토하려는 회사에 대한 정보를 저장합니다.

봇은 작업 처리기에서 파생됩니다. 많은 샘플 봇과 같은 방식으로 사용자를 환영하고, 대화를 사용하여 사용자의 메시지를 처리하고, 순서가 끝나기 전에 사용자와 대화 상태를 저장합니다.

대화를 사용하려면 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>();

대화 상자 만들기

이 봇에는 다음 세 가지 대화 상자가 포함되어 있습니다.

  • 기본 대화 상자는 전체 프로세스를 시작한 다음 수집된 정보를 요약합니다.
  • 최상위 대화는 사용자 정보를 수집하고 사용자의 나이를 기준으로 분기 논리를 포함합니다.
  • 검토 선택 대화 상자를 사용하면 사용자가 검토할 회사를 반복적으로 선택할 수 있습니다. 루프 논리를 사용하여 이 작업을 수행합니다.

기본 대화 상자

기본 대화 상자에는 다음 두 단계가 있습니다.

  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을 선택하여 완료합니다.
    • 대화 상자가 초기 정보로 시작된 경우 폭포 단계 컨텍스트의 옵션 속성을 통해 정보를 사용할 수 있습니다. 검토 선택 대화가 다시 시작될 수 있으며 이는 사용자가 검토할 회사를 여러 개 선택할 수 있도록 하는 데 사용됩니다.
    • 사용자가 검토할 회사를 이미 선택한 경우 해당 회사는 사용 가능한 선택 항목에서 제거됩니다.
    • 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);
    }
}

대화 상자 실행

대화 상자 봇 클래스는 작업 처리기를 확장하고 대화 상자를 실행하기 위한 논리를 포함합니다. 대화 상자 및 환영 봇 클래스는 대화에 참가할 때도 사용자를 환영하도록 대화 봇을 확장합니다.

봇의 턴 처리기는 세 개의 대화 상자로 정의된 대화 흐름을 반복합니다. 사용자로부터 메시지를 수신하는 경우:

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

봇에 대한 서비스 등록

필요에 따라 서비스를 만들고 등록합니다.

  • 봇에 대한 기본 서비스: 어댑터 및 봇 구현.
  • 상태를 관리하기 위한 서비스: 스토리지, 사용자 상태 및 대화 상태.
  • 봇이 사용할 루트 대화 상자입니다.

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

참고 항목

메모리 스토리지는 테스트 목적으로만 사용되며 프로덕션 용도로는 사용되지 않습니다. 프로덕션 봇에 영구 스토리지 유형을 사용해야 합니다.

봇 테스트

  1. 아직 설치하지 않은 경우 Bot Framework Emulator설치합니다.

  2. 머신에서 로컬로 샘플을 실행합니다.

  3. 에뮬레이터를 시작하고 봇에 연결한 다음, 아래와 같은 메시지를 보냅니다.

    복잡한 대화 봇과의 대화 내용 예제입니다.

추가 리소스

대화 상자를 구현하는 방법에 대한 소개는 단일 폭포 대화 상자와 몇 가지 프롬프트를 사용하여 사용자에게 일련의 질문을 하는 순차적 대화 흐름 구현을 참조하세요.

Dialogs 라이브러리에는 프롬프트에 대한 기본 유효성 검사가 포함되어 있습니다. 사용자 지정 유효성 검사를 추가할 수도 있습니다. 자세한 내용은 대화 프롬프트를 사용하여 사용자 입력 수집을 참조하세요.

대화 코드를 단순화하고 여러 봇을 다시 사용하려면 대화 집합의 일부를 별도의 클래스로 정의할 수 있습니다. 자세한 내용은 다시 사용 대화 상자를 참조 하세요.

다음 단계