Implementieren eines sequenziellen KonversationsflussesImplement sequential conversation flow

gilt für: SDK v4APPLIES TO: SDK v4

Das Sammeln von Informationen durch das Stellen von Fragen ist eine der Hauptvorgehensweisen, mit denen ein Bot mit Benutzern interagiert.Gathering information by posing questions is one of the main ways a bot interacts with users. Die Dialogbibliothek bietet nützliche integrierte Features wie prompt-Klassen zum einfachen Stellen von Fragen und Überprüfen der Antworten, um sicherzustellen, dass sie einen bestimmten Datentyp aufweisen oder benutzerdefinierte Validierungsregeln erfüllen.The dialogs library provides useful built-in features such as prompt classes that make it easy to ask questions and validate the response to make sure it matches a specific data type or meets custom validation rules.

Mit der Dialogbibliothek können Sie einfache und komplexe Konversationsflüsse verwalten.You can manage simple and complex conversation flows using the dialogs library. In einer einfachen Interaktion wird der Bot über eine feste Sequenz von Schritten ausgeführt, und die Konversation endet.In a simple interaction, the bot runs through a fixed sequence of steps, and the conversation finishes. Ein Dialog ist nützlich, wenn der Bot Informationen vom Benutzer sammeln muss.A dialog is useful when the bot needs to gather information from the user.

In diesem Artikel wird gezeigt, wie Sie einen einfachen Konversationsfluss implementieren, indem Sie Eingabeaufforderungen erstellen und über einen Wasserfalldialog aufrufen.This article shows how to implement simple conversation flow by creating prompts and calling them from a waterfall dialog.

Tipp

Beispiele dafür, wie Sie Ihre eigenen Eingabeaufforderungen schreiben können, ohne die Dialogbibliothek zu verwenden, finden Sie im Artikel Erstellen eigener Eingabeaufforderungen zum Erfassen von Benutzereingaben.For examples of how to write your own prompts without using the dialogs library, see the Create your own prompts to gather user input article.

VoraussetzungenPrerequisites

Informationen zu diesem BeispielAbout this sample

Das Beispiel für Eingabeaufforderungen mit mehreren Durchklicken verwendet einen Wasserfalldialog, einige Eingabeaufforderungen und einen Komponentendialog, um eine einfache Interaktion zu erstellen, die dem Benutzer eine Reihe von Fragen stellt.The multi-turn prompts sample uses a waterfall dialog, a few prompts, and a component dialog to create a simple interaction that asks the user a series of questions. Der Code durchläuft die folgenden Schritte in Form eines Dialogs:The code uses a dialog to cycle through these steps:

SchritteSteps Art der EingabeaufforderungPrompt type
Transportmittel des Benutzers erfragenAsk the user for their mode of transportation AuswahleingabeaufforderungChoice prompt
Name des Benutzers erfragenAsk the user for their name TexteingabeaufforderungText prompt
Benutzer fragen, ob er sein Alter angeben möchteAsk the user if they want to provide their age BestätigungseingabeaufforderungConfirm prompt
Wenn sie mit Ja geantwortet haben, fragen Sie nach ihrem Alter.If they answered yes, ask for their age Zahlenaufforderung mit Überprüfung, dass nur Altersklassen akzeptiert werden, die größer als 0 und kleiner als 150 sindNumber prompt, with validation to only accept ages greater than 0 and less than 150
Wenn Microsoft Teams nicht verwendet wird, nach Profilbild fragenIf they're not using Microsoft Teams, ask them for a profile picture Eingabeaufforderung für Anlagen mit Überprüfung zum Zulassen einer fehlenden AnlageAttachment prompt, with validation to allow a missing attachment
Fragen Sie, ob die gesammelten Informationen "OK" sind.Ask if the collected information is "ok" Erneute BestätigungseingabeaufforderungReuse Confirm prompt

Falls ja, werden die erfassten Informationen angezeigt. Falls nicht, wird dem Benutzer mitgeteilt, dass seine Informationen nicht gespeichert werden.Finally, if they answered yes, display the collected information; otherwise, tell the user that their information will not be kept.

Erstellen des HauptdialogsCreate the main dialog

Installieren Sie das NuGet-Paket Microsoft.Bot.Builder.Dialogs, um Dialoge verwenden zu können.To use dialogs, install the Microsoft.Bot.Builder.Dialogs NuGet package.

