From Zero to Smart Answers

How To: einen Chatbot mit Open Source implementieren

Virtuelle Assistenten können vielfältige Aufgaben übernehmen und zu einer gelungenen Customer Experience beitragen. Dieser Beitrag unserer Blogserie zeigt, wie Sie mit der Umsetzung eines Chatbots schnell und effizient starten können. Wir werden Schritt für Schritt einen Bot implementieren und dazu Rasa Open Source nutzen. Als beispielhaften Use Case haben wir hier einen Chatbot zur Anmeldung für einen Newsletter gewählt. Natürlich lassen sich auf dieselbe Art (zusätzlich) auch andere Chatbot-Use-Cases realisieren – beispielsweise die Reservierung eines Termins, Auskunft über den Kontostand, usw.

Rasa installieren und das Projekt initialisieren

Voraussetzung: Python ist in der Version 3.7.x oder 3.8.x installiert (bei mir Python 3.7.9)

Wir starten, indem wir eine virtuelle Python-Umgebung erstellen. Dies ist zwar nicht zwingend nötig, aber grundsätzlich eine gute Praxis, um bei verschiedenen Python-Projekten etwa Versionskonflikten aus dem Weg zu gehen.

Wir wählen also einen Python-Interpreter aus und legen ein ./venv-Verzeichnis an, das die virtuelle Umgebung enthält:

python3 -m venv ./venv

Im Anschluss aktivieren wir die virtuelle Umgebung:

source ./venv/bin/activate

Wir führen nun ein Upgrade von pip auf die neuste Version durch, denn sonst kann es zu Problemen bei der Installation von Rasa kommen. Anschließend können wir dann Rasa Open Source mit pip installieren:

pip3 install -U pip && pip3 install rasa

Es wird die aktuellste Rasa Version installiert (bei mir 3.0.4). Dies kann einen kurzen Moment dauern, doch dann können wir bereits unser erstes Rasa-Projekt initialisieren:

rasa init

Jetzt werden uns ein paar Fragen gestellt. Zunächst müssen wir den Pfad angeben, unter welchem das Projekt erstellt werden soll. Dann werden wir gefragt, ob wir ein initiales Modell trainieren möchten. Dies verneinen wir.  

Es wird dann ein initiales Rasa-Projekt unter dem angegebenen Pfad erstellt. Die entstandene Verzeichnisstruktur ist die folgende (wobei der Ordner models tatsächlich erst nach dem Trainieren eines ersten Modells erzeugt wird):

Wie diese Dateien zu konfigurieren sind, werden wir im Folgenden sehen. Zuvor möchte ich jedoch noch kurz erklären, nach welchem Prinzip ein Rasa-Chatbot agiert, um Ihnen das Verständnis der Konfiguration zu erleichtern.

Wie funktioniert Rasa?

Eine Konversation startet mit einer ersten Eingabe des Users. Der Chatbot ordnet diese Eingabe dann im Hintergrund einem sogenannten „Intent“ zu, also einer Nutzerabsicht. Dabei wählt er aus einer Reihe an vordefinierten Intents, die er anhand von Beispieldaten gelernt hat. Mögliche User-Intents wären beispielsweise das Ziel, den Bot zu begrüßen oder der Wunsch, eine Auskunft zu bekommen oder Informationen zu übergeben.

Der Chatbot weiß aufgrund vordefinierter Regeln und „Stories“, welche Antwort oder gegebenenfalls Aktion seinerseits nun auf diesen Intent folgen soll.

Die etwaige nächste Eingabe des Users wird wieder einem Intent zugeordnet, auf die der Chatbot zu reagieren weiß, und so weiter.

Damit sich unser Newsletter-Chatbot also wie von uns gewünscht verhält, müssen wir nun solche Intents, Aktionen, Antworten, Regeln und Stories vorgeben.

NLU-Daten bereitstellen

Wir beginnen mit der Bereitstellung von Natural Language Understanding (NLU)-Daten. Wie eben bereits angeklungen ist, müssen wir Beispielnachrichten für die verschiedenen Userabsichten hinterlegen, aus denen unser Assistent lernen kann. Schließlich soll der Bot erkennen können, was ein Benutzer meint, unabhängig davon, wie dessen Nachricht formuliert ist.

Dies tun wir in der Datei nlu.yml im Verzeichnis data, und zwar gruppiert nach dem „Intent“. Wir beschränken uns hier erstmal auf die grundlegenden Intents für den Use Case – wir nehmen an, dass sich User zum Newsletter anmelden möchten und den Chatbot zudem gegebenenfalls begrüßen und verabschieden. Wir nennen daher Beispiele für einen Intent greet, einen Intent goodbye und einen Intent subscribe.

