Erstellen eigener Eingabeaufforderungen zum Erfassen von Benutzereingaben

GILT FÜR: SDK v4

Eine Konversation zwischen einem Bot und einem Benutzer umfasst in der Regel die Anforderung von Benutzerinformationen, die Analyse der Benutzerantwort und eine entsprechende Reaktion auf die Antwort. Ihr Bot sollte den Kontext einer Konversation nachverfolgen, damit er das Verhalten verwalten und sich Antworten auf vorherige Fragen merken kann. Der Zustand eines Bots ist eine Information, die nachverfolgt wird, um auf eingehende Nachrichten angemessen reagieren zu können.

Tipp

Die Dialogbibliothek enthält integrierte Eingabeaufforderungen mit weiterer Funktionalität, die Benutzer verwenden können. Beispiele für diese Eingabeaufforderungen finden Sie im Artikel Implementieren eines sequenziellen Konversationsflusses.

Hinweis

Die JavaScript-, C#- und Python-SDKs für Bot Framework werden weiterhin unterstützt, das Java-SDK wird jedoch eingestellt und der langfristige Support endet im November 2023.

Bestehende Bots, die mit dem Java SDK erstellt wurden, werden weiterhin funktionieren.

Wenn Sie einen neuen Bot erstellen möchten, sollten Sie den Einsatz von Power Virtual Agents in Betracht ziehen und sich über die Auswahl der richtigen Chatbot-Lösung informieren.

Weitere Informationen finden Sie unter Die Zukunft des Bot-Design.

Voraussetzungen

Informationen zum Beispielcode

Der Beispielbot stellt dem Benutzer einige Fragen, überprüft einige Antworten und speichert die Eingabe. Das folgende Diagramm zeigt die Beziehung zwischen dem Bot, dem Benutzerprofil und den Konversationsflussklassen.

Klassendiagramm für das C#-Beispiel.

  • Eine UserProfile-Klasse für die Benutzerinformationen, die vom Bot gesammelt werden.
  • Eine ConversationFlow-Klasse zum Kontrollieren des Konversationszustands, während Benutzerinformationen erfasst werden.
  • Eine innere ConversationFlow.Question-Enumeration, um zu verfolgen, wo Sie sich in der Konversation befinden.

Über den Benutzerzustand werden der Name, das Alter und das gewählte Datum des Benutzers nachverfolgt, und mit dem Konversationszustand wird nachverfolgt, was Sie den Benutzer zuletzt gefragt haben. Da Sie nicht planen, diesen Bot bereitzustellen, konfigurieren Sie für den Benutzer- und Konversationszustand die Nutzung des Arbeitsspeichers.

Sie verwenden den Nachrichten-Turn-Handler des Bots sowie die Eigenschaften für den Benutzer- und Konversationszustand, um den Konversationsfluss und die Erfassung der Eingabe zu verwalten. In Ihrem Bot zeichnen Sie die Informationen der Zustandseigenschaft auf, die bei jedem Durchlauf des Nachrichten-Turn-Handlers empfangen werden.

Erstellen von Konversations- und Benutzerobjekten

Erstellen Sie beim Start die Benutzer- und Konversationszustandsobjekte, und verwenden Sie sie über die Abhängigkeiteneinschleusung im Botkonstruktor.

Startup.cs

// 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.
services.AddSingleton<UserState>();

// Create the Conversation state.
services.AddSingleton<ConversationState>();

Bots/CustomPromptBot.cs

private readonly BotState _userState;
private readonly BotState _conversationState;

public CustomPromptBot(ConversationState conversationState, UserState userState)
{
    _conversationState = conversationState;
    _userState = userState;
}

Erstellen von Eigenschaftenaccessoren

Erstellen Sie Eigenschaftenaccessoren für die Eigenschaften des Benutzerprofils und des Konversationsflusses, und rufen Sie dann GetAsync auf, um den Eigenschaftswert aus dem Zustand abzurufen.

Bots/CustomPromptBot.cs

protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
    var conversationStateAccessors = _conversationState.CreateProperty<ConversationFlow>(nameof(ConversationFlow));
    var flow = await conversationStateAccessors.GetAsync(turnContext, () => new ConversationFlow(), cancellationToken);

    var userStateAccessors = _userState.CreateProperty<UserProfile>(nameof(UserProfile));
    var profile = await userStateAccessors.GetAsync(turnContext, () => new UserProfile(), cancellationToken);

