Tutorial: Building Assistants

Tutorial: Building Assistants

After following the basics of setting up an assistant in the Rasa Tutorial, we’ll now walk through building a basic FAQ chatbot and then build a bot that can handle contextual conversations.

Building a simple FAQ assistant

FAQ assistants are the simplest assistants to build and a good place to get started. These assistants allow the user to ask a simple question and get a response. We’re going to build a basic FAQ assistant using features of Rasa designed specifically for this type of assistant.

In this section we’re going to cover the following topics:

To prepare for this tutorial, we’re going to create a new directory and start a new Rasa project.

mkdir rasa-assistant
rasa init

Let’s remove the default content from this bot, so that the nlu.md, stories.md and domain.yml are empty.

Memoization Policy

The MemoizationPolicy remembers examples from training stories for up to a max_history of turns. The number of “turns” includes messages the user sent, and actions the assistant performed. For the purpose of a simple, context-less FAQ bot, we only need to pay attention to the last message the user sent, and therefore we’ll set that to 1.

You can do this by editing your config.yml file as follows:

policies:
- name: MemoizationPolicy
  max_history: 1
- name: MappingPolicy

Now that we’ve defined our policies, we can add some stories for the goodbye, thank and greet intents to the stories.md file:

## greet
* greet
  - utter_greet

## thank
* thank
  - utter_noworries

## goodbye
* bye
  - utter_bye

We’ll also need to add the intents, actions and templates to our domain.yml file in the following sections:

intents:
  - greet
  - bye
  - thank

actions:
  - utter_greet
  - utter_noworries
  - utter_bye

templates:
  utter_noworries:
    - text: No worries!
  utter_greet:
    - text: Hi
  utter_bye:
    - text: Bye!

Finally, we’ll copy over some NLU data from Sara into our nlu.md:

## intent:greet
- Hi
- Hey
- Hi bot
- Hey bot
- Hello
- Good morning
- hi again
- hi folks

## intent:bye
- goodbye
- goodnight
- good bye
- good night
- see ya
- toodle-oo
- bye bye
- gotta go
- farewell

## intent:thank
- Thanks
- Thank you
- Thank you so much
- Thanks bot
- Thanks for that
- cheers

You can now train a first model and test the bot, by running the following commands:

rasa train
rasa shell

This bot should now be able to reply to the intents we defined consistently, and in any order.

While it’s good to test the bot interactively, we should also add end to end test cases that can later be included as part of our CI/CD system. End to end stories include NLU data, so that both components of Rasa can be tested. Create a file called test_stories.md in the root directory with some test cases:

## greet + goodbye
* greet: Hi!
  - utter_greet
* bye: Bye
  - utter_bye

## greet + thanks
* greet: Hello there
  - utter_greet
* thank: thanks a bunch
  - utter_noworries

## greet + thanks + goodbye
* greet: Hey
  - utter_greet
* thank: thank you
  - utter_noworries
* bye: bye bye
  - utter_bye

To test our model against the test file, run the command:

rasa test --e2e --stories test_stories.md

The test command will produce a directory named results. It should contain a file called failed_stories.md, where any test cases that failed will be printed. It will also specify whether it was an NLU or Core prediction that went wrong. As part of a CI/CD pipeline, the test option --fail-on-prediction-errors can be used to throw an exception that stops the pipeline.

Response Selectors

The Response Selector NLU component is designed to make it easier to handle dialogue elements like Small Talk and FAQ messages in a simple manner. By using the ResponseSelector, you only need one story to handle all FAQs, instead of adding new stories every time you want to increase your bot’s scope.

People often ask Sara different questions surrounding the Rasa products, so let’s start with three intents: ask_channels, ask_languages, and ask_rasax. We’re going to copy over some NLU data from the Sara training data into our nlu.md. It’s important that these intents have an faq/ prefix, so they’re recognised as the faq intent by the ResponseSelector:

## intent: faq/ask_channels
- What channels of communication does rasa support?
- what channels do you support?
- what chat channels does rasa uses
- channels supported by Rasa
- which messaging channels does rasa support?

