RASA - Unhappy paths
Tags: rasa, chatbot, nlp, ai
Published: 2021-03-25 06:32:37

When users communicates with the chatbot, they don't always behave the way we would like them to.
When filling a newsletter form, they might jump to a chitchat or change their mind and not fill the form at all.

We will handle those two cases now.

## Chitchat
It might happen, that user starts talking about something completely irrelevant when filling the newsletter form. In this case, we want to provide a way for the user to go back on track and finish the form.

Create a new intent that will mean that user went out of scope. Add a few training examples to this intent.
```yml
# data/nlu.yml
# ... previous contents ...
  - intent: chitchat
    examples: |
      - that's not what I want to do
      - wait stop
      - you're no help
      - this is no help at all
      - how old are you
      - I want to order a pizza
      - tell me the weather
      - this isn't working
      - I already told you that
      - don't like that
      - I don't want to tell you that
      - none of your business
      - that's not right
      - stop asking
      - nevermind
      - I want to do something else
      - I changed my mind
```

Add another two intents **affirm** and **deny**.
```yml
# data/nlu.yml
# ... previous contents ...
  - intent: affirm
    examples: |
      - yes
      - indeed
      - of course
      - that sounds good
      - correct
      - sure
      - ok
      - why not
      - ok great
      - yes I did
      - yeah, great
      - pretty good
      - fine
      - You bet
      - I sure did
      - more or less
  - intent: deny
    examples: |
      - no
      - never
      - I don't think so
      - no way
      - not really
      - none
      - absolutely not
      - no thanks
      - didn't do any
      - no I didn't
      - could have been better
      - not great
      - nope
```

As all other intents, list those in `domain.yml` file too.
```yml
# domain.yml
# ... previous contents ...
intents:
  # ... previous intents ...
  - chitchat
  - affirm
  - deny
```

If our chatbot notices **chitchat** intent, it will ask if the user wants to continue. Let's create an utterance for this.
```yml
# domain.yml
# ... previous contents ...
  utter_ask_continue:
    - text: Sorry, I don't quite understand. Do you want to continue?
```

Now let's put those intents and responses together in a story.
```yml
# data/stories.yml
# ... previous contents ...
  - story: newsletter form continue
    steps:
      - intent: subscribe
      - action: newsletter_form
      - active_loop: newsletter_form
      - intent: chitchat
      - action: utter_ask_continue
      - intent: affirm
      - action: newsletter_form
```
In this story, if chitchat intent is recognized, the chatbot will ask if the user wants to continue. If so, the form is reactivated.

Now run `rasa train && rasa test`.
Let's test our assistant.
![Chat with chitchat during email question](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g7coh2zf8qm060d37q2q.png)

Looks good, now let's try chitchat during the second form question.

![Chat with chitchat during frequency question handled poorly](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1l3d418dur6bin45y21g.png)

What happened? Why does it consider our pizza order an email frequency? To answer this, I will introduce new – very useful – rasa command: `rasa interactive`.
This will train our model and start an interactive learning session to create new training data for a Rasa model by chatting. We will, however, use this to debug our assistant.

During the interactive chat, you see chatbot's decisions about what intent was expressed:

![Subscribe intent during interactive chat](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wvl6fx53jk800cvap356.png)

what action should follow:

![newsletter_form action during interactive chat](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f5v00kuwc919pq2c0j9d.png)

and which entities have been recognized:

![Recognized email entity](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/faa7oxb2bzfaly02ngy6.png)

You can modify those decisions.

We can see, that the chatbot recognized our pizza order properly as a **chitchat** intent.

![Chitchat intent recognized during interactive chat](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/txra81pv01mjz3g920ot.png)

So where is the problem?
The problem is, that no matter the intent, the **frequency** slot is always filled **from_text**.

![Current slots](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/92wuplgit6a2ug4prarf.png)

We need to tell the chatbot, that the **frequency** slot should be filled only when the intent is **inform_frequency**. There is an easy way to do this in the `domain.yml` file.
```yml
# domain.yml
# ... previous content ...
forms:
  newsletter_form:
    email:
      - type: from_entity
        entity: email
    frequency:
      - type: from_text
        intent: inform_frequency
```
Now **frequency** slot will be filled **from_text** only if the intent was **inform_frequency**.

You can learn more about this in the [documentation](https://rasa.com/docs/rasa/forms#from_text).

Now it is right!

![Chat with chitchat during frequency question handled properly](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m8ntm0rfgr5bxtklcmcz.png)

## Leaving the form
The second unhappy path that might occur is user not wanting to continue the form at all. In cases like this, the assistant should stop asking for the requested slots.
Here's a story for this.

```yml
# data/stories.yml
# ... previous contents ...
  - story: newsletter form stop
    steps:
      - intent: subscribe
      - action: newsletter_form
      - active_loop: newsletter_form
      - intent: chitchat
      - action: utter_ask_continue
      - intent: deny
      - action: action_deactivate_loop
      - active_loop: null
```

We handle the situation using a default action **action_deactivate_loop** which will deactivate the form and reset the requested slot.

![Cancelling the form](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o6b9226wcmnrqa7nep2r.png)

We see that the chatbot stopped asking questions after the user cancelled the form.

You can learn more about unhappy paths in the [documentation](https://rasa.com/docs/rasa/forms#writing-stories--rules-for-unhappy-form-paths).

In the next chapter, we will look at testing those unhappy paths.

Repository for this tutorial:
{% github petr7555/rasa-dev-tutorial no-readme %}

You can checkout the state of the repository at the end of this tutorial by running:
```bash
git clone --branch 05-unhappy-paths git@github.com:petr7555/rasa-dev-tutorial.git
```