Rufen Sie vor dem Ende des Turns SaveChangesAsync auf, um Zustandsänderungen in den Speicher zu schreiben.

    await _conversationState.SaveChangesAsync(turnContext, false, cancellationToken);
    await _userState.SaveChangesAsync(turnContext, false, cancellationToken);
}

Nachrichten-Turn-Handler

Beim Verarbeiten von Nachrichtenaktivitäten verwendet der Nachrichtenhandler eine Hilfsmethode, um die Konversation zu verwalten und den Benutzer zur Eingabe aufzufordern. Die Hilfsmethode wird im folgenden Abschnitt beschrieben.

Bots/CustomPromptBot.cs

protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
    var conversationStateAccessors = _conversationState.CreateProperty<ConversationFlow>(nameof(ConversationFlow));
    var flow = await conversationStateAccessors.GetAsync(turnContext, () => new ConversationFlow(), cancellationToken);

    var userStateAccessors = _userState.CreateProperty<UserProfile>(nameof(UserProfile));
    var profile = await userStateAccessors.GetAsync(turnContext, () => new UserProfile(), cancellationToken);

    await FillOutUserProfileAsync(flow, profile, turnContext, cancellationToken);

    // Save changes.
    await _conversationState.SaveChangesAsync(turnContext, false, cancellationToken);
    await _userState.SaveChangesAsync(turnContext, false, cancellationToken);
}

Ausfüllen des Benutzerprofils

Der Bot fordert den Benutzer zur Eingabe von Informationen auf, basierend auf der Frage, die der Bot ggf. im vorherigen Turn gestellt hat. Die Eingabe wird mithilfe einer Validierungsmethode analysiert.

Jede Validierungsmethode folgt einem ähnlichen Design:

  • Der Rückgabewert gibt an, ob die Eingabe eine gültige Antwort auf die Frage ist.
  • Wenn die Validierung erfolgreich war, wird ein analysierter und normalisierter Wert erzeugt, der gespeichert werden kann.
  • Falls für die Validierung ein Fehler auftritt, wird eine Nachricht erzeugt, über die der Bot erneut nach den Informationen fragen kann.

Die Validierungsmethoden werden im folgenden Abschnitt beschrieben.

Bots/CustomPromptBot.cs

{
    var input = turnContext.Activity.Text?.Trim();
    string message;

    switch (flow.LastQuestionAsked)
    {
        case ConversationFlow.Question.None:
            await turnContext.SendActivityAsync("Let's get started. What is your name?", null, null, cancellationToken);
            flow.LastQuestionAsked = ConversationFlow.Question.Name;
            break;
        case ConversationFlow.Question.Name:
            if (ValidateName(input, out var name, out message))
            {
                profile.Name = name;
                await turnContext.SendActivityAsync($"Hi {profile.Name}.", null, null, cancellationToken);
                await turnContext.SendActivityAsync("How old are you?", null, null, cancellationToken);
                flow.LastQuestionAsked = ConversationFlow.Question.Age;
                break;
            }
            else
            {
                await turnContext.SendActivityAsync(message ?? "I'm sorry, I didn't understand that.", null, null, cancellationToken);
                break;
            }

        case ConversationFlow.Question.Age:
            if (ValidateAge(input, out var age, out message))
            {
                profile.Age = age;
                await turnContext.SendActivityAsync($"I have your age as {profile.Age}.", null, null, cancellationToken);
                await turnContext.SendActivityAsync("When is your flight?", null, null, cancellationToken);
                flow.LastQuestionAsked = ConversationFlow.Question.Date;
                break;
            }
            else
            {
                await turnContext.SendActivityAsync(message ?? "I'm sorry, I didn't understand that.", null, null, cancellationToken);
                break;
            }

        case ConversationFlow.Question.Date:
            if (ValidateDate(input, out var date, out message))
            {
                profile.Date = date;
                await turnContext.SendActivityAsync($"Your cab ride to the airport is scheduled for {profile.Date}.");
                await turnContext.SendActivityAsync($"Thanks for completing the booking {profile.Name}.");
                await turnContext.SendActivityAsync($"Type anything to run the bot again.");
                flow.LastQuestionAsked = ConversationFlow.Question.None;
                profile = new UserProfile();
                break;
            }
            else
            {
                await turnContext.SendActivityAsync(message ?? "I'm sorry, I didn't understand that.", null, null, cancellationToken);
                break;
            }
    }
}

