RASA: FAQ automatisieren und Informationen sammeln mit Chatbots

Ein Rasa FAQ-Chatbot bringt Ihren First-Level-Support auf ein neues Level!

In diesem Artikel zeigen wir, wie mit Hilfe von Rasa FAQ mit Chatbots automatisiert und zum Ausfüllen von Formularen implementiert werden können. Für das Arbeiten mit Formularen bietet das Rasa Framework mit der FormPolicy eine einfache Möglichkeit, ohne umfangreiches Erstellen von Dialogen benutzerfreundliche Bots anzufertigen.

Mit dem Artikel "Chatbot erstellen mit Rasa" haben wir bereits beschrieben, wie ein einfacher Chatbot mit Rasa erstellt werden kann. Wir haben veranschaulicht, wie Rasa installiert wird und ein erstes Projekt initialisiert. Auch haben wir gezeigt, wie ein einfacher Dialog mit dem Bot geführt werden kann.

Für diesen Use-Case beschreiben wir einen Chatbot, der es ermöglicht, ein Hotelzimmer zu reservieren und grundlegende Fragen zum Hotel beantwortet. Eine beispielhafte Implementierung, auf der unser Artikel und die Erstellung eines Bots aufbauen, finden Sie hier.

Wir haben Rasa 1.8 genutzt. Da zum Zeitpunkt der Erstellung dieses Artikels erst die erste Alpha Version von Rasa 2.0 vorgestellt wurde, gehen wir auf Rasa 2.0 nicht ein. Zunächst beginnen wir damit, dass unser Chatbot Fragen aus einem FAQ beantwortet.

Now, we will start with our chatbot answering questions.

Rasa FAQ Chatbots erstellen: So geht's!

Zu Beginn initialisieren wir in einem leeren Ordner mithilfe der Rasa CLI ein Projekt. Falls Rasa bislang nicht installiert ist und das Aufsetzen eines initialen Projektes noch unbekannt, können die einzelnen Schritte mithilfe unseres vorherigen Tutorials durchgeführt werden.

Nach Initialisierung des Projektes löschen wir die *Intents, Stories und nicht benötigten Konfigurationen der Domain. Anschließend erstellen wir Intents für drei Fragen. Dem automatisierten FAQ-Chatbot können Fragen über den Standort des Hotels, das Aussehen und mögliche Aktivitäten dort gestellt werden.  Diese erstellen wir zunächst innerhalb der NLU (Natural Language Understanding) Daten unter data/nlu.md.

ResponseSelector

Mit dem ResponseSelector verfügt Rasa über eine Funktionalität, die den Umgang mit Smalltalk und FAQs vereinfacht. Diese Funktionalität wird im Folgenden verwendet. Dazu müssen die Fragen innerhalb der NLU-Daten speziell markiert werden, d. h. die Fragen müssen dem Muster ## intent: faq/ask_ folgen<name>. Die Frage nach dem Aussehen des Hotels wird unten als Beispiel gezeigt. Um den ResponseSelector zu verwenden, müssen mindestens zwei Intents erstellt werden.

    
    ## intent: faq/ask_location
    - Wo ist das Hotel? 
    - Wo kann ich euch finden?
    - Das Hotel ist wo?
    - In welcher Stadt ist das Hotel? 
    - Wo befindet sich das Hotel 'Zum sprechenden Bot'?
    

Nach den Intents legen wir nun die Responses an, also die Reaktionen des Bots auf den Intent des Benutzers. Dies erfolgt allerdings nicht wie im Artikel zuvor beschrieben über Responses innerhalb der Domain. Damit die Datei domain.yml nicht zu unübersichtlich und überladen mit Konfigurationen wird, legen wir im Ordner data eine neue Datei responses.md an.

In dieser Datei werden die Antworten auf die zuvor definierten Fragen erzeugt. Antworten werden ähnlich wie Geschichten erstellt, jedoch mit nur einem Wechsel zwischen Benutzer und Chatbot

    
    # Ask location * faq/ask_location - Das Hotel 'Zum sprechenden Bot' befindet sich im Herzen Münchens mit Panoramablick auf die Alpen.
    

Die Vorteile des ResponseSelectors zeigen sich nun bei der Erstellung der Story. Es ist nicht notwendig, mehrere Stories zu erstellen, die jede einzelne Frage behandeln. Innerhalb der Stories unter data/stories.md werden alle FAQs gleich behandelt und es gibt keine Unterscheidung zwischen ihnen. Dies kann vor allem für Chatbots mit vielen verschiedenen FAQs ein großer Vorteil sein.

    
    ## Some questions for faq
    * faq 
        - respond_faq
    

