Natural Language Processing

How to create a FAQ Chatbot with Rasa?

 

 

FAQ Chatbot answering requests

A FAQ Chatbot will bring your First-Level Support to a new level!

In this article we will show how to implement a FAQ chatbot with Rasa to answer FAQs and fill in forms. For working with forms, the Rasa framework with the FormPolicy offers a simple way to create simple yet user-friendly bots for this task without the need to write extensive dialogs.

In the article "Create a chatbot using Rasa" we described how to create a simple chatbot with Rasa. We showed how to install Rasa and initialize a first project. We also illustrated how to have a simple dialog with the bot.

Human chatting with FAQ Chatbot

To show this use case, we describe a chatbot which allows to reserve a hotel room and answers basic questions about the hotel. An exemplary implementation can be found at https://github.com/Steadforce/rasa_faq_form_bot. This article describes the creation of the chatbot using the implementation found there. 

Rasa 1.8 was used for the creation. Since at the time of writing this article only the first alpha version of Rasa 2.0 was introduced, Rasa 2.0 is not covered. First, we will start with our chatbot answering questions.

 

Building the FAQ Chatbot

To start, initialize a project in an empty folder using the Rasa CLIIf Rasa is not yet installed and you don’t know how to set up an initial project, you can follow the steps in our previous tutorial.

After initialization of the project we delete the *intents, stories and unnecessary configurations of the domain. Now, intents are created for three questions. The FAQ chatbot can be asked questions about the location of the hotel, its appearance and possible activities there. We first create these within the NLU data under data/nlu.md. 

With the ResponseSelector Rasa has a functionality that simplifies the handling of small talk and FAQs. This functionality is used below. For this purpose, the questions within the NLU data have to be specially marked, ie. the questions need to follow the pattern ## intent: faq/ask_<name>The question about the appearance of the hotel is shown below as an example. To use the ResponseSelector, at least two intents must be created.

## intent: faq/ask_location 
- Where is the hotel?
- Where can I find you?
- The hotel is where?
- In which city is the hotel?
- Where is the hotel?

After creating the intents, the responses, i.e. the reactions of the bot to the user’s intent, must be prepared. This is not done via responses within the domain as described in the previous article. To avoid the domain.yml file becoming too confusing and overloaded with configurations, we add a new responses.md to the data folder.

In this file the responses. to the previously defined questions are generated. Responses are created similarly to stories, but with only one switch between user and chatbot.

# Ask location 
* faq/ask_location 
    - The hotel 'To speaking bot' is located in the heart of Munich with a panoramic view of the Alps.

The advantages of the ResponseSelector are now evident in the creation of the story. It is not necessary to create multiple stories, which deal with each individual question. Within the stories under data/stories.md all FAQs are treated in the same way and there is no distinction between them. This can be a major advantage especially for chatbots with a lot of different FAQs.

## Some questions for faq
* faq
    - respond_faq

