Using Variables in Responses#
You can use variables to insert information into responses. Within a response, a variable is enclosed in curly brackets. For example, see the variable name below:
- text: "Hey, {name}. How are you?"
When the utter_greet response is used, Rasa automatically fills in the variable with the value found in the slot called name. If such a slot doesn't exist or is empty, the variable gets filled with None.
Another way to fill in a variable is within a custom action. In your custom action code, you can supply values to a response to fill in specific variables. If you're using the Rasa SDK for your action server, you can pass a value for the variable as a keyword argument to dispatcher.utter_message:
dispatcher.utter_message(
template="utter_greet",
If you use a different custom action server, supply the values by adding extra parameters to the responses your server returns:
"template":"utter_greet",
You can make your assistant's replies more interesting if you provide multiple response variations to choose from for a given response name:
- text: "Hey, {name}. How are you?"
- text: "Hey, {name}. How is your day going?"
In this example, when utter_greet gets predicted as the next action, Rasa will randomly pick one of the two response variations to use.
You can now set an ID for any response. This is useful when you want to use the NLG server to generate the response.
Type for ID is string.
Example of response variations with ID:
text: "Hey, {name}. How are you?"
text: "Hey, {name}. How is your day going?"
Slots and Conversation Behavior#
You can specify whether or not a slot influences the conversation with the influence_conversation property.
If you want to store information in a slot without it influencing the conversation, set influence_conversation: false when defining your slot.
The following example defines a slot age which will store information about the user's age, but which will not influence the flow of the conversation. This means that the assistant will ignore the value of the slot each time it predicts the next action.
influence_conversation: false
When defining a slot, if you leave out influence_conversation or set it to true, that slot will influence the next action prediction, unless it has slot type any. The way the slot influences the conversation will depend on its slot type.
The following example defines a slot home_city that influences the conversation. A text slot will influence the assistant's behavior depending on whether the slot has a value. The specific value of a text slot (e.g. Bangalore or New York or Hong Kong) doesn't make any difference.
influence_conversation: true
As an example, consider the two inputs "What is the weather like?" and "What is the weather like in Bangalore?" The conversation should diverge based on whether the home_city slot was set automatically by the NLU. If the slot is already set, the bot can predict the action_forecast action. If the slot is not set, it needs to get the home_city information before it is able to predict the weather.
Storing true or false values.
If influence_conversation is set to true, the assistant's behavior will change depending on whether the slot is empty, set to true or set to false. Note that an empty bool slot influences the conversation differently than if the slot was set to false.
Storing slots which can take one of N values.
If influence_conversation is set to true, the assistant's behavior will change depending on the concrete value of the slot. This means the assistant's behavior is different depending on whether the slot in the above example has the value low, medium, or high.
A default value __other__ is automatically added to the user-defined values. All values encountered which are not explicitly defined in the slot's values are mapped to __other__. __other__ should not be used as a user-defined value; if it is, it will still behave as the default to which all unseen values are mapped.
Storing real numbers.
max_value=1.0, min_value=0.0
If influence_conversation is set to true, the assistant's behavior will change depending on the value of the slot. If the value is between min_value and max_value, the specific value of the number is used. All values below min_value will be treated as min_value, and all values above max_value will be treated as max_value. Hence, if max_value is set to 1, there is no difference between the slot values 2 and 3.5.
Storing arbitrary values (they can be of any type, such as dictionaries or lists).
Slots of type any are always ignored during conversations. The property influence_conversation cannot be set to true for this slot type. If you want to store a custom data structure which should influence the conversation, use a custom slot type.
Maybe your restaurant booking system can only handle bookings for up to 6 people. In this case you want the value of the slot to influence the next selected action (and not just whether it's been specified). You can do this by defining a custom slot class.
The code below defines a custom slot class called NumberOfPeopleSlot. The featurization defines how the value of this slot gets converted to a vector so Rasa machine learning model can deal with it. The NumberOfPeopleSlot has three possible “values”, which can be represented with a vector of length 2.
from rasa.shared.core.slots import Slot
class NumberOfPeopleSlot(Slot):
def feature_dimensionality(self):
def as_feature(self):
r = [0.0] * self.feature_dimensionality()
You can implement a custom slot class as an independent python module, separate from custom action code. Save the code for your custom slot in a directory alongside an empty file called "__init__.py" so that it will be recognized as a python module. You can then refer to the custom slot class by it's module path.
For example, say you have saved the code above in "addons/my_custom_slots.py", a directory relative to your bot project:
│ └── my_custom_slots.py
Your custom slot type's module path is then addons.my_custom_slots.NumberOfPeopleSlot. Use the module path to refer to the custom slot type in your domain file:
type: addons.my_custom_slots.NumberOfPeopleSlot
influence_conversation: true
Now that your custom slot class can be used by Rasa, add training stories that diverge based on the value of the people slot. You could write one story for the case where people has a value between 1 and 6, and one for a value greater than six. You can choose any value within these ranges to put in your stories, since they are all featurized the same way (see the featurization table above).
- story: collecting table info
# ... other story steps
- action: action_book_table
- story: too many people at the table
# ... other story steps
- action: action_explain_table_limit
As of 3.0, slot mappings are defined in the slots section of the domain. This change removes the implicit mechanism of setting slots via auto-fill and replaces it with a new explicit mechanism of setting slots after every user message. You will need to explicitly define slot mappings for each slot in the slots section of domain.yml. If you are migrating from an earlier version, please read through the migration guide to update your assistant.
Rasa comes with four predefined mappings to fill slots based on the latest user message.
In addition to the predefined mappings, you can define custom slot mappings. All custom slot mappings should contain a mapping of type custom.
Slot mappings are specified as a YAML list of dictionaries under the key mappings in the domain file. Slot mappings are prioritized in the order they are listed in the domain. The first slot mapping found to apply will be used to fill the slot.
The default behavior is for slot mappings to apply after every user message, regardless of the dialogue context. To make a slot mapping apply only within the context of a form see Mapping Conditions. There is one additional default limitation on applying from_entity slot mappings in the context of a form; see unique from_entity mapping matching for details.
Note that you can also define lists of intents for the optional parameters intent and not_intent.
The from_entity slot mapping fills slots based on extracted entities. The following parameters are required:
The following parameters are optional and can be used to further specify when the mapping applies:
not_intent: excluded_intent
There is an intentional limitation on applying from_entity slot mappings in the context of a form. When a form is active, a from_entity slot mapping will be applied only if one or more of the following conditions are met:
This limitation exists to prevent a form from filling multiple required slots with the same extracted entity value.
For example, in the example below, an entity date uniquely sets the slot arrival_date, an entity city with a role from uniquely sets the slot departure_city and an entity city with a role to uniquely sets the slot arrival_city, therefore they can be used to fit corresponding slots even if these slots were not requested. However, entity city without a role can fill both departure_city and arrival_city slots, depending which one is requested, so if an entity city is extracted when slot arrival_date is requested, it'll be ignored by the form.
Note that the unique from_entity mapping constraint will not prevent filling slots which are not in the active form's required_slots; those mappings will apply as usual, regardless of the uniqueness of the mapping. To limit applicability of a slot mapping to a specific form, see Mapping Conditions.
The from_text mapping will use the text of the last user utterance to fill the slot slot_name. If intent_name is None, the slot will be filled regardless of intent name. Otherwise, the slot will only be filled if the user's intent is intent_name.
The slot mapping will not apply if the intent of the message is excluded_intent.
not_intent: excluded_intent
To maintain the 2.x form behavior when using from_text slot mappings, you must use mapping conditions, where both active_loop and requested_slot keys are defined.
The from_intent mapping will fill slot slot_name with value my_value if user intent is intent_name. If you choose not to specify the parameter intent, the slot mapping will apply regardless of the intent of the message as long as the intent is not listed under not_intent parameter.
The following parameter is required:
The following parameters are optional and can be used to further specify when the mapping applies:
Note that if you choose not to define the parameter intent, the slot mapping will apply regardless of the intent of the message as long as the intent is not listed under the not_intent parameter.
not_intent: excluded_intent
The from_trigger_intent mapping will fill slot slot_name with value my_value if a form is activated by a user message with intent intent_name. The slot mapping will not apply if the intent of the message is excluded_intent.
- type: from_trigger_intent
not_intent: excluded_intent
To apply a slot mapping only within the context of a form, specify the name of the form in the conditions key of a slot mapping. Conditions list the form name(s) for which the mapping is applicable in the active_loop key.
Slot mappings can now specify null as the value of active_loop to indicate that the slot should only be filled when no form is active. Note that requested_slot cannot be used in conjunction with active_loop: null.
Conditions can also include the name of the requested_slot. If requested_slot is not mentioned, then the slot will be set if relevant information is extracted, regardless of which slot is being requested by the form.
- active_loop: your_form
requested_slot: slot_name
- active_loop: another_form
If conditions are not included in a slot mapping, the slot mapping will be applicable regardless of whether any form is active. As long as a slot is listed in a form's required_slots, the form will prompt for the slot if it is empty when the form is activated.
Session configuration#
A conversation session represents the dialogue between the assistant and the user. Conversation sessions can begin in three ways:
the user begins the conversation with the assistant,
the user sends their first message after a configurable period of inactivity, or
a manual session start is triggered with the /session_start intent message.
You can define the period of inactivity after which a new conversation session is triggered in the domain under the session_config key.
Available parameters are:
The default session configuration looks as follows:
session_expiration_time: 60 # value in minutes, 0 means infinitely long
carry_over_slots_to_new_session: true # set to false to forget slots between sessions
This means that if a user sends their first message after 60 minutes of inactivity, a new conversation session is triggered, and that any existing slots are carried over into the new session. Setting the value of session_expiration_time to 0 means that sessions will not end (note that the action_session_start action will still be triggered at the very beginning of conversations).
A session start triggers the default action action_session_start. Its default implementation moves all existing slots into the new session. Note that all conversations begin with an action_session_start. Overriding this action could for instance be used to initialize the tracker with slots from an external API call, or to start the conversation with a bot message. The docs on Customizing the session start action shows you how to do that.
The config key in the domain file maintains the store_entities_as_slots parameter. This parameter is used only in the context of reading stories and turning them into trackers. If the parameter is set to True, this will result in slots being implicitly set from entities if applicable entities are present in the story. When an entity matches the from_entity slot mapping, store_entities_as_slots defines whether the entity value should be placed in that slot. Therefore, this parameter skips adding an explicit slot_was_set step manually in the story. By default, this behaviour is switched on.
You can turn off this functionality by setting the store_entities_as_slots parameter to false:
store_entities_as_slots: false
If you're looking for information on the config.yml file, check out the docs on Model Configuration.
A story is a representation of a conversation between a user and an AI assistant, converted into a specific format where user inputs are expressed as intents (and entities when necessary), while the assistant's responses and actions are expressed as action names.
Here's an example of a dialogue in the Rasa story format:
- story: collect restaurant booking info # name of the story - just for debugging
- intent: greet # user message with no entities
- action: utter_ask_howcanhelp
- intent: inform # user message with entities
- action: utter_on_it # action that the bot should execute
- action: utter_ask_cuisine
- action: utter_ask_num_people
While writing stories, you do not have to deal with the specific contents of the messages that the users send. Instead, you can take advantage of the output from the NLU pipeline, which lets you use just the combination of an intent and entities to refer to all the possible messages the users can send to mean the same thing.
It is important to include the entities here as well because the policies learn to predict the next action based on a combination of both the intent and entities (you can, however, change this behavior using the use_entities attribute).
All actions executed by the bot, including responses are listed in stories under the action key.
You can use a response from your domain as an action by listing it as one in a story. Similarly, you can indicate that a story should call a custom action by including the name of the custom action from the actions list in your domain.
During training, Rasa does not call the action server. This means that your assistant's dialogue management model doesn't know which events a custom action will return.
Because of this, events such as setting a slot or activating/deactivating a form have to be explicitly written out as part of the stories. For more info, see the documentation on Events.
Slot events are written under slot_was_set in a story. If this slot is set inside a custom action, add the slot_was_set event immediately following the custom action call. If your custom action resets a slot value to None, the corresponding event for that would look like this:
- story: set slot to none
# ... other story steps
- action: my_custom_action
There are three kinds of events that need to be kept in mind while dealing with forms in stories.
A form action event (e.g. - action: restaurant_form) is used in the beginning when first starting a form, and also while resuming the form action when the form is already active.
A form activation event (e.g. - active_loop: restaurant_form) is used right after the first form action event.
A form deactivation event (e.g. - active_loop: null), which is used to deactivate the form.
In order to get around the pitfall of forgetting to add events, the recommended way to write these stories is to use interactive learning.
Custom Output Payloads#
You can send any arbitrary output to the output channel using the custom key. The output channel receives the object stored under the custom key as a JSON payload.
Here's an example of how to send a date picker to the Slack Output Channel:
text: "Make a bet on when the world will end:"
initial_date: '2019-05-21'
The requested_slot slot#
The slot requested_slot is automatically added to the domain as a slot of type text. The value of the requested_slot will be ignored during conversations. If you want to change this behavior, you need to add the requested_slot to your domain file as a categorical slot with influence_conversation set to true. You might want to do this if you want to handle your unhappy paths differently, depending on what slot is currently being asked from the user. For example, if your users respond to one of the bot's questions with another question, like why do you need to know that? The response to this explain intent depends on where we are in the story. In the restaurant case, your stories would look something like this:
- story: explain cuisine slot
- intent: request_restaurant
- action: restaurant_form
- active_loop: restaurant
- requested_slot: cuisine
- action: utter_explain_cuisine
- action: restaurant_form
- story: explain num_people slot
- intent: request_restaurant
- action: restaurant_form
- active_loop: restaurant
- requested_slot: cuisine
- requested_slot: num_people
- action: utter_explain_num_people
- action: restaurant_form
Again, it is strongly recommended that you use interactive learning to build these stories.
Validating Form Input#
After extracting a slot value from user input, you can validate the extracted slots. By default Rasa Open Source only validates if any slot was filled after requesting a slot.
Forms no longer raise ActionExecutionRejection if nothing is extracted from the user’s utterance for any of the required slots.
You can implement a Custom Action validate_
- validate_restaurant_form
When the form is executed it will run your custom action.
This custom action can extend FormValidationAction class to simplify
the process of validating extracted slots. In this case, you need to write functions
named validate_
The following example shows the implementation of a custom action which validates that the slot named cuisine is valid.
from typing import Text, List, Any, Dict
from rasa_sdk import Tracker, FormValidationAction
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk.types import DomainDict
class ValidateRestaurantForm(FormValidationAction):
def name(self) -> Text:
return "validate_restaurant_form"
def cuisine_db() -> List[Text]:
"""Database of supported cuisines"""
return ["caribbean", "chinese", "french"]
def validate_cuisine(
dispatcher: CollectingDispatcher,
) -> Dict[Text, Any]:
"""Validate cuisine value."""
if slot_value.lower() in self.cuisine_db():
return {"cuisine": slot_value}
return {"cuisine": None}
You can also extend the Action class and retrieve extracted slots with tracker.slots_to_validate to fully customize the validation process.
Dynamic Form Behavior#
By default, Rasa will ask for the next empty slot from the slots listed for your form in the domain file. If you use custom slot mappings and the FormValidationAction, it will ask for the first empty slot returned by the required_slots method. If all slots in required_slots are filled the form will be deactivated.
You can update the required slots of your form dynamically. This is, for example, useful when you need to fill additional slots based on how a previous slot was filled or when you want to change the order in which slots are requested.
If you are using the Rasa SDK, we strongly recommend that you use the FormValidationAction and
override required_slots to fit your dynamic behavior. You must implement
a method extract_
from typing import Text, List, Optional
from rasa_sdk.forms import FormValidationAction
class ValidateRestaurantForm(FormValidationAction):
def name(self) -> Text:
return "validate_restaurant_form"
async def required_slots(
domain_slots: List[Text],
dispatcher: "CollectingDispatcher",
domain: "DomainDict",
additional_slots = ["outdoor_seating"]
if tracker.slots.get("outdoor_seating") is True:
additional_slots.append("shade_or_sun")
return additional_slots + domain_slots
If conversely, you want to remove a slot from the form's required_slots defined in the domain file under certain conditions, you should copy the domain_slots over to a new variable and apply changes to that new variable instead of directly modifying domain_slots. Directly modifying domain_slots can cause unexpected behaviour. For example:
from typing import Text, List, Optional
from rasa_sdk.forms import FormValidationAction
class ValidateBookingForm(FormValidationAction):
def name(self) -> Text:
return "validate_booking_form"
async def required_slots(
domain_slots: List[Text],
dispatcher: "CollectingDispatcher",
domain: "DomainDict",
updated_slots = domain_slots.copy()
if tracker.slots.get("existing_customer") is True:
updated_slots.remove("email_address")
Head Office Planetmoto
The Belleza Office Tower Lt. 7 Unit 1
Jln. Letjen Soepono No. 34, Arteri Permata Hijau
Grogol Utara, Kebayoran Lama, Jakarta Selatan
In Rasa, your domain defines the universe in which your assistant operates. Specifically, it lists:
If you are building an NLU-based assistant, refer to the Domain documentation to see how intents, entities, slot mappings, and slot featurization can be configured in your domain.
Using a Custom Action to Ask For the Next Slot#
As soon as the form determines which slot has to be filled next by the user, it will
execute the action utter_ask_
from typing import Dict, Text, List
from rasa_sdk import Tracker
from rasa_sdk.events import EventType
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk import Action
class AskForSlotAction(Action):
def name(self) -> Text:
return "action_ask_cuisine"
self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict
) -> List[EventType]:
dispatcher.utter_message(text="What cuisine?")
If there is more than one asking option for the slot, Rasa prioritizes in the following order:
Calling Responses as Actions#
If the name of the response starts with utter_, the response can directly be used as an action, without being listed in the actions section of your domain. You would add the response to the domain:
- text: "Hey! How are you?"
You can use that same response as an action in your stories:
- action: utter_greet
When the utter_greet action runs, it will send the message from the response back to the user.
If you want to change the text, or any other part of the response, you need to retrain the assistant before these changes will be picked up.