Business Logic with Flows
Flows in Rasa offer a structured way to design conversation-driven business logic. This page details the rules for effectively using and managing flows within Rasa.
New in 3.7
Flows are part of Rasa's new Conversational AI with Language Models (CALM) approach
and available starting with version 3.7.0
.
Overview
In CALM, the business logic of your AI assistant is implemented as a set of flows. Each flow describes the logical steps your AI assistant uses to complete a task. It describes the information you need from the user, data you need to retrieve from an API or a database, and branching logic based on the information collected.
A flow in Rasa only describes the logic your assistant follows, not all the potential paths conversations can take. If you're used to designing AI assistants by creating flow charts of how conversations should go, you'll see that flows in Rasa are much simpler. Check out Rasa Studio's Flow Builder to build flows with a web interface.
To get familiar with how flows work, follow the tutorial. This page provides a reference of the format and properties of flows.
Hello World
A Flow is defined using YAML syntax. Here is an example of a simple flow:
Flow Properties
A flow is defined using the following properties:
Flow ID
The id is required and uniquely identifies the flow among all flows. It allows only alphanumeric characters, underscores, and hyphens, with the restriction that the first character cannot be a hyphen.
Name
The name
field is an optional human readable name for the flow.
Description
The description
field is a summary of the flow. It is required, and should
describe what the flow does for the user.
Writing a clear description is important, because it is used by the
Dialogue Understanding component to decide when
to start this flow.
See Starting Flows for more details.
Additionally, for guidelines on how to write concise and clear descriptions
see the section provided here.
Always Include in Prompt
If always_include_in_prompt
field is set to true
and the flow guard
defined in the if
field evaluates to true
, the flow will be
always be included in the prompt
NLU Trigger property
The nlu_trigger
field is used to add intents that can start the flow.
If property
The if
field is used to add flow guards.
Steps
The steps
field is required and lists the flow steps.
There are six types of steps:
- action step: a custom action or utterance action run by the flow
- collect step: a question asked to the user to fill a slot
- call step: a step to call another flow
- link step: a step to link another flow after this flow is finished
- set slots step: a step to set slots
- noop step: a step to create conditions without necessarily running an action, uttering a response, collecting a slot or linking / calling another flow in that step itself.
All steps share these common properties:
Id Property
The id
field is an optional unique identifier for each step. It is used to
reference the step in the next
field of other steps.
Next Property
The next
field specifies which step is executed after this one.
If it is omitted, the following step in the list is the next one.
To link a specific step, you can use the next step's id
:
You can also create a nested structure by listing steps under the next
field:
This is sometimes easier to read, especially when using conditions to create branching logic. For example:
Depending on the user's input value for age, this example show the flow proceeding to different steps.
Note the age
slot must be prefixed by the slots.
namespace to be accessible in the condition.
For namespaces, navigate to the Namespaces section.
When a condition is met that leads to next: END
, the flow will complete without executing further steps.
Step Types
Every step in a flow has a type. The type determines what the step does and what properties it supports. A step must have exactly one of they following keys:
action
collect
link
call
set_slots
noop
Action
A step with the key action: action_do_something
instructs your assistant to execute action_do_something
and then proceed to the next step. It will not wait for user input.
The value of the action
key is either the name of a custom action:
Or the name of a response defined in your domain:
Collect
A step with a collect
key instructs your assistant to request
information from the user to fill a slot. For example:
Your assistant will not proceed to the next step in the flow until the slot
account_type
has been filled.
See the tutorial for more information
about slot filling and defining slots in your domain file.
Instead of a response
you can also define a custom action called action_ask_recipient
to
phrase the question along with, for example, some buttons to the user.
Make sure to add the custom action to your domain file.
info
You can define either a response
or a custom action
for your collect step.
It is not possible to define both.
A validation error will be thrown by Rasa if both are defined.
Slot Descriptions
An optional description
field can be added to the collect
step to guide the
language model in extracting slot values.
info
The description field can be used to perform slot validation:
Always Asking Questions
By default, a collect
step is skipped if the corresponding slot is already filled.
If a collect
step should always be asked, no matter if the underlying slot
is already filled, you can set ask_before_filling: true
on the collect
step:
If the "final_confirmation" slot is already filled, the assistant will clear it and proceed to ask the collect
step,
then fill the slot again. This ensures the confirmation collect
step is always asked.
Resetting slots at the End of a Flow
By default, all slots filled via collect
steps are reset when a flow completes.
Once the flow ends, the slot's value is either reset to null
or to the
slot's initial value (if provided in the domain file under slots
).
If you want to retain the value of a slot after the flow completes,
set the reset_after_flow_ends
property to false
. For example:
In coexistence mode, this behavior has to be enforced by
annotating the slot definition with the property shared_for_coexistence: True
.
collect
step
Using a different response key for the By default, Rasa will look for a response called utter_ask_{slot_name}
to execute a collect
step.
You can use a response with a different key by adding an utter
property to the step.
For example:
collect
step
Using an action to ask for information in Instead of using a templated response for the collect
step you can also use a custom action.
This is useful if you, for example, want to display available values for the slot fetched from a database as buttons.
Rasa will look for an action called action_ask_{slot_name}
to execute a collect
step.
The custom action needs to strictly follow the specified naming convention.
Make sure to add the custom action action_ask_{slot_name}
to your domain file.
You don't need to update the collect step itself to use the custom action. The collect step inside the flow stays the same, for example,
info
You can define either a response
or a custom action
for your collect step.
It is not allowed to define both.
A validation error will be thrown by Rasa if both are defined.
Slot validation
You can define slot validation rules directly in your flow yaml file by adding a rejections
property to any
collect
step. The rejections
section is a list of mappings. Each mapping must have
if
and utter
mandatory properties:
- the
if
property is a condition written in natural language and evaluated using the pypred library. In the condition, you can only use the slot name that is collected in this step. At the moment, using other slots is not supported. - the
utter
property is the name of the response the assistant will send if the condition evaluates toTrue
.
Here is an example:
When validation fails, your assistant will automatically try to collect the information again. The assistant will repeatedly ask for the slot until the value is not rejected.
If the predicate defined in the if
property is invalid, the assistant will log an error and respond with the
utter_internal_error_rasa
response which by default is Sorry, I'm having trouble understanding you right now.
Please try again later.
You can override the text message for utter_internal_error_rasa
by adding this response with
the custom text in your domain file.
note
For more complex validation logic, you can also define slot validation in a custom action.
Note this custom action must follow this naming convention: validate_{slot_name}
.
Link
A link
step is used to connect flows. Links can only be used as the last step in a flow. When a link
step is reached,
the current flow is ended and the targeted flow is started. You can define a link
step as:
It is not possible to add any other property like an action
or a next
to a link
step. Doing so, will result in an error during flow validation.
It is possible to link from a flow to the Human Handoff conversation repair pattern. This enables catching a scenario where the conversation should be handed over to a human agent. It is not possible to link from a flow to any of the other conversation repair pattern
Call
New in 3.8.0
The call
step is available starting with version 3.8.0
.
You can use a call
step inside a flow (parent flow) to embed another flow (child flow). When the execution reaches a
call
step, CALM starts the child flow. Once the child flow is complete,
the execution continues with the parent flow.
Calling other flows helps split up and reuse functionality. It allows you to define a flow once and use it in multiple other flows. Long flows can be split into smaller ones, making them easier to understand and maintain.
You can define a call
step as:
The call step must reference an existing flow and the child flow can be defined in the same file as the one containing the parent flow or a different file.
call
step
Behavior of the The call
step is designed to behave as if the child flow is part of
the parent flow. Hence, the following properties come out of the box:
- If the child flow has a
next: END
in any step, the control will get passed back to the parent flow, and the next logical step will be executed. - Slots of the child flow can be filled upfront, even before the child
flow is started. The
collect
steps in a child flow behave as if they were directly part of the parent flow. - Slots of the child flow can be corrected once they are filled and the control is still inside the child or the parent flow. So, even after the child flow is complete, the slots can be corrected as long as the parent flow is still active.
- Slots of the parent flow will not be reset when the child flow is activated. The child flow can access and modify slots of the parent flow.
- Slots of a child flow will not be reset when the control comes back to
the parent flow. Instead, they will be reset together with the slots of the
parent flow once that ends (unless
reset_after_flow_ends
is set toFalse
for any of the slots). - If the
CancelFlow()
command is triggered inside the the child flow, the parent flow is also cancelled.
note
To prevent the child flow from getting triggered directly by a user message, you can add a flow guard to the child flow:
In the above example, the child_flow
will never be triggered directly by a user message but only when the parent flow calls it.
call
step
Constraints on the Calling other flows has the following constraints by design:
- A child flow can not use the
link
step because alink
step is meant to always terminate the previous flow which would contradict with the behaviour ofcall
step where the control should always be passed to the parent flow. - Patterns can not use the call step.
Recommendation on using link
v/s call
If the use case demands a flow to be initiated as a follow-up to another flow,
then a link
step is better suited to accomplish the connection between
the two flows. However, if a flow needs to behave as if it was part of
another larger flow and more steps need to be executed inside the larger flow
after the child flow has completed, then call
step should be used.
Set Slots
A set_slots
step is used to set one or more slots. For example:
Normally, slots are either set from user input (using a collect
step) or
by fetching information from another system (using a custom action).
A set_slot
is mostly useful to unset a slot value.
For example, if a user asks to transfer more money than they have available in their account,
you might want to inform them. Just reset the amount
slot rather than ending the flow.
Noop
A noop
step can be combined with the next
property to create a
conditional branch in a flow without necessarily
running an action, uttering a response, collecting a slot or linking / calling another flow in that step itself.
For example:
It's always necessary to add the next
property to a noop
step. Otherwise, validation of flows would fail during training.
Examples
A basic flow with branching
The example shows a flow that branches based on the age
slot collected from a user message.
Linking multiple flows
This example demonstrates how the link
step in flows enables the start of
another flow as a follow-up flow. Specifically, the flow collect_feedback
is
initiated as a follow up flow after transfer_money
is terminated at the link
step.
Embedding a flow inside another flow
Let's assume a financial assistant needs to serve two use cases:
- Transferring money to another individual
- Adding a new recipient for transferring money
It's possible that an end user talking to the assistant wants to initiate a money transfer
to an existing recipient, hence not needing the second use case. However, it is also possible
that the user wants to transfer money to a new recipient in which case both the use cases need
to be combined. This is exactly where a call
step lets you accomplish both the
possibilities without needing to create redundant flows. To accomplish the above use cases,
you can leverage the call
step in your flows as shown below:
For the above flow structure, the LLM's prompt would contain the following flow definition:
Each of the above flows are quite self-contained, accomplishing a single purpose and reused effectively to accomplish combinations of multiple use cases in a single conversation. This enhances the modularity and maintainability of flows. Also, note that no slot of a child flow is overlapping with slot of its parent flow in terms of the information they capture. This is important for the command generator's LLM to not get confused at filling such slots.
Optionally ask for information
Imagine a dress shopping AI assistant created to help users find and purchase dresses. This AI assistant includes two types of features: primary features (i.e., dress type, size) and optional features (i.e., color, material, price range, etc.). The assistant should ask for the primary features and avoid asking for the optional features, unless the user specifically requests them. This approach is key to avoid asking too many questions and overwhelming the user.
You can achieve this by setting the ask_before_filling
property to false
on the collect
step and setting an
initial_value
for the slot in the domain file.
With ask_before_filling
set to false
and given that the slots (dress_color
and dress_material
) already have initial values,
the corresponding collect
steps will not be asked. Instead, the assistant will move to the next step.
If the user explicitly provides a value for a slot, this new value will overwrite the initial one.