Skip to main content

Patterns

Configurations

Default Behavior

Rasa ships a default behavior for every conversation repair case that works out-of-the-box. Each case is handled through a pattern which is a special flow designed specifically to handle the case:

  • pattern_continue_interrupted for digressions.
  • pattern_correction for corrections.
  • pattern_cancel_flow for cancellations.
  • pattern_skip_question for skipping collect steps.
  • pattern_chitchat for chitchat.
  • pattern_completed for completion.
  • pattern_clarification for clarification.
  • pattern_internal_error for internal errors.
  • pattern_cannot_handle for cannot handle.
  • pattern_human_handoff for human handoff.
  • pattern_session_start for procatively starting a session by the assistant.

Voice-specific patterns:

  • pattern_repeat_bot_messages for when the user asks the assistant to repeat an utterance.
  • pattern_user_silence for handling user silences in voice assistants.

The syntax for each of these flows is the same as any other flow.

info

Conversation repair cases are expected to work out-of-the-box. This means that if the default behaviour is good enough for the assistant's use case, then the flow corresponding to the pattern handling the repair case is not needed in the assistant's project directory.

info

The Contextual Response Rephraser helps the default responses from patterns to fit in naturally with the context of the conversations.

Modifying default behaviour

It is possible to override the default behaviour of each conversation repair case by creating a flow with the same name as that of the pattern used to handle the corresponding case, like pattern_correction. If the pattern uses a default action which needs to be modified, you can override the implementation of the default action by implementing a new custom action and use that custom action in the flow.

It is possible to add a link step from a pattern to a flow, except for pattern_internal_error, where link steps are not allowed.

Additionally, you can link a pattern to the pattern_human_handoff.

info

Make sure the assistant is re-trained after the modification is completed.

info

Since most of these patterns interrupt another flow, they should be kept short and simple.

Sample Configuration

Modify Rasa's response when a flow concludes:

flows.yml
flows:
pattern_completed:
description: Completion of a user's flow
steps:
- action: utter_can_do_something_else
domain.yml
responses:
utter_can_do_something_else:
- text: "Is there anything else I can assist you with?"

Common Modifications

Here are some common modifications to the default behavior.

Requiring Confirmation

You can change the default implementation for a correction and require a confirmation from the user before a slot is updated, e.g. this would result in a conversation like this:

User: I want to send some money to Joe

Bot: How much money do you want to send?

User: 50$

Bot: Do you want to send 50$ to Joe? (Yes/No)

User: Oh wait!! I meant to say to John, not Joe!

Bot:

Do you want to update the recipient to John? (Yes/No)

User: Yes!

Bot: Updated recipient to John

Bot: Do you want to send 50$ to John? (Yes/No)

User: ...

A common correction scenario

To achieve the above confirmation, create a flow named pattern_correction which is defined as follows:

flows.yml
flows:
pattern_correction:
description: Confirm a previous correction of a slot value.
steps:
- noop: true
next:
- if: context.is_reset_only
then:
- action: action_correct_flow_slot
next: END
- else: confirm_first
- id: confirm_first
collect: confirm_slot_correction
next:
- if: not slots.confirm_slot_correction
then:
- action: utter_not_corrected_previous_input
next: END
- else:
- action: action_correct_flow_slot
- action: utter_corrected_previous_input
next: END

Also make sure to add the used responses and slots to your domain file:

domain.yml
slots:
confirm_slot_correction:
type: bool

responses:
utter_ask_confirm_slot_correction:
- text: "Do you want to update the {{ context.corrected_slots.keys()|join(', ') }}?"
buttons:
- payload: "yes"
title: "Yes"
- payload: "no"
title: "No, please keep the previous information"
metadata:
rephrase: True
template: jinja

utter_not_corrected_previous_input:
- text: "Ok, I did not correct the previous input."
metadata:
rephrase: True

Implementing a Human Handoff

Currently, the default behaviour for a human handoff is to inform the user that the assistant cannot help with the request. However, in scenarios where customer service is available, implementing a human handoff becomes relevant. You can implement a human handoff by writing a custom action and overriding the flow named pattern_human_handoff:

flows.yml
flows:
pattern_human_handoff:
description: Human handoff implementation
steps:
- collect: confirm_human_handoff
next:
- if: slots.confirm_human_handoff
then:
- action: action_human_handoff
next: END
- else:
- action: utter_human_handoff_cancelled
next: END

Also make sure to add the used actions, responses and slots to your domain file:

domain.yml
slots:
confirm_human_handoff:
type: bool
mappings:
- type: custom

actions:
- action: action_human_handoff

responses:
utter_ask_confirm_human_handoff:
- text: "Do you want to be connected to a human agent?"
buttons:
- payload: "yes"
title: "Yes"
- payload: "no"
title: "No"
utter_human_handoff_cancelled:
- text: "Ok, I understand you don't want to be connected to a human agent. Is there something else I can help you with?"
metadata:
rephrase: True