Letztendlich müssen wir den Intent faq und die Aktion zur Beantwortung der Fragen der Domain hinzufügen (Datei: domain.yml). Folglich können wir den Rasa-FAQ-Chatbot mit dem Befehl rasa train trainieren und dann über die rasa shell testen.

FAQ Chatbot dialog rasa shell

Rasa FAQ Chatbot: Ausfüllen eines Formulars durch Dialog

Der FAQ-Chatbot ist nun in der Lage, einfache Fragen zu beantworten. Im Folgenden beschreiben wir, wie Sie den Rasa-Bot in die Lage versetzen, Reservierungen anzunehmen. Dazu bietet Rasa die Möglichkeit, Formulare auszufüllen. Dieser Artikel beschreibt nur einen PoC mit eingeschränkter Funktionalität.

Mit Entity Extraction bietet Rasa die Möglichkeit, komplexe Datentypen in Formulare einzugeben. So ist es möglich, Benutzerdaten, wie z.B. "Morgen Nachmittag um 14:00 Uhr", korrekt zu interpretieren. Weitere Informationen finden Sie in der Rasa-Dokumentation unter https://legacy-docs-v1.rasa.com/nlu/entity-extraction/

Erste Schritte zum Ausfüllen des Rasa-Formulars

Um ein Formular in Rasa auszufüllen, müssen Sie zunächst die requiredFormPolicy unter policies in der config.yml hinzufügen.
Der nächste Schritt ist das Hinzufügen des Formulars, das wir ausfüllen wollen, zur Domain innerhalb der domain.yml-Datei.

    
    forms:  
        - hotel_form
    

Wir haben die erforderliche Richtlinie hinzugefügt und das Formular in die Domäne aufgenommen. Wie bei den zu beantwortenden Fragen erzeugen wir eine Story, die den Prozess des Ausfüllens des Formulars zeigt. Dazu legen wir zunächst den Intent request_room innerhalb der Domain an und definieren unter data/nlu.md Beispielinhalte für das Training.

Hierzu erstellen wir zunächst den Intent request_room innerhalb der Domain und legen unter data/nlu.md Beispielintents für das Training an. Hierbei legen wir zwei unterschiedliche Ausprägungen der Intents an. Der erste Intent enthält lediglich die Information, dass ein Zimmer zu reservieren ist.

    
    ## intent:request_room 
    - Ich möchte ein Zimmer reservieren
    

Eine weitere Möglichkeit ist es, Informationen zu übertragen, die sich bereits in diesem Intent befinden. So können Sie innerhalb dieses Intents sogenannte Entitäten angeben. In diesem Beispiel verwenden wir dazu das Ankunftsdatum. Wichtig ist, dass der Slot und die Entität einen identischen Namen haben, in diesem Beispiel Datum. Slots und Entitäten werden in den weiteren Schritten spezifiziert.

    
    ## intent:request_room  
    - Ist ein Zimmer ab [11/02/2020](date) frei.
    - Ich möchte ein Zimmer für den [10/03/2020](date) buchen.
    

Diese beiden Intents ermöglichen es nun, eines der Felder am Anfang des Formulars zu füllen. Wir nehmen sie auch in die Domain unter domain.yml auf. Beim weiteren Ausfüllen des Formulars fragt der Chatbot den Benutzer nicht, welches Datum er haben möchte, da dieses Datum bereits zu Beginn angegeben wurde.  

Nun legen wir eine Story an, die den optimalen Fall zum Ausfüllen des Forms wiedergibt.

    
    ## Form Happy Path  
    * request_room
        - hotel_form
        - form{"name": "hotel_form"}
        - form{"name": null}
    

Um das Formular in einem Dialog auszufüllen, schreiben wir die Python-Klasse HotelForm in actions.py. Diese Klasse erbt von der Klasse FormAction und implementiert die vier Methoden name, requiered_slots, submit und slot_mappings. Im Folgenden beschreiben wir den Zweck der einzelnen Methoden und ihre Implementierung.

1. Name

Diese Methode gibt lediglich den Namen des Forms zurück, wie er innerhalb der Domain definiert wurde. Das ermöglicht es Rasa, das *Mapping zwischen Python Klasse und des in der Domain definierten Forms vorzunehmen.

    
    def name(self) -> Text: return "hotel_form"