Diese Intents und ihre Beispiele werden später beim Modelltraining als Trainingsdaten für das NLU-Modell des Assistenten verwendet.

Natürlich wären in diesem Zusammenhang noch weitere Userabsichten denkbar, etwa dass sich die Nutzer bedanken möchten.

Nutzerabsichten, Antworten und Aktionen definieren

Eine der wichtigsten Konfigurationsdateien in einem Rasa Projekt ist die domain.yml. Man könnte sagen, sie definiert das Universum, in dem unser Assistent arbeitet. So gibt sie u.a. die Nutzerabsichten, Antworten und Aktionen an, die der Bot kennen muss.

Wir verwenden hier die folgende Konfiguration:

Die wichtigsten Teile der domain.yml möchte ich Ihnen nun erläutern.

Damit unser Chatbot überhaupt weiß, welche Intents es gibt, müssen diese in der domain.yml gelistet werden. Wir setzen also die drei Intents greet, subscribe und goodbye, für die wir in der nlu.yml bereits Beispiele gelistet haben.

Den Abschnitt forms benötigen wir, damit unser Assistent den Namen und die E-Mail-Adresse des Users abfragen kann. Diese Infos, die in den „Slots“ name und email abgespeichert werden, benötigt er schließlich für die Newsletteranmeldung. Doch was sind Slots überhaupt?

Slots sind gewissermaßen das Gedächtnis eines Rasa-Bots. Sie fungieren als Key-Value-Speicher, in dem sowohl Informationen gespeichert werden können, die der Benutzer angegeben hat (wie z.B. sein Name), als auch Informationen, die er über die Außenwelt gesammelt hat (etwa das Ergebnis einer Datenbankabfrage). Welche Slots es gibt und deren Settings, wird im Bereich slots definiert.

Unter responses können wir die Antworten des Chatbots festlegen, z.B. „Hallo, wie kann ich helfen?“ als Begrüßung. 

Schließlich legen wir noch fest, welche actions unser Assistent kennen soll, hier die Aktion action_subscribe. Wie man definiert, was bei dieser Aktion passieren soll, werden wir im nächsten Abschnitt sehen.

Benutzerdefinierte Aktionen

Eine benutzerdefinierte Aktion kann jeden beliebigen Code ausführen, etwa eine API aufrufen oder eine Datenbank abfragen. Wir können eine solche also nutzen, um einen Termin zu einem Kalender hinzufügen, den Kontostand eines Benutzers zu überprüfen oder eben einen User zu einem Newsletter anzumelden.

Wir nutzen den folgenden Python-Code, der in der actions/actions.py im Projekt eingefügt wird.

Der Code holt sich zunächst die Daten des Nutzers aus den Slots email und name und kann diese dann weiterverarbeiten. Der Code-Teil für die tatsächliche Anmeldung ist ausgespart, da dieser natürlich ganz individuell ist. Am Ende wird mit dispatcher.utter_message(…)noch eine Antwort an den Nutzer festgelegt.

Wichtig im Code ist auch, dass durch returnaction_subscribe“ festgelegt wird, unter welchem Namen diese Aktion aufgerufen werden kann. Diesen Namen haben wir bereits in der domain.yml im Abschnitt actions gelistet, sodass der Bot die Aktion kennt.

Um später unser kleines Programm auch ausführen zu können, benötigen wir einen sogenannten Action-Server. Wir setzen daher in der endpoints.yml folgende Zeile, um später den Action-Server auf Port 5055 der lokalen Maschine zu starten:

Rules und Stories

Unser Chatbot kennt nun also verschiedene User-Intents, ein „Formular“, mit dem er Name und E-Mail-Adresse des Users abfragen kann, und diverse Antwortsätze. Auch haben wir Code für eine benutzerdefinierte Aktion hinterlegt, durch welche die tatsächliche Anmeldung durchgeführt werden kann.

Doch auf welchen Intent soll der Assistent mit welcher der Antworten reagieren? An welcher Stelle soll er das Formular präsentieren und wann die Aktion zur Newsletteranmeldung aufrufen? Um das festzulegen, nutzen wir sogenannte „Stories“ und „Rules“.

Stories sind beispielhafte Gesprächsverläufe, aus denen der Assistent lernt, richtig zu reagieren; je nachdem, was der Benutzer zuvor in dem Gespräch gesagt hat. Genauer gesagt werden Stories verwendet, um ein maschinelles Lernmodell zu trainieren, das Muster in Gesprächen erkennt und auf ungesehene Gesprächsverläufe verallgemeinert. Der Nutzer muss also nicht strikt dem vorgegebenen Gesprächsverlauf einer Story folgen, damit der Bot weiß, wie er zu reagieren hat.

