Vytvoření pokročilého toku konverzace pomocí větví a smyček

PLATÍ PRO: SDK v4

Pomocí knihovny dialogových oken můžete vytvářet složité toky konverzací. Tento článek popisuje, jak spravovat složité konverzace, které větve a smyčky a jak předávat argumenty mezi různými částmi dialogového okna.

Poznámka:

Sady SDK služby Bot Framework JavaScript, C# a Python budou nadále podporovány, ale sada Java SDK se vyřazuje s konečnou dlouhodobou podporou končící v listopadu 2023.

Stávající roboti sestavení pomocí sady Java SDK budou i nadále fungovat.

Pro nové vytváření robotů zvažte použití Power Virtual Agents a přečtěte si o výběru správného řešení chatovacího robota.

Další informace najdete v tématu Budoucnost vytváření robotů.

Požadavky

O této ukázce

Tato ukázka představuje robota, který může zaregistrovat uživatele a zkontrolovat až dvě společnosti ze seznamu. Robot ke správě toku konverzace používá tři dialogy komponent. Každé dialogové okno komponenty obsahuje vodopádové dialogové okno a všechny výzvy potřebné ke shromáždění uživatelského vstupu. Tato dialogová okna jsou podrobněji popsána v následujících částech. Ke správě dialogových oken používá stav konverzace a používá stav uživatele k ukládání informací o uživateli a o tom, které společnosti chtějí zkontrolovat.

Robot je odvozený z obslužné rutiny aktivity. Stejně jako mnoho ukázkových robotů vítá uživatele, používá dialogy ke zpracování zpráv od uživatele a ukládá stav uživatele a konverzace před koncem turnu.

Pokud chcete použít dialogy, nainstalujte balíček NuGet Microsoft.Bot.Builder.Dialogs .

Diagram tříd pro ukázku jazyka C#.

Definování profilu uživatele

Profil uživatele bude obsahovat informace shromážděné dialogy, jméno uživatele, věk a společnosti vybrané ke kontrole.

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

Vytvoření dialogových oken

Tento robot obsahuje tři dialogy:

  • Hlavní dialog spustí celkový proces a pak shrne shromážděné informace.
  • Dialogové okno nejvyšší úrovně shromažďuje informace o uživatelích a zahrnuje logiku větvení na základě věku uživatele.
  • Dialogové okno pro výběr kontroly umožňuje uživateli iterativní výběr společností, které se mají zkontrolovat. K tomu používá logiku smyčky.

Hlavní dialog

Hlavní dialog má dva kroky:

  1. Spusťte dialogové okno nejvyšší úrovně.
  2. Načtěte a shrňte profil uživatele, který shromáždil dialog nejvyšší úrovně, uložil tyto informace do stavu uživatele a pak signalizoval konec hlavního dialogového okna.

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

Dialogové okno nejvyšší úrovně

Dialogové okno nejvyšší úrovně má čtyři kroky:

  1. Požádejte o jméno uživatele.
  2. Požádejte o věk uživatele.
  3. Buď spusťte dialogové okno pro výběr kontroly nebo přejděte k dalšímu kroku na základě věku uživatele.
  4. Nakonec uživateli děkuji za účast a vrácení shromážděných informací.

První krok vytvoří prázdný profil uživatele jako součást stavu dialogového okna. Dialogové okno začíná prázdným profilem a při jeho průběhu přidá do profilu informace. Po skončení vrátí poslední krok shromážděné informace.

Ve třetím kroku (počáteční výběr) se tok konverzace větví podle věku uživatele.

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

Dialogové okno pro výběr revizí

Dialogové okno pro výběr revizí má dva kroky:

  1. Požádejte uživatele, aby zvolil společnost, která si ji má zkontrolovat nebo done dokončit.
    • Pokud se dialogové okno spustilo s počátečními informacemi, jsou informace k dispozici prostřednictvím vlastnosti možností kontextu vodopádového kroku. Dialogové okno pro výběr revizí se může restartovat a používá ho k tomu, aby si uživatel mohl vybrat více než jednu společnost ke kontrole.
    • Pokud už uživatel vybral společnost k revizi, odebere se z dostupných voleb.
    • Přidá done se volba, která uživateli umožní včas ukončit smyčku.
  2. Podle potřeby tento dialog opakujte nebo ukončete.
    • Pokud si uživatel vybral společnost ke kontrole, přidejte ji do svého seznamu.
    • Pokud uživatel vybral dvě společnosti nebo se rozhodl ukončit, ukončete dialogové okno a vraťte shromážděný seznam.
    • V opačném případě dialogové okno restartujte a inicializujete ho obsahem jejich seznamu.

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

Spuštění dialogů

Třída robota dialogového okna rozšiřuje obslužnou rutinu aktivity a obsahuje logiku pro spouštění dialogů. Třída dialogového okna a uvítacího robota rozšiřuje robota dialogového okna, aby také přivítal uživatele, když se připojí ke konverzaci.

Obslužná rutina otáčení robota opakuje tok konverzace definovaný třemi dialogy. Když uživatel obdrží zprávu:

  1. Spustí hlavní dialog.
    • Pokud je zásobník dialogového okna prázdný, spustí se hlavní dialog.
    • V opačném případě jsou dialogy stále v polovině procesu a budou pokračovat v aktivním dialogovém okně.
  2. Uloží stav, takže všechny aktualizace uživatele, konverzace a stavu dialogového okna se zachovají.

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

Registrace služeb pro robota

Podle potřeby vytvořte a zaregistrujte služby:

  • Základní služby pro robota: adaptér a implementace robota
  • Služby pro správu stavu: úložiště, stav uživatele a stav konverzace.
  • Kořenový dialog, který robot použije.

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

Poznámka:

Úložiště paměti se používá jenom pro účely testování a není určené pro produkční použití. Ujistěte se, že pro produkčního robota používáte trvalý typ úložiště.

Otestování robota

  1. Pokud jste to ještě neudělali, nainstalujte bot Framework Emulator.

  2. Spusťte ukázku místně na svém počítači.

  3. Spusťte emulátor, připojte se k robotovi a odešlete zprávy, jak je znázorněno níže.

    Příklad přepisu z konverzace se složitým dialogovým robotem

Další materiály

Úvod k implementaci dialogového okna najdete v tématu Implementace sekvenčního toku konverzace, který používá jeden vodopádový dialog a několik výzev k zadání řady otázek uživatele.

Knihovna Dialogs obsahuje základní ověření pro výzvy. Můžete také přidat vlastní ověření. Další informace najdete v tématu Shromáždění uživatelského vstupu pomocí dialogového okna výzvy.

Pokud chcete zjednodušit kód dialogového okna a znovu ho použít více robotů, můžete definovat části dialogového okna nastavené jako samostatnou třídu. Další informace najdete v dialogových oknech pro opakované použití.

Další kroky