2. benötigte Steckplätze

Diese statische Methode gibt alle Pflichtfelder/Slots des Formulars als Liste zurück. Die Reihenfolge der Liste definiert auch die Reihenfolge, in der der Chatbot den Benutzer nach den Pflichtfeldern fragen wird. In diesem Beispiel sind die Anzahl der Personen, das Anreisedatum, die Anzahl der Nächte und der Zimmertyp die Pflichtfelder des Formulars.

Es wäre auch möglich, Felder dynamisch als Pflichtfelder zu definieren, basierend auf den Eingaben des Benutzers. Ein Anwendungsfall könnte die Angabe sein, ob der Benutzer ein Kinderbett benötigt - wenn Kinder im Zimmer schlafen. Wenn kein Kind im Zimmer schläft, ist diese Frage unnötig und wird daher vom Chatbot nicht gestellt. In unserem Beispiel nehmen wir jedoch keine dynamischen Pflichtfelder auf und daher sieht der Code so aus:

    
    @staticmethod
    def required_slots(tracker: Tracker) -> List[Text]:
        return [
            "number_of_persons",
            "date",
            "nights",
            "room_type" ]
    

Um die Slots zu verwenden, definieren wir sie unter Slots innerhalb der Domain in der domain.yml. Die Definition eines Slots gibt den Namen, den Datentyp und in speziellen Fällen die möglichen Werte des Slots an. In diesem Beispiel zeigen wir nur die Slots number_of_persons und room_type.

Für die beiden anderen Slots müssen wir einen korrekten Datentyp auswählen, und dann ist die Vorgehensweise dieselbe wie bei number_of_persons. Der Slot room_type ist ein Beispiel für einen Slot mit einer begrenzten Auswahl an Werten. An dieser Stelle hat der Benutzer die Wahl zwischen zwei Varianten, die im Chat mit dem Bot als zwei Schaltflächen angezeigt werden.

    
    slots: number_of_persons: type: float room_type: type: categorical values: - Junior - Senior
    

Fragen für Steckplätze

Um die mit dieser Methode verbundenen Änderungen abzuschließen, müssen wir noch die Fragen vorbereiten, die der FAQ-Chatbot stellen wird, um die Slots zu füllen. Diese müssen wir ebenfalls innerhalb der Domain (Datei: domain.yml) erstellen. Sie müssen nach der festen Struktur utter_ask angelegt werden <slot_name>. Ein besonderes Element ist der Slot room_type. Um dem Benutzer nur die beiden Auswahlmöglichkeiten als Schaltflächen zur Verfügung zu stellen, legen wir diese Antwort wie folgt an: </slot_name>

    
    utter_ask_room_type:
    - text: "In which room do you want to sleep. In a junior or senior suite?" 
    	buttons:
      - title: "Junior Suite"
      	payload: '/choose{"room_type": "Junior"}'
      - title: "Senior Suite" 
      	payload: '/choose{"room_type": "Senior"}'
    

3. einreichen

