Version: Latest

Tutorial

You will build an assistant in this tutorial for helping people transfer money. This tutorial does not assume any existing knowledge of Rasa or chatbots. The techniques you will learn in this tutorial are fundamental to building any Rasa assistant, and understanding it will bring you quite far along to mastering Rasa.

What are you building?

In this tutorial, you will build an LLM-powered assistant that can complete a money transfer, reliably executing your business logic while allowing for fluid conversation.

Here are some of the conversations your assistant will be able to handle:

User: I want to send money

Bot: Who would you like to send money to?

User: to Jen

Bot: How much would you like to send?

User: $50

Bot: Please confirm: you want to transfer $50.0 to Jen?

User: yes

Bot: All done. $50.0 has been sent to Jen.

Bot: Is there anything else I can help you with?!

happy path

Following This Tutorial

Whenever there is something for you to do, you'll see this label:

Action Required

Prerequisites

To follow this tutorial, you will need:

info

This tutorial works with Rasa versions >= 3.8.0.

Setup

Action Required

For new users, the easiest way to get started is in the browser with a GitHub Codespace.

You can also install rasa-pro locally and use your own machine.

info

A GitHub codespace gives you a working environment to explore Rasa Pro in under a minute. We really suggest you start there!

To code along with this tutorial, navigate to an empty directory in your terminal, and run:

rasa init --template tutorial

By default, this tutorial uses the OpenAI API. If you'd like to use a different LLM, follow the instructions here.

If you're using a codespace, you already set your environment variables during setup. If you've installed Rasa Pro locally, set your OpenAI API key and Rasa Pro license in an environment variables:

export OPENAI_API_KEY="your-api-key"
export RASA_PRO_LICENSE="your-rasa-pro-license-key"

Then replace your-api-key and your-rasa-pro-license-key with the actual keys.

info

In order to gain access to GPT-4 from OpenAI you need to make a successful payment of $5 or more (see here).

Overview

Open up the project folder in your IDE to see the files that make up your new project. In this tutorial you will primarily work with the following files:

  • data/flows.yml
  • domain.yml
  • actions/actions.py

Testing your money transfer flow

Action Required

Train your assistant by running:

rasa train

And start talking to it in the browser by running:

rasa inspect
info

When you run the rasa inspect command in a GitHub Codespace, you'll see a notification that your application is available on port 5005. Click 'Open in Browser' to access the inspector and start chatting.

screenshot showing notification to click to open the inspector.

Now, try telling the assistant that you'd like to transfer some money to a friend.

info

This template bot uses a generative model to handle basic chitchat. If you want to disable this, delete the patterns.yml file and re-train.

Understanding your money transfer flow.

The file data/flows.yml contains the definition of a flow called transfer_money. Let's look at this definition to see what is going on:

flows.yml
flows:
transfer_money:
description: This flow lets users send money to friends and family.
steps:
- collect: recipient
- collect: amount
description: the number of US dollars to send
- action: utter_transfer_complete

The two key attributes of the transfer_money flow are the description and the steps. The description is used to help decide when to activate this flow. But it is also helpful for anyone who inspects your code to understand what is going on. If a user says "I need to transfer some money", the description helps Rasa understand that this is the relevant flow. The steps describe the business logic required to do what the user asked for.

The first step in your flow is a collect step, which is used to fill a slot. A collect step sends a message to the user requesting information, and waits for an answer.

Collecting Information in Slots

Slots are variables that your assistant can read and write throughout a conversation. Slots are defined in your domain.yml file. For example, the definition of your recipient slot looks like this:

domain.yml
slots:
recipient:
type: text
mappings:
- type: from_llm
# ...

Slots can be used to store information that users provide during the conversation, or information that has been fetched via an API call. First, you're going to see how to store information provided by the end user in a slot. To do this, you define a collect step like the first step in your flow above.

flows.yml
flows:
transfer_money:
description: This flow lets users send money to friends and family.
steps:
- collect: recipient
- collect: amount
description: the number of US dollars to send
- action: utter_transfer_complete

Rasa will look for a response called utter_ask_recipient in your domain file and use this to phrase the question to the user.

domain.yml
responses:
utter_ask_recipient:
- text: "Who would you like to send money to?"

After sending this message, Rasa will wait for a response from the user. When the user responds, Rasa will try to use their answer to fill the slot recipient. Read about slot validation to learn how you can run extra checks on the slot values Rasa has extracted.

The diagram below summarizes how slot values are used to collect and store information, and how they can be used to create branching logic.

explanation of how slots are used in flows

Descriptions in collect steps

The second collect step includes a description of the information your assistant will request from the user. Descriptions are optional, but can help Rasa extract slot values more reliably.

flows.yml
flows:
transfer_money:
description: This flow lets users send money to friends and family.
steps:
- collect: recipient
- collect: amount
description: the number of US dollars to send
- action: utter_transfer_complete

Action Steps

The third step in your transfer_money flow is not a collect step but an action step. When you reach an action step in a flow, your assistant will execute the corresponding action and then proceed to the next step. It will not stop to wait for the user's next message. For now, this is the final step in the flow, so there is no next step to execute and the flow completes.