React dependent on the current flow

You can change a pattern's behaviour depending on the flow that was interrupted. This can be done by using the context object in the if condition of a pattern:

flows.yml
flows:
pattern_cancel_flow:
description: A meta flow that's started when a flow is cancelled.

steps:
- id: decide_cancel_step
noop:
- if: context.canceled_name = "transfer money"
then: inform_user
- else: cancel_flow # skips the inform step
- id: inform_user
action: utter_flow_cancelled_rasa
next: cancel_flow
- id: cancel_flow
action: action_cancel_flow

In the above example, the inform_user step is only used if the flow that was interrupted is called transfer_money.

Free form generation for chitchat

By default, chitchat operates via action_trigger_chitchat that invokes the IntentlessPolicy to provide a relevant predefined response.

To switch to free-form generated responses, override the default behaviour of pattern_chitchat by creating a flow named pattern_chitchat which is defined as follows:

flows.yml
flows:
pattern_chitchat:
description: handle interactions with the user that are not task-oriented
name: pattern chitchat
steps:
- action: utter_free_chitchat_response
warning

Free-form responses will be generated using an LLM. There's a possibility that the assistant could answer queries outside of the intended domain.

Disabling chitchat

By default, if the Intentless Policy is not configured, the assistant defaults to the pattern_cannot_handle, effectively restricting chitchat by informing the user that the request cannot be processed.

To completely restrict casual conversation, override the default behaviour of pattern_chitchat by creating a flow named pattern_chitchat. Instead of the usual behavior that triggers action_trigger_chitchat, configure it to use a predefined response:

flows.yml
flows:
pattern_chitchat:
description: |
Handle interactions with the user that
are not task-oriented using a predefined response
name: pattern chitchat
steps:
- action: utter_cannot_handle # or any other response template

Skipping clarification

By default, clarification will check on the users intention by asking the user to choose from a list of flows. In some cases, it may be desirable to skip clarification and move directly to starting a flow by adding a link step directly to that flow.

flows.yml
flows:
pattern_clarification:
description: Conversation repair flow for handling ambiguous requests that could match multiple flows
name: pattern clarification
steps:
- action: action_clarify_flows
next:
- if: context.names contains "<name of a flow>"
then:
- link: <name_of_a_flow>
- else: clarify_options
- id: clarify_options
action: utter_clarification_options_rasa

Preventing multiple Clarifications

By default, clarification will continue to check on the users intentions regardless of the number of times it has asked. This can be avoided by counting the number of clarification requests and linking to the human handoff pattern if this count reaches some threshold.

flows.yml
flows:
pattern_clarification:
description: Conversation repair flow for handling ambiguous requests that could match multiple flows
name: pattern clarification
steps:
- action: action_clarify_flows
- action: action_increase_clarification_count
next:
- if: slots.clarification_count > CLARIFICATION_LIMIT
then:
- link: pattern_human_handoff
- else: clarify_options
- id: clarify_options
action: utter_clarification_options_rasa

This would require the custom action action_increase_clarification_count to be implemented and added to the domain.yml along with the clarification_count slot.

Common Voice-specific Pattern Modifications

Handling Call Start and Call Metadata

New in 3.11

We have unified the call handling patterns across Voice Channel Connectors, all voice channels handle call starts, ends and metadata in a similar manner.

The assistant will receive the message /session_start when the call is picked up along with the call metadata. This intent triggers the Session Start pattern. Here's a customized pattern that sends utter_greet when the call connects:

flows.yml
flows:
pattern_session_start:
description: Flow for starting the conversation
name: pattern session start
nlu_trigger:
- intent: session_start
steps:
- action: utter_greet

The following call metadata is received for Twilio:

  • call_id is the unique call identifier from Twilio (CallSid parameter as sent by Twilio Voice)
  • user_phone is the phone number of the user (Caller)
  • bot_phone is the phone number of the bot (Called)
  • direction is the call direction. It can be either inbound or outbound

Action action_session_start is triggered at the beginning of each Rasa session and it can be used to set certain slots based on this metadata. These slots can be used in your utterances for a dynamic greeting. Here is an example:

from rasa_sdk import Action, Tracker
from rasa_sdk.events import SlotSet
from rasa_sdk.executor import CollectingDispatcher
import logging

logger = logging.getLogger(__name__)

class ActionSessionStart(Action):

def name(self) -> str:
return "action_session_start"

def run(self, dispatcher: CollectingDispatcher, tracker: Tracker,
domain: dict) -> list:
# get the call metadata from the tracker
metadata = tracker.get_slot("session_started_metadata")
logger.info(f"🤙 action_session_start's metadata: {metadata}")