Die Methode submit wird ausgeführt, wenn das Formular vollständig ausgefüllt ist. Sie kann dazu dienen, die Reservierung zu speichern. In diesem Beispiel wird nur die Aktion utter_submit ausgeführt. Diese Aktion druckt die Eingaben des Benutzers aus und bestätigt sie somit.

    
    def submit(
        self,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> List[Dict]:
        dispatcher.utter_message(template="utter_submit")
        return []
    

Damit die Antwort utter_submit ausgeführt werden kann, muss sie innerhalb der Domäne definiert sein. Durch die Angabe des Namens des Slots innerhalb des Antworttextes kann der aktuelle Wert ausgegeben werden. Wenn wir z. B. den Wert von room_types ausgeben wollen, gehen wir wie folgt vor:

"Wir haben die Reservierung für eine {room_type} Suite erhalten."

Innerhalb einer Responses können beliebig viele Slots mit ihrem aktuellen Wert ausgegeben werden.

4. slot_mappings

Bevor wir die letzte Methode der Klasse namens slot_mapping definieren, müssen wir der Domäne einen weiteren Intent hinzufügen. Dies ist der Intent, den der Benutzer ausführt, um das Formular auszufüllen. Dazu fügen wir der Domäne die Entitäten number, data, days und room_type sowie den Intent inform hinzu.

    
    intents:
        - inform
    entities:
        - number
        - date
        - days
        - room_type
    

Nun fügen wir unter data/nlu.md Beispielinhalte mit den jeweiligen Entitäten hinzu. Die Entität room_type benötigt dies nicht, da sie durch eine Auswahl von zwei Buttons gefüllt wird. Wir empfehlen, für ein korrektes Training mindestens 5 Beispiele pro Entität bereitzustellen.

    
    ## intent:inform
    - Wir sind zu [4](number)
    - Wir suchen ein Zimmer für [2](number)
    - Der [05.03.2020](date) ist mein Anreisedatum
    - Am [15.04.2023](date)
    - [4](days) Tage
    - Ich werde [1](days) Tag im Hotel sein
    

Wir haben die Entitäten und Slots zur Domain hinzugefügt und die Intents in data/nlu.md für das Training eingerichtet. Die letzte Methode ist nun das Mapping von Entitäten auf Slots, in diesem Beispiel eine sehr einfache Version. Wir machen das Mapping mit der Methode form_entity der Klasse FormAction. Als Parameter wird die Entität und eine Liste von möglichen Intents übergeben. Wir mappen innerhalb des Dictionarys, das die Methode zurückgibt.

    
    def slot_mappings(self) -> Dict[Text, Union[Dict, List[Dict[Text, Any]]]]:
        return {
                "number_of_persons":[self.from_entity(entity="number", intent=["inform"])],
                "date": [self.from_entity(entity="date", intent=["inform"])],
                "nights": [self.from_entity(entity="days", intent=["inform"])],
                "room_type": [self.from_entity(entity="room_type", intent=["inform"])],
                }
    

Ausführen des Rasa FAQ Chatbots

Um den Chatbot korrekt auszuführen, starten wir nun den Action-Server von Rasa. Die vom Entwickler erstellten Aktionen werden innerhalb dieses Servers ausgeführt. Wir können noch komplexere Aktionen innerhalb von Rasa erstellen. Zum Beispiel können wir externe Schnittstellen einbinden und diese innerhalb von Aktionen verwenden. So führt ein Fehler innerhalb einer Aktion nicht zum Abbruch des Bots selbst, da dieser eigenständig ausgeführt wird.

Wir starten den Server mit dem Befehl rasa run action. Mit dem Parameter -p <port> ist es auch möglich, einen alternativen Port anzugeben, wenn dieser vom Standardport 5055 abweicht.</port>

Startet man nun den Chatbot mit rasa shell wird es nicht möglich sein, das Form zu füllen. Grund dafür ist, dass wir in der Konfigurationsdatei endpoints.yml die beiden Server, den Action Server und den FAQ-Chatbot selbst, miteinander verknüpfen müssen. Dafür fügen wir die ursprünglich auskommentierten Zeilen wieder hinzu:

    
    action_endpoint: url: http://localhost:5055/webhook
    

Jetzt können wir den Chatbot nach einem Training über rasa train mit rasa shell verwenden. Nachfolgend zeigen wir ein Beispiel zum Befüllen des Dialogs.

FAQ Chatbot example Dialog

*Intent = Intention des Benutzers. Wenn ein Benutzer z. B. eingibt "zeige mir die Technologie-Nachrichten von gestern", besteht die Absicht des Benutzers darin, eine Liste von Technologie-Schlagzeilen abzurufen. Wir benennen die Intentionen, oft mit einem Verb und einem Substantiv, wie z. B. "showNews".

*Entitäten/Entität = In der Datenmodellierung ist eine Entität ein eindeutig identifizierbares Objekt, das Informationen besitzt, die wir speichern oder verarbeiten wollen.

*(Daten-)Mapping = Der Prozess, der Datenelemente zwischen verschiedenen Datenmodellen abbildet. Das Datenmapping ist ein erster Schritt für verschiedene Aufgaben der Informationsintegration.

Ausblick

In diesem Tutorial haben wir einen Rasa-Chatbot für die Beantwortung einfacher FAQs und für eine Reservierung gebaut.

Diese Implementierung beinhaltet noch keine Fehlerbehandlung. Bislang kann der Bot nicht auf unerwartete Fragen reagieren. Auch kann der Benutzer während der Reservierung keine Fragen stellen. Dieser Chatbot erlaubt es auch nicht, Slots über externe Schnittstellen oder basierend auf Abhängigkeiten zu füllen.

Dennoch kann Rasa für all diese Probleme eine Lösung anbieten, um den optimalen Chatbot für jede Situation zu erstellen.

You want to see more?
mehr anzeigen
No spam, we promise.
Erhalten Sie wertvolle Insights von unserem Expertenteam.