Der Bot interagiert mit dem Benutzer über UserProfileDialog.The bot interacts with the user via UserProfileDialog. Beim Erstellen der -Klasse des DialogBot Bots UserProfileDialog wird als Hauptdialog festgelegt.When creating the bot's DialogBot class, the UserProfileDialog is set as its main dialog. Der Bot verwendet dann eine Hilfsmethode vom Typ Run, um auf den Dialog zuzugreifen.The bot then uses a Run helper method to access the dialog.

Dialogfeld "C#-Benutzerprofil"

Dialogs\UserProfileDialog.csDialogs\UserProfileDialog.cs

Erstellen Sie zunächst die UserProfileDialog , die von der -Klasse ComponentDialog ableitungt und 7 Schritte hat.Begin by creating the UserProfileDialog that derives from the ComponentDialog class, and has 7 steps.

Erstellen Sie im Konstruktor UserProfileDialog die Wasserfallschritte, die Eingabeaufforderungen und den Wasserfalldialog, und fügen Sie sie dem Dialogsatz hinzu.In the UserProfileDialog constructor, create the waterfall steps, prompts and the waterfall dialog, and add them to the dialog set. Die Eingabeaufforderungen müssen sich in dem Dialogsatz befinden, in dem sie verwendet werden.The prompts need to be in the same dialog set in which they are used.

public UserProfileDialog(UserState userState)
    : base(nameof(UserProfileDialog))
{
    _userProfileAccessor = userState.CreateProperty<UserProfile>("UserProfile");

    // This array defines how the Waterfall will execute.
    var waterfallSteps = new WaterfallStep[]
    {
        TransportStepAsync,
        NameStepAsync,
        NameConfirmStepAsync,
        AgeStepAsync,
        PictureStepAsync,
        ConfirmStepAsync,
        SummaryStepAsync,
    };

    // Add named dialogs to the DialogSet. These names are saved in the dialog state.
    AddDialog(new WaterfallDialog(nameof(WaterfallDialog), waterfallSteps));
    AddDialog(new TextPrompt(nameof(TextPrompt)));
    AddDialog(new NumberPrompt<int>(nameof(NumberPrompt<int>), AgePromptValidatorAsync));
    AddDialog(new ChoicePrompt(nameof(ChoicePrompt)));
    AddDialog(new ConfirmPrompt(nameof(ConfirmPrompt)));
    AddDialog(new AttachmentPrompt(nameof(AttachmentPrompt), PicturePromptValidatorAsync));

    // The initial child Dialog to run.
    InitialDialogId = nameof(WaterfallDialog);
}

Fügen Sie als Nächstes die Schritte hinzu, mit denen das Dialogfeld zur Eingabeaufforderung verwendet wird.Next, add the steps that the dialog uses to prompt for input. Rufen Sie in einem Schritt Ihres Dialogs eine Eingabeaufforderung auf, um sie zu verwenden, und rufen Sie im nächsten Schritt mithilfe von stepContext.Result das Ergebnis der Eingabeaufforderung ab.To use a prompt, call it from a step in your dialog and retrieve the prompt result in the following step using stepContext.Result. Im Hintergrund sind Eingabeaufforderungen ein aus zwei Schritten bestehender Dialog.Behind the scenes, prompts are a two-step dialog. Zuerst fordert die Eingabeaufforderung zur Eingabe auf.First, the prompt asks for input. Anschließend wird der gültige Wert zurückgegeben oder von Anfang an mit einem rerompt-Wert gestartet, bis er eine gültige Eingabe empfängt.Then it returns the valid value, or starts over from the beginning with a reprompt until it receives a valid input.

Von einem Wasserfallschritt sollte immer ein Dialog-Turn-Ergebnis (DialogTurnResult) zurückgegeben werden, das nicht NULL ist.You should always return a non-null DialogTurnResult from a waterfall step. Wenn sie dies nicht möchten, funktioniert Ihr Dialog möglicherweise nicht wie entworfen.If you don't, your dialog may not work as designed. Unten ist die Implementierung für NameStepAsync im Wasserfalldialog dargestellt.Shown below is the implementation for NameStepAsync in the waterfall dialog.

private static async Task<DialogTurnResult> NameStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    stepContext.Values["transport"] = ((FoundChoice)stepContext.Result).Value;

    return await stepContext.PromptAsync(nameof(TextPrompt), new PromptOptions { Prompt = MessageFactory.Text("Please enter your name.") }, cancellationToken);
}

