Créer des flux de conversation avancés à l’aide de branches et de boucles

S'APPLIQUE À : SDK v4

Vous pouvez créer des flux de conversation complexes avec la bibliothèque de dialogues. Cet article explique comment gérer des conversations complexes permettant de créer une branche et une boucle, et comment passer des arguments entre les différentes parties du dialogue.

Remarque

Les kits de développement logiciel (SDK) JavaScript, C# et Python bot Framework continueront d'être pris en charge. Toutefois, le kit de développement logiciel (SDK) Java est mis hors service avec une prise en charge finale à long terme se terminant en novembre 2023. Seuls les correctifs de sécurité et de bogues critiques au sein de ce référentiel seront entrepris.

Les bots existants créés avec le kit de développement logiciel (SDK) Java continueront de fonctionner.

Pour la nouvelle génération de bots, envisagez d'utiliser Power Virtual Agents et découvrez comment choisir la solution de chatbot appropriée.

Pour plus d'informations, consultez L'avenir de la construction de bots.

Prérequis

À propos de cet exemple

Dans cet exemple, un bot inscrit des utilisateurs qui sont ensuite invités à évaluer jusqu’à deux entreprises parmi celles figurant dans une liste. Le bot utilise trois dialogues de composant pour gérer le flux de conversation. Chaque dialogue de composant comprend un dialogue en cascade, ainsi que les invites nécessaires pour collecter les entrées d’utilisateur. Ces dialogues sont décrits de manière plus détaillée dans les sections suivantes. Le bot utilise l’état des conversations pour gérer ses dialogues et utilise l’état des utilisateurs pour enregistrer les informations sur les utilisateurs et les entreprises qu’ils souhaitent évaluer.

Le bot est dérivé du gestionnaire d’activités. Comme la plupart des exemples de bots, il salue l’utilisateur, utilise des dialogues pour gérer les messages de l’utilisateur, et enregistre l’état de l’utilisateur et de la conversation avant la fin du tour.

Pour utiliser les dialogues, installez le package NuGet Microsoft.Bot.Builder.Dialogs.

Class diagram for C# sample.

Définir le profil utilisateur

Le profil utilisateur contient les informations collectées par les dialogues, le nom de l’utilisateur, son âge, ainsi que les entreprises qu’il souhaite évaluer.

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

Créer les dialogues

Ce bot comprend trois dialogues :

  • Le dialogue principal démarre le processus global, puis récapitule les informations collectées.
  • Le dialogue de niveau supérieur collecte les informations utilisateur et inclut la logique de branchement, en fonction de l’âge de l’utilisateur.
  • Le dialogue de sélection et d’évaluation permet à l’utilisateur de sélectionner de manière itérative les entreprises à évaluer. Pour cela, il utilise une logique de boucle.

Le dialogue principal

Le dialogue principal implique deux étapes :

  1. Démarrez le dialogue de niveau supérieur.
  2. Récupérez et résumez le profil utilisateur collecté par le dialogue de niveau supérieur, enregistrez ces informations dans l’état de l’utilisateur, puis signalez la fin du dialogue principal.

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

Dialogue de niveau supérieur

Le dialogue de niveau supérieur implique quatre étapes :

  1. Demander le nom de l’utilisateur.
  2. Demander l’âge de l’utilisateur.
  3. Démarrez le dialogue de sélection et d’évaluation, ou passez à l’étape suivante, en fonction de l’âge de l’utilisateur.
  4. Enfin, remercier l’utilisateur pour sa participation et retourner les informations collectées.

La première étape crée un profil utilisateur vide dans le cadre de l’état du dialogue. Le dialogue commence par un profil vide et ajoute des informations au profil à mesure qu’il progresse. Lorsqu’il se termine, la dernière étape retourne les informations collectées.

Dans la troisième étape (début de la sélection), le flux de conversation crée une branche, en fonction de l’âge de l’utilisateur.

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

Dialogue de sélection de l’évaluation

Le dialogue de sélection de l’évaluation comporte deux étapes :

  1. Demandez à l’utilisateur de choisir une entreprise à évaluer ou d’utiliser done pour terminer.
    • Si le dialogue a été démarré avec des informations initiales, ces informations seront disponibles via la propriété options du contexte de l’étape en cascade. Le dialogue de sélection et d’évaluation peut redémarrer tout seul, ce qui lui permet d’autoriser l’utilisateur à sélectionner plusieurs entreprises à évaluer.
    • Si l’utilisateur a déjà sélectionné une entreprise à évaluer, celle-ci est supprimée des choix disponibles.
    • Le choix done est ajouté pour permettre à l’utilisateur de quitter la boucle plus tôt.
  2. Répéter ce dialogue ou en sortir selon le cas.
    • Si l’utilisateur a choisi une entreprise à évaluer, ajoutez-la à sa liste.
    • Si l'utilisateur a choisi deux entreprises ou s'il a choisi de quitter la boucle, terminez le dialogue et renvoyez la liste collectée.
    • Sinon, redémarrez le dialogue, en l’initialisant avec le contenu de sa liste.

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

Exécuter les dialogues

La classe dialog bot étend le gestionnaire d’activités et contient la logique d’exécution des dialogues. La classe dialog and welcome bot étend le bot de dialogue pour qu’il salue également l’utilisateur lorsqu’il rejoint la conversation.

Le gestionnaire de tour du bot répète le flux de conversation défini par les trois dialogues. Quand il reçoit un message de l’utilisateur :

  1. Il exécute le dialogue principal.
    • Si la pile de dialogues est vide, le dialogue principal sera démarré.
    • Sinon, les dialogues seront toujours exécutés, ce qui aura pour effet de maintenir l’exécution du dialogue actif.
  2. Il enregistre l’état afin de rendre persistante toute mise à jour de l’état de l’utilisateur, de la conversation et du dialogue.

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

Inscrire les services pour le bot

Créez et inscrivez des services en fonction des besoins :

  • Services de base pour le bot : un adaptateur et l’implémentation du bot.
  • Services pour gérer l’état : le stockage, l’état utilisateur et l’état de conversation.
  • Le dialogue racine que le bot va utiliser.

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

Remarque

Le stockage mémoire est utilisé uniquement à des fins de test et n'est pas destiné à une utilisation en production. Veillez à utiliser un type de stockage permanent pour un bot de production.

Tester le bot

  1. Si ce n'est déjà fait, installez Bot Framework Emulator.

  2. Exécutez l’exemple en local sur votre machine.

  3. Démarrez l’émulateur, connectez-vous à votre bot et envoyez des messages, comme indiqué ci-dessous.

    Example transcript from a conversation with the complex dialog bot.

Ressources supplémentaires

Pour une présentation de l'implémentation d'un dialogue, consultez l'implémentation d'un flux de conversation séquentiel, qui utilise un seul dialogue en cascade et quelques invites pour poser une série de questions à l'utilisateur.

La bibliothèque de dialogues inclut la validation de base des invites. Vous pouvez également ajouter une validation personnalisée. Pour plus d’informations, consultez Collecter les entrées utilisateur avec une invite de dialogue.

Pour simplifier votre code de dialogue et le réutiliser dans plusieurs bots, vous pouvez définir chaque partie d’un ensemble de dialogues comme une classe distincte. Pour plus d’informations, consultez Réutiliser des dialogues.

Étapes suivantes