flows.yml
flows:
transfer_money:
description: This flow lets users send money to friends and family.
steps:
- collect: recipient
- collect: amount
description: the number of US dollars to send
- action: utter_transfer_complete

Branching Logic

Slots are also used to build branching logic in flows.

Action Required

You're going to introduce an extra step to your flow, asking the user to confirm the amount and the recipient before sending the transfer. Since you are asking a yes/no question, you can store the result in a boolean slot which you will call final_confirmation.

In your domain file, add the definition of the final_confirmation slot and the corresponding response: utter_ask_final_confirmation. Also add a response to confirm the transfer has been cancelled.

domain.yml
slots:
recipient:
type: Text
mappings:
- type: from_llm
# ...
final_confirmation:
type: bool
mappings:
- type: from_llm
domain.yml
responses:
utter_ask_recipient:
- text: "Who would you like to send money to?"
# ...
utter_ask_final_confirmation:
- text: "Please confirm: you want to transfer {amount} to {recipient}?"
utter_transfer_cancelled:
- text: "Your transfer has been cancelled."

Notice that your confirmation question uses curly brackets {} to include slot values in your response.

Add a collect step to your flow for the slot final_confirmation. This step includes a next attribute with your branching logic. The expression after the if key will be evaluated to true or false to determine the next step in your flow. The then and else keys can contain either a list of steps or the id of a step to jump to. In this case, the then key contains an action step to inform the user their transfer was cancelled. The else key contains the id transfer_successful. Notice that you've added this id to the final step in your flow.

flows.yml
flows:
transfer_money:
description: This flow lets users send money to friends and family.
steps:
- collect: recipient
- collect: amount
description: the number of US dollars to send
- collect: final_confirmation
next:
- if: not slots.final_confirmation
then:
- action: utter_transfer_cancelled
next: END
- else: transfer_successful
- action: utter_transfer_complete
id: transfer_successful

To try out the updated version of your assistant, run rasa train, and then rasa inspect to talk to your assistant. It should now ask you to confirm before completing the transfer.

Integrating an API call

An action step in a flow can describe two types of actions. If the name of the action starts with utter_, then this action sends a message to the user. The name of the action has to match the name of one of the responses defined in your domain. The final step in your flow contains the action utter_transfer_complete, and this response is also defined in your domain. Responses can contain buttons, images, and custom payloads. You can learn more about everything you can do with responses here.

The second type of action is a custom action. The name of a custom action starts with action_.

You are going to create a custom action, action_check_sufficient_funds, to check whether the user has enough money to make the transfer, and then add logic to your flow to handle both cases.

Your custom action is defined in the file actions/actions.py. To learn more about custom actions, go here.

Your actions.py file should look like this:

actions.py
from typing import Any, Text, Dict, List
from rasa_sdk import Action, Tracker
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk.events import SlotSet
class ActionCheckSufficientFunds(Action):
def name(self) -> Text:
return "action_check_sufficient_funds"
def run(self, dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:
# hard-coded balance for tutorial purposes. in production this
# would be retrieved from a database or an API
balance = 1000
transfer_amount = tracker.get_slot("amount")
has_sufficient_funds = transfer_amount <= balance
return [SlotSet("has_sufficient_funds", has_sufficient_funds)]

Slots are the primary way to pass information to and from custom actions. In the run() method above, you access the value of the amount slot that was set during the conversation, and you pass information back to the conversation by returning a SlotSet event to update the has_sufficient_funds slot.

diagram of how slots are used with custom actions
Action Required

Now you are going to make three additions to your domain.yml. You will add a top-level section listing your custom actions. You will add the new boolean slot has_sufficient_funds, and you will add a new response to send to the user in case they do not have sufficient funds.

domain.yml
actions:
- action_check_sufficient_funds
slots:
# ...
has_sufficient_funds:
type: bool
mappings:
- type: custom
responses:
# ...
utter_insufficient_funds:
- text: "You do not have enough funds to make this transaction."

Now you are going to update your flow logic to handle the cases where the user does or does not have enough money in their account to make the transfer.

Notice that your collect: final_confirmation step now also has an id so that your branching logic can jump to it.

flows.yml
flows:
transfer_money:
description: This flow lets users send money to friends and family.
steps:
- collect: recipient
- collect: amount
description: the number of US dollars to send
- action: action_check_sufficient_funds
next:
- if: not slots.has_sufficient_funds
then:
- action: utter_insufficient_funds
next: END
- else: final_confirmation
- collect: final_confirmation
id: final_confirmation
next:
- if: not slots.final_confirmation
then:
- action: utter_transfer_cancelled
next: END
- else: transfer_successful
- action: utter_transfer_complete
id: transfer_successful

Testing your Custom Action

Action Required

Double check that in the file endpoints.yml, that the section for your custom action server is uncommented:

endpoints.yml
action_endpoint:
actions_module: actions

In the terminal, stop and restart the inspector by running rasa inspect. When you reach the "check_funds" step in your flow, Rasa will call the custom action action_check_sufficient_funds. We have hardcoded the user's balance to be 1000, so if you try to send more, the assistant will tell you that you don't have enough funds in your account.

At this point you have experience using some of the key concepts involved in building with Rasa. Congratulations!