Geben Sie in eine Eingabeaufforderung für wiederholungsversuche an, wenn die Benutzereingabe nicht überprüft werden kann, entweder weil sie in einem Format vor liegt, das von der Eingabeaufforderung nicht analysiert werden kann, oder wenn bei der Eingabe ein Validierungskriterium AgeStepAsync fehlschlägt.In AgeStepAsync, specify a retry prompt for when the user's input fails to validate, either because it's in a format that the prompt can't parse, or the input fails a validation criteria. Ohne Angabe einer erneuten Eingabeaufforderung verwendet die Eingabeaufforderung den Text der ersten Eingabeaufforderung, um den Benutzer erneut zu einer Eingabe aufzufordern.In this case, if no retry prompt was provided, the prompt will use the initial prompt text to re-prompt the user for input.

private async Task<DialogTurnResult> AgeStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    if ((bool)stepContext.Result)
    {
        // User said "yes" so we will be prompting for the age.
        // WaterfallStep always finishes with the end of the Waterfall or with another dialog; here it is a Prompt Dialog.
        var promptOptions = new PromptOptions
        {
            Prompt = MessageFactory.Text("Please enter your age."),
            RetryPrompt = MessageFactory.Text("The value entered must be greater than 0 and less than 150."),
        };

        return await stepContext.PromptAsync(nameof(NumberPrompt<int>), promptOptions, cancellationToken);
    }
    else
    {
        // User said "no" so we will skip the next step. Give -1 as the age.
        return await stepContext.NextAsync(-1, cancellationToken);
    }
}

UserProfile.csUserProfile.cs

Transportmittel, Name und Alter des Benutzers werden in einer Instanz der Klasse UserProfile gespeichert.The user's mode of transportation, name, and age are saved in an instance of the UserProfile class.

public class UserProfile
{
    public string Transport { get; set; }

    public string Name { get; set; }

    public int Age { get; set; }

    public Attachment Picture { get; set; }
}

Dialogs\UserProfileDialog.csDialogs\UserProfileDialog.cs

Überprüfen Sie im letzten Schritt die , die vom Dialog zurückgegeben stepContext.Result wurde, der im vorherigen Wasserfallschritt aufgerufen wurde.In the last step, check the stepContext.Result returned by the dialog called in the previous waterfall step. Wenn der Rückgabewert true ist, ruft der Benutzerprofil-Accessor das Benutzerprofil ab und aktualisiert es.If the return value is true, the user profile accessor gets and updates the user profile. Um das Benutzerprofil zu erhalten, rufen Sie auf, und legen Sie dann die Werte GetAsync der Eigenschaften , und userProfile.Transport userProfile.Name userProfile.Age userProfile.Picture fest.To get the user profile, call GetAsync and then set the values of the userProfile.Transport, userProfile.Name, userProfile.Age and userProfile.Picture properties. Fassen Sie abschließend die Informationen für den Benutzer zusammen, bevor Sie EndDialogAsync aufrufen, wodurch der Dialog beendet wird.Finally, summarize the information for the user before calling EndDialogAsync, which ends the dialog. Der beendete Dialog wird aus dem Dialogstapel entfernt und gibt ein optionales Ergebnis an das übergeordnete Element des Dialogs zurück.Ending the dialog pops it off the dialog stack and returns an optional result to the dialog's parent. Das übergeordnete Element ist der Dialog oder die Methode, der bzw. die den soeben beendeten Dialog gestartet hat.The parent is the dialog or method that started the dialog that just ended.

private async Task<DialogTurnResult> SummaryStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    if ((bool)stepContext.Result)
    {
        // Get the current profile object from user state.
        var userProfile = await _userProfileAccessor.GetAsync(stepContext.Context, () => new UserProfile(), cancellationToken);

        userProfile.Transport = (string)stepContext.Values["transport"];
        userProfile.Name = (string)stepContext.Values["name"];
        userProfile.Age = (int)stepContext.Values["age"];
        userProfile.Picture = (Attachment)stepContext.Values["picture"];

        var msg = $"I have your mode of transport as {userProfile.Transport} and your name as {userProfile.Name}";

        if (userProfile.Age != -1)
        {
            msg += $" and your age as {userProfile.Age}";
        }

        msg += ".";

        await stepContext.Context.SendActivityAsync(MessageFactory.Text(msg), cancellationToken);

        if (userProfile.Picture != null)
        {
            try
            {
                await stepContext.Context.SendActivityAsync(MessageFactory.Attachment(userProfile.Picture, "This is your profile picture."), cancellationToken);
            }
            catch
            {
                await stepContext.Context.SendActivityAsync(MessageFactory.Text("A profile picture was saved but could not be displayed here."), cancellationToken);
            }
        }
    }
    else
    {
        await stepContext.Context.SendActivityAsync(MessageFactory.Text("Thanks. Your profile will not be kept."), cancellationToken);
    }

    // WaterfallStep always finishes with the end of the Waterfall or with another dialog; here it is the end.
    return await stepContext.EndDialogAsync(cancellationToken: cancellationToken);
}