Analysieren und Überprüfen der Eingabe

Der Bot verwendet die folgenden Kriterien, um die Eingabe zu überprüfen.

  • Der Name darf keine leere Zeichenfolge sein. Er wird durch Entfernen der Leerstellen normalisiert.
  • Das Alter (age) muss zwischen 18 und 120 liegen. Es wird durch Zurückgeben einer ganzen Zahl normalisiert.
  • Beim Datum (date) muss es sich um ein Datum bzw. einen Zeitpunkt handeln, der mindestens einen Stunde in der Zukunft liegt. Es wird normalisiert, indem nur der Datumsteil der analysierten Eingabe zurückgegeben wird.

Hinweis

Für die Alters- und Datumseingabe verwendet das Beispiel die Microsoft/Erkennungsmodul-Text-Bibliotheken, um die erste Analyse durchzuführen. Dies ist nur eine Möglichkeit, die Eingabe zu analysieren. Weitere Informationen zu diesen Bibliotheken finden Sie in der INFODATEI des Projekts.

Bots/CustomPromptBot.cs

private static bool ValidateName(string input, out string name, out string message)
{
    name = null;
    message = null;

    if (string.IsNullOrWhiteSpace(input))
    {
        message = "Please enter a name that contains at least one character.";
    }
    else
    {
        name = input.Trim();
    }

    return message is null;
}

private static bool ValidateAge(string input, out int age, out string message)
{
    age = 0;
    message = null;

    // Try to recognize the input as a number. This works for responses such as "twelve" as well as "12".
    try
    {
        // Attempt to convert the Recognizer result to an integer. This works for "a dozen", "twelve", "12", and so on.
        // The recognizer returns a list of potential recognition results, if any.

        var results = NumberRecognizer.RecognizeNumber(input, Culture.English);

        foreach (var result in results)
        {
            // The result resolution is a dictionary, where the "value" entry contains the processed string.
            if (result.Resolution.TryGetValue("value", out var value))
            {
                age = Convert.ToInt32(value);
                if (age >= 18 && age <= 120)
                {
                    return true;
                }
            }
        }

        message = "Please enter an age between 18 and 120.";
    }
    catch
    {
        message = "I'm sorry, I could not interpret that as an age. Please enter an age between 18 and 120.";
    }

    return message is null;
}

private static bool ValidateDate(string input, out string date, out string message)
{
    date = null;
    message = null;

    // Try to recognize the input as a date-time. This works for responses such as "11/14/2018", "9pm", "tomorrow", "Sunday at 5pm", and so on.
    // The recognizer returns a list of potential recognition results, if any.
    try
    {
        var results = DateTimeRecognizer.RecognizeDateTime(input, Culture.English);

        // Check whether any of the recognized date-times are appropriate,
        // and if so, return the first appropriate date-time. We're checking for a value at least an hour in the future.
        var earliest = DateTime.Now.AddHours(1.0);

        foreach (var result in results)
        {
            // The result resolution is a dictionary, where the "values" entry contains the processed input.
            var resolutions = result.Resolution["values"] as List<Dictionary<string, string>>;

            foreach (var resolution in resolutions)
            {
                // The processed input contains a "value" entry if it is a date-time value, or "start" and
                // "end" entries if it is a date-time range.
                if (resolution.TryGetValue("value", out var dateString)
                    || resolution.TryGetValue("start", out dateString))
                {
                    if (DateTime.TryParse(dateString, out var candidate)
                        && earliest < candidate)
                    {
                        date = candidate.ToShortDateString();
                        return true;
                    }
                }
            }
        }

        message = "I'm sorry, please enter a date at least an hour out.";
    }
    catch
    {
        message = "I'm sorry, I could not interpret that as an appropriate date. Please enter a date at least an hour out.";
    }

    return false;
}

Lokales Testen des Bots

Laden Sie den Bot Framework Emulator herunter, und installieren Sie ihn, um den Bot lokal zu testen.

  1. Führen Sie das Beispiel lokal auf Ihrem Computer aus. Eine Anleitung finden Sie in der README-Datei für das C#-Beispiel, JS-Beispiel bzw. Python-Beispiel.
  2. Testen Sie ihn mit dem Emulator.

Zusätzliche Ressourcen

In der Dialogbibliothek werden Klassen bereitgestellt, mit denen viele Aspekte der Verwaltung von Konversationen automatisiert werden.

Nächster Schritt