## intent: faq/ask_languages
- what language does rasa support?
- which language do you support?
- which languages supports rasa
- can I use rasa also for another laguage?
- languages supported

## intent: faq/ask_rasax
- I want information about rasa x
- i want to learn more about Rasa X
- what is rasa x?
- Can you tell me about rasa x?
- Tell me about rasa x
- tell me what is rasa x

Next, we’ll need to define the responses associated with these FAQs in a new file called responses.md in the data/ directory:

## ask channels
* faq/ask_channels
  - We have a comprehensive list of [supported connectors](/content/docs/core/connectors/index.html), but if you don't see the one you're looking for, you can always create a custom connector by following [this guide](/content/docs/rasa/user-guide/connectors/custom-connectors/index.html).

## ask languages
* faq/ask_languages
  - You can use Rasa to build assistants in any language you want!

## ask rasa x
* faq/ask_rasax
 - Rasa X is a tool to learn from real conversations and improve your assistant. Read more [here](/content/docs/rasa-x/index.html)

To use the Response Selector we need to add it to the end of the expanded supervised_embeddings NLU pipeline in our config.yml:

pipeline:
- name: "WhitespaceTokenizer"
- name: "RegexFeaturizer"
- name: "CRFEntityExtractor"
- name: "EntitySynonymMapper"
- name: "CountVectorsFeaturizer"
- name: "CountVectorsFeaturizer"
  analyzer: "char_wb"
  min_ngram: 1
  max_ngram: 4
- name: "EmbeddingIntentClassifier"
- name: "ResponseSelector"

Now that we’ve defined the NLU side, we need to make Core aware of these changes. Open your domain.yml file and add the faq intent:

intents:
  - greet
  - bye
  - thank
  - faq

We’ll also need to add a retrieval action, which takes care of sending the response predicted from the ResponseSelector back to the user, to the list of actions. These actions always have to start with the respond_ prefix:

actions:
  - utter_greet
  - utter_noworries
  - utter_bye
  - respond_faq

Next we’ll write a story so that Core knows which action to predict:

## Some question from FAQ
* faq
    - respond_faq

This prediction is handled by the MemoizationPolicy, as we described earlier.

Using the features we described in this tutorial, you can easily build a context-less assistant. When you’re ready to enhance your assistant with context, check out Building contextual assistants.

Building contextual assistants

Whether you’ve just created an FAQ bot or are starting from scratch, the next step is to expand your bot to handle contextual conversations.

In this tutorial we’re going to cover a variety of topics:

Please make sure you’ve got all the data from the Building a simple FAQ assistant section before starting this part. You will need to make some adjustments to your configuration file, since we now need to pay attention to context:

policies:
- name: MemoizationPolicy
- name: MappingPolicy

We removed the max_history: 1 configuration. The default is 5, meaning Core will pay attention to the past 5 turns when making a prediction (see explanation of max history).

Business logic

A lot of conversational assistants have user goals that involve collecting a bunch of information from the user before being able to do something for them. This is called slot filling. For example, in the banking industry you may have a user goal of transferring money, where you need to collect information about which account to transfer from, whom to transfer to and the amount to transfer. This type of behaviour can and should be handled in a rule based way, as it is clear how this information should be collected.

For this type of use case, we can use Forms and our FormPolicy. The FormPolicy works by predicting the form as the next action until all information is gathered from the user.

As an example, we will build out the SalesForm from Sara. The user wants to contact our sales team, and for this we need to gather the following pieces of information:

We will start by defining the SalesForm as a new class in the file called actions.py. The first method we need to define is the name, which like in a regular Action returns the name that will be used in our stories:

from rasa_sdk.forms import FormAction

class SalesForm(FormAction):
    """Collects sales information and adds it to the spreadsheet"""

def name(self):
        return "sales_form"

Next we have to define the required_slots method which specifies which pieces of information to ask for, i.e. which slots to fill.

@staticmethod
def required_slots(tracker):
    return [
        "job_function",
        "use_case",
        "budget",
        "person_name",
        "company",
    ]

... (Continued in similar fashion for further topics)