Ausführen des DialogsRun the dialog

Bots\DialogBot.csBots\DialogBot.cs

Der Handler OnMessageActivityAsync verwendet die RunAsync-Methode, um den Dialog zu starten oder fortzusetzen.The OnMessageActivityAsync handler uses the RunAsync method to start or continue the dialog. OnTurnAsync verwendet die Zustandsverwaltungsobjekte des Bots, um zustandsänderungen im Speicher zu speichern.OnTurnAsync uses the bot's state management objects to persist any state changes to storage. Die ActivityHandler.OnTurnAsync-Methode ruft die verschiedenen Aktivitätshandlermethoden auf – beispielsweise OnMessageActivityAsync.The ActivityHandler.OnTurnAsync method calls the various activity handler methods, such as OnMessageActivityAsync. Auf diese Weise wird der Zustand gespeichert, nachdem der Nachrichtenhandler abgeschlossen wurde, aber bevor der Turn selbst abgeschlossen ist.In this way, the state is saved after the message handler completes but before the turn itself completes.

public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default)
{
    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);
}

Registrieren von Diensten für den BotRegister services for the bot

Dieser Bot verwendet die folgenden Dienste:This bot uses the following services:

  • Grundlegende Dienste für einen Bot: Anmeldeinformationsanbieter, Adapter und BotimplementierungBasic services for a bot: a credential provider, an adapter, and the bot implementation.
  • Dienste für die Zustandsverwaltung: Speicher, Benutzerzustand und KonversationszustandServices for managing state: storage, user state, and conversation state.
  • Der vom Bot verwendete DialogThe dialog the bot will use.

Startup.csStartup.cs

Registrieren Sie Dienste für den Bot in Startup .Register services for the bot in Startup. Diese Dienste sind für andere Teile des Codes per Abhängigkeitsinjektion verfügbar.These services are available to other parts of the code through dependency injection.

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

    // Create the Bot Framework 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>();

    // Create the Conversation state. (Used by the Dialog system itself.)
    services.AddSingleton<ConversationState>();

    // The Dialog that will be run by the bot.
    services.AddSingleton<UserProfileDialog>();

    // Create the bot as a transient. In this case the ASP Controller is expecting an IBot.
    services.AddTransient<IBot, DialogBot<UserProfileDialog>>();
}

Hinweis

Arbeitsspeicher wird nur für Testzwecke genutzt und ist nicht für die Verwendung in der Produktion vorgesehen.Memory storage is used for testing purposes only and is not intended for production use. Verwenden Sie für einen Produktionsbot unbedingt einen permanenten Speicher.Be sure to use a persistent type of storage for a production bot.

So testen Sie den BotTo test the bot

  1. Wenn Sie dies noch nicht getan haben, installieren Sie die Bot Framework Emulator.If you haven't done so already, install the Bot Framework Emulator.
  2. Führen Sie das Beispiel lokal auf Ihrem Computer aus.Run the sample locally on your machine.
  3. Starten Sie den Emulator, stellen Sie eine Verbindung mit Ihrem Bot her, und senden Sie Nachrichten wie unten dargestellt.Start the Emulator, connect to your bot, and send messages as shown below.

Beispielausführung des Dialogs mit mehreren Eingabeaufforderungen

Zusätzliche InformationenAdditional information

Informationen zu Dialogen und zum BotzustandAbout dialog and bot state

In diesem Bot werden zwei Zustandseigenschafts-Accessoren definiert:In this bot, two state property accessors are defined:

  • Ein Accessor wurde im Konversationszustand für die Dialogzustandseigenschaft erstellt.One created within conversation state for the dialog state property. Der Dialogzustand verfolgt nach, wo sich der Benutzer innerhalb der Dialoge eines Dialogsets befindet, und wird vom Dialogkontext aktualisiert, z. B. wenn die Dialogmethoden "Dialog starten" oder "Fortfahren" aufgerufen werden.The dialog state tracks where the user is within the dialogs of a dialog set, and it's updated by the dialog context, such as when the begin dialog or continue dialog methods are called.
  • Ein Accessor wurde im Benutzerzustand für die Benutzerprofileigenschaft erstellt.One created within user state for the user profile property. Der Bot verwendet diese Zum Nachverfolgen von Informationen über den Benutzer, und Sie müssen diesen Zustand explizit im Dialogcode verwalten.The bot uses this to track information it has about the user, and you must explicitly manage this state in the dialog code.