# set appropriate slots
if metadata:
return [
SlotSet("user_phone", metadata.get("user_phone")),
SlotSet("bot_phone", metadata.get("bot_phone")),
]

return []

Handling the End of a Call

Call can be ended by the user or by the assistant.

  • When the call is ended by the user /session_end message is received by the assistant along with a SessionEnded event to the conversation.

  • Assistant flows can use the default action action_hangup to disconnect calls. This action also will add a SessionEnded event to the conversation.

Using Responses relevant to Voice Channels

It is recommended to use channel specific responses with voice channels. This can be done with channel specific responses:

domain.yml
responses:
utter_setup_guide:
- text: "Click the 👉 button or visit https://example.com/setup-guide"
- text: ""To continue setup, open our website and go to the setup guide""
channel: "twilio_media_streams"

In the above example, note that emoji doesn't translate well to speech. URLs are difficult to conprehend due to the temporal nature of voice vs permanence of text. Words like "Type" or "Click" assume interactions that aren't possible on a phone call. Special characters are awkward when spoken.

You can also use SSML in the responses to allow for more customisation in the audio responses from the assistant.

domain.yml
responses:
utter_contact_support:
- text: "Call our support team at 1-800-555-0123"
- text: |
<speak>
You can reach our support team at
<say-as interpret-as="telephone">1 800 555 0123</say-as>
<break time="500ms"/>
Our agents are available 24/7.
</speak>
channel: "twilio_media_streams"

Reference: Default Pattern Configuration

For reference, here is the complete default configuration for conversation repair:

Default Patterns
version: "3.1"
responses:

utter_ask_rephrase:
- text: I’m sorry I am unable to understand you, could you please rephrase?

utter_ask_still_there:
- text: "Hello, are you still there?"
metadata:
rephrase: True

utter_boolean_slot_rejection:
- text: "Sorry, the value you provided, `{{value}}`, is not valid. Please respond with a valid value."
metadata:
rephrase: True
template: jinja

utter_can_do_something_else:
- text: "What else can I help you with?"
metadata:
rephrase: True

utter_cannot_handle:
- text: I'm sorry, I'm not trained to help with that.

utter_categorical_slot_rejection:
- text: "Sorry, you responded with an invalid value - `{{value}}`. Please select one of the available options."
metadata:
rephrase: True
template: jinja

utter_clarification_options_rasa:
- text: "I can help, but I need more information. Which of these would you like to do: {{context.clarification_options}}?"
metadata:
rephrase: True
template: jinja

utter_corrected_previous_input:
- text: "Ok, I am updating {{ context.corrected_slots.keys()|join(', ') }} to {{ context.corrected_slots.values()|join(', ') }} respectively."
metadata:
rephrase: True
template: jinja

utter_float_slot_rejection:
- text: "Sorry, it seems the value you provided `{{value}}` is not a valid number. Please provide a valid number in your response."
metadata:
rephrase: True
template: jinja

utter_flow_cancelled_rasa:
- text: "Okay, stopping {{ context.canceled_name }}."
metadata:
rephrase: True
template: jinja

utter_flow_continue_interrupted:
- text: "Let's continue with {{ context.previous_flow_name }}."
metadata:
rephrase: True
template: jinja

utter_free_chitchat_response:
- text: "Sorry, I'm not able to answer that right now."
metadata:
rephrase: True
rephrase_prompt: |
You are an incredibly friendly assistant. Generate a short
response to the user's comment in simple english.

User: {{current_input}}
Response:

utter_human_handoff_not_available:
- text: I understand you want to be connected to a human agent, but that's something I cannot help you with at the moment. Is there something else I can help you with?
metadata:
rephrase: True

utter_inform_code_change:
- text: There has been an update to my code. I need to wrap up our running dialogue and start from scratch.
metadata:
rephrase: True

utter_inform_hangup:
- text: It seems you are not there anymore. I will hang up shortly.
metadata:
rephrase: True

utter_internal_error_rasa:
- text: Sorry, I am having trouble with that. Please try again in a few minutes.

utter_no_knowledge_base:
- text: I am afraid, I don't know the answer. At this point, I don't have access to a knowledge base.
metadata:
rephrase: True

utter_skip_question_answer:
- text: I'm here to provide you with the best assistance, and in order to do so, I kindly request that we complete this step together. Your input is essential for a seamless experience!
metadata:
rephrase: True

utter_user_input_empty_error_rasa:
- text: I see an empty message. What can I assist you with?

utter_user_input_too_long_error_rasa:
- text: I'm sorry, but your message is too long for me to process. Please keep your message concise and within {% if context.info.max_characters %}{{context.info.max_characters}} characters.{% else %}a reasonable length.{% endif %}
metadata:
template: jinja