Ultimately the intent faq and the action to answer the questions of the domain (file: domain.ymlmust be added so that the FAQ chatbot can be trained with the command rasa train and then tested via rasa shell.

FAQ Chatbot dialog rasa shell

FAQ Chatbot: Filling a form through dialog

The FAQ chatbot is now able to answer simple questions. In the following we enable the Bot to accept reservations. In order to do this, Rasa offers the possibility to fill in Forms. This article describes only a PoC with limited functionality.

With Entity Extraction Rasa offers the possibility to enter complex data types into forms. Thus, it is possible to correctly interpret user data, such as "Tomorrow afternoon at 14:00". For more information please refer to the Rasa documentation at https://rasa.com/docs/rasa/nlu/entity-extraction.  

To fill a form in Rasa you first have to add the required FormPolicy under policies in config.yml.
T
he next step is to add the form that is to be filled to the domain within the domain.yml file.

forms: 
    - hotel_form

The required policy is added, and the form is included in the domain. As with the questions to be answered, we generate a story, which shows the process of filling the form. For this we first set up the intent request_room within the domain and define sample contents for the training under data/nlu.md.

Here we add two different versions of the intents. The first intent only contains the information that a room must be reserved.

## intent:request_room  
- I would like to book a room

Another possibility is to transfer information already in this intent. So, you can specify so-called entities within this intent.  In this example, the arrival date is used for this purpose. It is important that the slot and the entity have an identical name, in this example date. Slots and entities will be specified in the further steps.

## intent:request_room  
- Is a room available from the [11/02/2020](date).  
- I would like to book a room for the [10/03/2020](date).

These two intents now make it possible to fill one of the fields at the beginning of the form. We also include them in the domain under domain.yml. During the further completion of the form, the user is not asked which date he wants, since this date was already specified at the beginning.   

Now we will build a story that shows the optimal case for filling the form.

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

To fill the form in a dialog, we write the Python class HotelForm within actions.pyThis class inherits from the class FormAction and implements the four methods name, requiered_slotssubmit and slot_mappings. The purpose of each method and its implementation is described below.

name

This method simply returns the name of the form as defined within the domain. This allows Rasa to perform *mapping between the Python class and the form defined within the domain.

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

required slots

This static method returns all mandatory fields/slots of the form. This is done as a list. The order of the list also defines the order in which the chatbot will ask the user for the mandatory fields. In this example, the number of people, the date of arrival, the number of nights and the room type are the required fields of the form.

It would also be possible to dynamically define fields as mandatory based on the user’s input. A use case might be, if children sleep in the room, the indication whether a crib is needed. If no child sleeps in the room, this question is unnecessary and is therefore not asked.  In our example, however, dynamic mandatory fields are not included and therefore the code looks like this:

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

To use the slots we define them under slots in the domain. This is also done under domain.yml. DThe definition of a slot specifies the name, the data type and in special cases the possible values of the slot. In this example we only show the slots number_of_persons and room_type.

For the two other slots, a correct data type must be selected and then the procedure is the same as for number_of_persons. The slot room_type is an example of a slot with a limited choice of values. At this point the user has the choice between two variants, which are displayed in the chat with the bot as two buttons.

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

To complete the changes associated with this method we still need to prepare the questions that the FAQ chatbot will ask to fill the slots. These must also be created within the domain (file: domain.yml). They have to be set up according to the fixed structure utter_ask <slot_name>. A special element is the slot room_type. In order to provide the user with only the two selection options as buttons, we create this response as follows:

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

 

submit

The submit method is executed when the form is completely filled. It may be used to save the reservation. This example only executes the action utter_submit. This action prints the user’s input and thus confirms it.

def submit( 
    self, 
    dispatcher: CollectingDispatcher, 
    tracker: Tracker, 
    domain: Dict[Text, Any], 
) -> List[Dict]: 

    dispatcher.utter_message(template="utter_submit") 
    return []

In order to execute the response utter_submitit must be defined within the domain. By specifying the name of the slot within the response text, the current value can be output. For example, if we want to output the value of room_types, this is done as follows:

"We have received the reservation for a {room_type} suite."

Within a response any number of slots can be output with their current value.

slot_mappings

Before we define the last method of the class called slot_mapping, we have to add another intent to the domain. This is the intent that the user executes to fill the form. For this we add the entities number, datadays and room_type and the intent inform to the domain.

intents:  
  - inform  

entities:  
  - number  
  - date  
  - days  
  - room_type

Now we add sample contents with the respective entities under data/nlu.mdThe entity room_type does not need this, because it is filled by a choice of two buttons. We recommend to provide at least 5 examples per entity for a correct training.

## intent:inform  
- There are [4](number) of us 
- We are looking for a room for [2](number)  
- The [03/05/2020](date) is my date of arrival 
- On [04/15/2023](date)  

- [4](days) days  
- I will be in the hotel for [1](days) day

We added the entities and slots to the domain and set up the intents within data/nlu.md for the training. Now the last method is the mapping from entities to slots, here a very simple version. The mapping is done with the method form_entity of the class FormAction. As parameters the entity and a list of possible intents is passed. The mapping is done within the dictionary, which is returned by the method.

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"])],  
       }

 

Executing the FAQ Chatbot

To execute the chatbot correctly, we now start the action server of Rasa. Actions created by the developer are executed within this server. Even more complex actions can be created within Rasa. For example, we can integrate external interfaces and use them within actions. Thus, an error within an action does not lead to the termination of the bot itself, since it is executed independently. 

We start the server with the command rasa run action. gestartet werden. With the parameter –p <port> it is also possible to specify an alternative port if it differs from the standard port 5055.

If you now start the chatbot with rasa shell, filling the form won’t work. The reason for this is that in the configuration file endpoints.yml we have to link the two servers, the action server and the chatbot itself. Therefore we have to add the initially commented lines:

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

Now we can use the chatbot after a training via rasa train using rasa shellAn example dialog for filling the dialog is shown below.

FAQ Chatbot example Dialog

*Intent = Intention of the user. For example, if a user enters "show me yesterday’s technology news", the user’s intention is to retrieve a list of technology headlines. Intentions are given a name, often a verb and a noun, such as "showNews".

*Entities/Entity = In data modeling, an entity is a clearly identifiable object about which information is to be stored or processed.

*(Data-) Mapping = The process that maps data elements between different data models. Data mapping is needed as a first step for various information integration tasks.

FAQ Chatbot Prospects outlook steadforce deer

Prospects

In this article we have built a chatbot for answering simple questions and making a reservation. This implementation does not yet include error handling. So far, the bot can’t react to unexpected questions. Also, the user can’t ask any questions during the reservation.  

This chatbot doesn’t offer the possibility to fill slots through external interfaces or based on dependencies either. For all these problems Rasa can offer a solution to create the optimal chatbot for each situation. 

More of AI and Natural Language Processing