Die get- und set-Methoden eines Zustandseigenschaftenaccessors rufen den Wert der Eigenschaft ab und legen ihn im Cache des Zustandsverwaltungsobjekts fest.The get and set methods of a state property accessor get and set the value of the property in the state management object's cache. Der Cache wird aufgefüllt, wenn der Wert einer Zustandseigenschaft erstmals in einem Turn angefordert wird, er muss jedoch explizit gespeichert werden.The cache is populated the first time the value of a state property is requested in a turn, but it must be persisted explicitly. Um Änderungen an beiden Zustandseigenschaften dauerhaft zu speichern, wird ein Aufruf der Save Changes-Methode des entsprechenden Zustandsverwaltungsobjekts ausgeführt.In order to persist changes to both of these state properties, a call to the save changes method, of the corresponding state management object, is performed.

In diesem Beispiel wird der Zustand des Benutzerprofils innerhalb des Dialogs aktualisiert.This sample updates the user profile state from within the dialog. Diese Vorgehensweise kann für einen einfachen Bot funktionieren, funktioniert aber nicht, wenn Sie einen Dialog botübergreifend wiederverwenden möchten.This practice can work for a simple bot, but it won't work if you want to reuse a dialog across bots.

Zum Trennen der Dialogschritte und des Botzustands stehen verschiedene Optionen zur Verfügung.There are various options for keeping dialog steps and bot state separate. Nachdem der Dialog vollständige Informationen erfasst hat, können Sie beispielsweise wie folgt vorgehen:For example, once your dialog gathers complete information, you can:

  • Verwenden Sie die Enddialogmethode, um die gesammelten Daten als Rückgabewert an den übergeordneten Kontext zurück zu geben.Use the end dialog method to provide the collected data as return value back to the parent context. Dies kann der Turn-Handler des Bots oder ein früherer aktiver Dialog im Dialogstapel sein, und die Eingabeaufforderungsklassen werden so entworfen.This can be the bot's turn handler or an earlier active dialog on the dialog stack and it's how the prompt classes are designed.
  • Generieren Sie eine Anforderung an einen geeigneten Dienst.Generate a request to an appropriate service. Dies kann gut funktionieren, wenn Ihr Bot als Front-End für einen umfangreicheren Dienst fungiert.This might work well if your bot acts as a front end to a larger service.

Definition einer Eingabeaufforderungen-Validierungssteuerelement-MethodeDefinition of a prompt validator method

UserProfileDialog.csUserProfileDialog.cs

Im Folgenden finden Sie ein Validierungscodebeispiel für die AgePromptValidatorAsync Methodendefinition.Below is a validator code example for the AgePromptValidatorAsync method definition. promptContext.Recognized.Value enthält den analysierten Wert, bei dem es sich hier um eine ganze Zahl für die Zahleneingabeaufforderung handelt.promptContext.Recognized.Value contains the parsed value, which is an integer here for the number prompt. promptContext.Recognized.Succeeded gibt an, ob die Eingabeaufforderung die Eingabe des Benutzers analysieren konnte.promptContext.Recognized.Succeeded indicates whether the prompt was able to parse the user's input or not. Das Validierungssteuerelement sollte „false“ zurückgeben, um anzugeben, dass der Wert nicht akzeptiert wurde, und der Eingabeaufforderungsdialog sollte den Benutzer erneut auffordern. Andernfalls wird „true“ zurückgegeben, um die Eingabe zu akzeptieren und zum Eingabeaufforderungsdialog zurückzukehren.The validator should return false to indicate that the value was not accepted and the prompt dialog should reprompt the user; otherwise, return true to accept the input and return from the prompt dialog. Beachten Sie, dass Sie den Wert im Validierungssteuerelement gemäß Ihrem Szenario ändern können.Note that you can change the value in the validator per your scenario.

private static Task<bool> AgePromptValidatorAsync(PromptValidatorContext<int> promptContext, CancellationToken cancellationToken)
{
    // This condition is our validation rule. You can also change the value at this point.
    return Task.FromResult(promptContext.Recognized.Succeeded && promptContext.Recognized.Value > 0 && promptContext.Recognized.Value < 150);
}

Nächste SchritteNext steps