Dela via


Skapa avancerat konversationsflöde med grenar och loopar

GÄLLER FÖR: SDK v4

Du kan skapa komplexa konversationsflöden med hjälp av dialogrutebiblioteket. Den här artikeln beskriver hur du hanterar komplexa konversationer som förgrenar och loopar och hur du skickar argument mellan olika delar av dialogrutan.

Kommentar

Bot Framework JavaScript-, C#- och Python-SDK:erna fortsätter att stödjas, men Java SDK dras tillbaka med slutligt långsiktigt stöd som slutar i november 2023.

Befintliga robotar som skapats med Java SDK fortsätter att fungera.

Om du vill skapa en ny robot kan du använda Microsoft Copilot Studio och läsa om hur du väljer rätt copilot-lösning.

Mer information finns i Framtiden för robotbygge.

Förutsättningar

Om det här exemplet

Det här exemplet representerar en robot som kan registrera användare för att granska upp till två företag från en lista. Roboten använder tre komponentdialogrutor för att hantera konversationsflödet. Varje komponentdialogruta innehåller en vattenfallsdialogruta och eventuella frågor som behövs för att samla in användarindata. Dessa dialogrutor beskrivs mer detaljerat i följande avsnitt. Den använder konversationstillstånd för att hantera sina dialogrutor och använder användartillstånd för att spara information om användaren och vilka företag de vill granska.

Roboten härleds från aktivitetshanteraren. Liksom många av exempelrobotarna välkomnar den användaren, använder dialogrutor för att hantera meddelanden från användaren och sparar användar- och konversationstillstånd innan svängen slutar.

Om du vill använda dialogrutor installerar du NuGet-paketet Microsoft.Bot.Builder.Dialogs .

Klassdiagram för C#-exempel.

Definiera användarprofilen

Användarprofilen innehåller information som samlas in av dialogrutorna, användarens namn, ålder och företag som valts att granska.

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

Skapa dialogrutorna

Den här roboten innehåller tre dialogrutor:

  • Huvuddialogrutan startar den övergripande processen och sammanfattar sedan den insamlade informationen.
  • Dialogrutan på den översta nivån samlar in användarinformation och innehåller förgreningslogik baserat på användarens ålder.
  • I dialogrutan för granskningsval kan användaren iterativt välja företag att granska. Den använder loopningslogik för att göra det.

Huvuddialogrutan

Huvuddialogrutan innehåller två steg:

  1. Starta dialogrutan på den översta nivån.
  2. Hämta och sammanfatta användarprofilen som dialogrutan på den översta nivån samlade in, spara informationen i användartillståndet och signalera sedan slutet av huvuddialogrutan.

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

Dialogrutan på den översta nivån

Dialogrutan på den översta nivån innehåller fyra steg:

  1. Fråga efter användarens namn.
  2. Fråga efter användarens ålder.
  3. Starta antingen dialogrutan för granskningsval eller gå vidare till nästa steg, baserat på användarens ålder.
  4. Slutligen tackar du användaren för att han eller hon deltar och returnerar den insamlade informationen.

Det första steget skapar en tom användarprofil som en del av dialogtillståndet. Dialogrutan börjar med en tom profil och lägger till information i profilen när den fortskrider. När den är slut returnerar det sista steget den insamlade informationen.

I det tredje steget (startval) förgrenar konversationsflödet, baserat på användarens ålder.

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

Dialogrutan för granskningsval

Dialogrutan för granskningsval har två steg:

  1. Be användaren att välja ett företag att granska eller done slutföra.
    • Om dialogrutan startades med någon inledande information är informationen tillgänglig via alternativegenskapen för vattenfallsstegkontexten. Dialogrutan för granskningsval kan starta om sig själv och den använder den för att tillåta användaren att välja fler än ett företag att granska.
    • Om användaren redan har valt ett företag att granska tas företaget bort från de tillgängliga alternativen.
    • Ett done val läggs till så att användaren kan avsluta loopen tidigt.
  2. Upprepa den här dialogrutan eller avsluta efter behov.
    • Om användaren har valt ett företag att granska lägger du till det i listan.
    • Om användaren har valt två företag eller väljer att avsluta dialogrutan avslutar du dialogrutan och returnerar den insamlade listan.
    • Annars startar du om dialogrutan och initierar den med innehållet i listan.

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

Kör dialogrutorna

Klassen dialogrobot utökar aktivitetshanteraren och innehåller logiken för att köra dialogrutorna. Dialogrutan och välkomstrobotklassen utökar dialogrutan för att även välkomna en användare när de ansluter till konversationen.

Robotens turhanterare upprepar konversationsflödet som definieras av de tre dialogrutorna. När det tar emot ett meddelande från användaren:

  1. Den kör huvuddialogrutan.
    • Om dialogstacken är tom startar huvuddialogrutan.
    • Annars är dialogrutorna fortfarande i mitten av processen och den aktiva dialogrutan fortsätter.
  2. Det sparar tillstånd, så att alla uppdateringar av användaren, konversationen och dialogtillståndet sparas.

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

Registrera tjänster för roboten

Skapa och registrera tjänster efter behov:

  • Grundläggande tjänster för roboten: ett kort och robotimplementeringen.
  • Tjänster för att hantera tillstånd: lagring, användartillstånd och konversationstillstånd.
  • Rotdialogrutan som roboten ska använda.

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

Kommentar

Minneslagring används endast i testsyfte och är inte avsett för produktionsanvändning. Se till att använda en beständig typ av lagring för en produktionsrobot.

Testa roboten

  1. Om du inte redan har gjort det installerar du Bot Framework-emulatorn.

  2. Kör exemplet lokalt på datorn.

  3. Starta emulatorn, anslut till roboten och skicka meddelanden enligt nedan.

    Exempel på avskrift från en konversation med den komplexa dialogroboten.

Ytterligare resurser

En introduktion till hur du implementerar en dialogruta finns i Implementera sekventiellt konversationsflöde, som använder en enda vattenfallsdialogruta och några frågor för att ställa en rad frågor till användaren.

Dialogrutebiblioteket innehåller grundläggande validering för frågor. Du kan också lägga till anpassad validering. Mer information finns i samla in användarindata med hjälp av en dialogruta.

För att förenkla din dialogkod och återanvända den flera robotar kan du definiera delar av en dialogruta som en separat klass. Mer information finns i återanvändningsdialogrutor.

Nästa steg