slots:
confirm_correction:
type: bool
mappings:
- type: from_llm
silence_timeout:
type: float
initial_value: 6.0
max_value: 1000000
consecutive_silence_timeouts:
type: float
initial_value: 0.0
max_value: 1000000


flows:
pattern_cancel_flow:
description: Conversation repair flow that starts when a flow is cancelled
name: pattern_cancel_flow
steps:
- action: action_cancel_flow
- action: utter_flow_cancelled_rasa

pattern_cannot_handle:
description: |
Conversation repair flow for addressing failed command generation scenarios
name: pattern cannot handle
steps:
- noop: true
next:
# chitchat fallback
- if: "'{{context.reason}}' = 'cannot_handle_chitchat'"
then:
- action: utter_cannot_handle
next: "END"
# fallback for things that are not supported
- if: "'{{context.reason}}' = 'cannot_handle_not_supported'"
then:
- action: utter_cannot_handle
next: END
# default
- else:
- action: utter_ask_rephrase
next: END

pattern_chitchat:
description: Conversation repair flow for off-topic interactions that won't disrupt the main conversation
name: pattern chitchat
steps:
- action: action_trigger_chitchat

pattern_clarification:
description: Conversation repair flow for handling ambiguous requests that could match multiple flows
name: pattern clarification
steps:
- action: action_clarify_flows
- action: utter_clarification_options_rasa

pattern_code_change:
description: Conversation repair flow for cleaning the stack after an assistant update
name: pattern code change
steps:
- action: utter_inform_code_change
- action: action_clean_stack

pattern_collect_information:
description: Flow for collecting information from users
name: pattern collect information
steps:
- id: start
action: action_run_slot_rejections
- action: validate_{{context.collect}}
next:
- if: "slots.{{context.collect}} is not null"
then: END
- else: ask_collect
- id: ask_collect
action: "{{context.utter}}"
- action: "{{context.collect_action}}"
- action: action_listen
next: start

pattern_completed:
description: Flow that asks if the user needs more help after completing their initiated use cases
name: pattern completed
steps:
- action: utter_can_do_something_else

pattern_continue_interrupted:
description: Conversation repair flow for managing when users switch between different flows
name: pattern continue interrupted
steps:
- action: utter_flow_continue_interrupted

pattern_correction:
description: Conversation repair flow for managing user input changes or error corrections
name: pattern correction
steps:
- action: action_correct_flow_slot
next:
- if: not context.is_reset_only
then:
- action: utter_corrected_previous_input
next: END
- else: END

pattern_human_handoff:
description: Conversation repair flow for switching users to a human agent if their request can't be handled
name: pattern human handoff
steps:
- action: utter_human_handoff_not_available

pattern_internal_error:
description: Conversation repair flow for informing users about internal errors
name: pattern internal error
steps:
- noop: true
next:
- if: "'{{context.error_type}}' = 'rasa_internal_error_user_input_too_long'"
then:
- action: utter_user_input_too_long_error_rasa
next: END
- if: "'{{context.error_type}}' = 'rasa_internal_error_user_input_empty'"
then:
- action: utter_user_input_empty_error_rasa
next: END
- else:
- action: utter_internal_error_rasa
next: END

pattern_repeat_bot_messages:
description: Voice conversation repair pattern to repeat bot messages
name: pattern repeat bot messages
steps:
- action: action_repeat_bot_messages

pattern_restart:
description: Flow for restarting the conversation
name: pattern restart
nlu_trigger:
- intent: restart
steps:
- action: action_restart

pattern_search:
description: Flow for handling knowledge-based questions
name: pattern search
steps:
- action: utter_no_knowledge_base
# - action: action_trigger_search to use enterprise search policy if present

pattern_session_start:
description: Flow for starting the conversation
name: pattern session start
nlu_trigger:
- intent: session_start
steps:
- action: action_session_start

pattern_skip_question:
description: Conversation repair flow for managing user intents to skip questions (steps)
name: pattern skip question
steps:
- action: utter_skip_question_answer

pattern_user_silence:
description: Reacting to user silence in voice bots
name: pattern react to silence
nlu_trigger:
- intent: silence_timeout
persisted_slots:
- consecutive_silence_timeouts
steps:
- noop: true
next:
- if: "slots.consecutive_silence_timeouts = 0.0"
then:
- set_slots:
- consecutive_silence_timeouts: 1.0
- action: action_repeat_bot_messages
next: END
- if: "slots.consecutive_silence_timeouts = 1.0"
then:
- set_slots:
- consecutive_silence_timeouts: 2.0
- action: utter_ask_still_there
next: END
- if: "slots.consecutive_silence_timeouts > 1.0"
then:
- action: utter_inform_hangup
- action: action_hangup
next: END
- else: END