Wir definieren in der stories.yml im data Verzeichnis folgende Story zur Newsletteranmeldung:

In dieser Story tauschen der Benutzer und der Assistent Grüße aus, der Benutzer äußert den Wunsch, den Newsletter zu abonnieren, und der Assistent beginnt, die benötigten Informationen über das Formular namens subscribe_form zu sammeln. Dann bedankt er sich für die Eingabe und führt die Anmeldung aus.

Wichtig hierbei ist, dass sämtliche Intents, Aktionen, Slots etc. auch in der domain.yml zu finden sind.

Neben den Stories können wir auch noch „Rules“ definieren, also feste Regeln. Wir können diese Regeln nutzen, wenn wir sicherstellen wollen, dass unser Assistent auf eine bestimmte Absicht immer mit einer bestimmten Aktion reagiert – unabhängig davon, was davor im Gespräch gesagt wurde. Der Vorteil fester Regeln kommt besonders zum Tragen, wenn der Chatbot mehr als nur die eine Aufgabe erfüllt.

Die entsprechende Konfigurationsdatei ist die rules.yml im data Verzeichnis:

Unsere erste Regel besagt, dass der Chatbot auf eine Verabschiedung des Users immer ebenfalls mit einer Abschiedsfloskel reagieren soll.

Im mittleren Codeblock haben wir eine Regel hinzugefügt, die das subscribe_form auslöst, wenn der Benutzer die Absicht subscribe äußert.

Wir haben außerdem eine Regel hinzugefügt, die die Aktion utter_submit gefolgt von der Aktion action_subscribe auslöst, sobald alle erforderlichen Informationen für das subscribe_form eingegeben wurden. Diese Regel gilt nur, wenn das subscribe_form zu Beginn aktiv ist. Sobald es nicht mehr aktiv ist (active_loop: null), wird das Formular beendet.

Trainieren des Modells und Starten des Bots

Wir haben nun alle nötigen Konfigurationen vorgenommen und können nun im nächsten Schritt das NLU-Modell trainieren:

rasa train

Nach einem kurzen Moment sollten wir die Erfolgsmeldung „Your Rasa model is trained and saved at models/<modelname>.tar.gz“ erhalten. Das Modell liegt nun also im Verzeichnis models und kann ab sofort vom Bot genutzt werden, um Intents zu erkennen.

Wie oben bereits angekündigt, müssen wir einen sogenannten Action-Server starten, damit der Code unserer benutzerdefinierten Aktion ausgeführt werden kann:

rasa run actions

Um uns nun schließlich mit unserem Assistenten unterhalten zu können, führen wir das folgende Kommando aus:

rasa shell

Dieser Befehl startet den Rasa Server – sofern nicht anders konfiguriert – auf Port 5005 und lädt unser neustes NLU-Modell. Wir können nun über das Terminal die Unterhaltung starten, z.B. mit einer Begrüßung und der anschließenden Frage nach dem Newsletter:

Wir sehen, der Bot reagiert beide Male wie gewünscht. Er erkennt die Absichten des Nutzers, obwohl sie anders formuliert wurden, als die in der nlu.yml angegebenen. Wir geben dem Chatbot nun die gewünschten Infos: Name und E-Mail-Adresse. Daraufhin wird der Python-Code aus der actions.py ausgeführt und der Chatbot antwortet uns, dass wir nun noch das Abonnement bestätigen müssen:

Wir sehen dabei, dass er sich unseren Namen und die E-Mail-Adresse „gemerkt“ hat und sie wiedergeben kann. Verabschieden wir uns nun, antwortet der Chatbot wie gewünscht:

Fazit und Ausblick

Wir haben es in diesem Blogbeitrag geschafft, einen ersten Chatbot mit Rasa Open Source zu implementieren. Dieser hat, wie wir sehen konnten, schon einige Stärken, aber natürlich auch noch viele Grenzen.

In den nächsten beiden Beiträgen der Reihe erfahren Sie mehr zu den Hürden traditioneller Chatbots und wie Sie diese überwinden können.

Sie wollen nicht tatenlos auf den nächsten Beitrag warten?

Bianca Schlüter

Bianca Schlüter

...geboren 1994 in Augsburg, studierte Mathematik an der Universität Augsburg mit den Schwerpunkten Statistik und Optimierung. Seit 2020 arbeitet sie als Consultant Search and Analytics bei der SHI. Lieblingsdateiformat: JSON