Version: Latest

Conversation Repair

Conversation Repair refers to the ability of an assistant to handle conversations that deviate from the happy path. Rasa handles Conversation Repair automatically using a set of customizable patterns.

New in 3.7

Conversation Repair is part of Rasa's new Conversational AI with Language Models (CALM) approach and available starting with version 3.7.0.

Overview

Flows describe your assistant's business logic. In the tutorial example, your transfer_money flow specifies that your assistant needs to ask the user for the recipient and the amount_of_money.

The "happy path" refers to a conversation where every time the assistant asks the user for information, the user provides an answer which successfully fills the requested slot. Conversation Repair is there to handle all the conversations which differ from the happy path.

For example:

  • your assistant asked for an amount of money, but the user says something else.
  • the end user interrupts the current flow and switches context to another topic.
  • the end user changes their mind about something they said earlier.

Rasa has default patterns for handling each of these cases. Each of these patterns is a pre-built flow. The behaviour can be fully customized by adding a flow with the same name to your assistant.

Conversation Repair Cases

1. Digressions

Digressions arise when a user shifts from one flow to another.

Example: During a money transfer, a user might ask about their current balance.

User: I want to send some money to Sudarshana

Bot: How much do you want to send to Sudarshana?

User: Ah wait, how much money do I have?

Bot: You currently have 4021.20$ in your account.

Bot: Let's continue with sending money to Sudarshana.

Bot: How much money do you want to send to Sudarshana then?

User: ...

User digresses in the middle of a transfer

2. Corrections

Corrections occur when users modify input data or rectify mistakes.

Example: A user might change their mind about the recipient of a transfer.

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: Updated recipient to John

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

User: ...

User corrects recipient's name
important

Upon correction, the flow retraces to align with the updated data. User might witness an alternate flow based on changes.

3. Cancellations

Cancellations happen when users halt a flow midway.

Example: A user opts out of sending money after initiating the process.

User: I want to send some money to Dimitri

Bot: How much money do you want to send?

User: Ah, nevermind. I see I have already sent it earlier.

Bot: Okay, I am cancelling the transfer.

User: ...

User cancels a transfer

4. Skipping collect steps

Occurs when a user intends to bypass the collect step either by avoiding to provide the requested information or requesting to move past the current step.

Example: A user avoids to answer the bot question.

User: I want to send some money to Dimitri

Bot: How much money do you want to send?

User: Go to the next question.

Bot: 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!

Bot: How much money do you want to send?

User: ...

User avoids to provide requested information

5. Chitchat

Engage in off-topic interactions without impacting a flow.

Example: A user has a casual conversation with the assistant that responds with free-form response.

User: Hi

Bot: Hi! I'm your Financial Assistant!

User: are you a bot?

Bot: I'm a virtual assistant made with Rasa.

Chitchat with the assistant

The default behavior relies on responses defined within the domain that are not part of any flow, with the Intentless Policy determining the appropriate response. If the IntentlessPolicy is not configured, the assistant will activate the Cannot Handle pattern, thus informing the user that their request cannot be handled. This effectively disables Chitchat.

Additionally, you have the option to explicitly disable Chitchat. For instructions on how to do this, see this section.

You can customize the default behavior to enable free-form responses. See this section on how to do it.

6. Completion

Flows conclude either by achieving user goals or by user abandonment.

Example: User queries about account balance.

User: Hey, how much money do I have?

Bot: You currently have 4021.20$ in your account.

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

Flow completion

7. Clarification

Clarifications arise when the user request can't clearly be identified and potentially matches multiple flows.

Example: User request can be matched to two flows.

User: cash

Bot: I'm not sure what you'd like to achieve. Do you want to check your balance or transfer money?

Flow completion

8. Internal Errors

Errors arise from unexpected system or flow issues:

  1. Unavailable actions, unresponsive modules, or errors from dependent services (e.g. timeout response from LLM).
  2. User input exceeds predefined limit (if limits are set).
  3. User sends empty message.
  4. Errors from dependent services, such as a timeout response from LLM.
  5. (with Enterprise Search Policy) In case of an error when connecting to the vector store, during document retrieval or from the LLM. Please click here for more details

Below are examples showcasing different internal error scenarios:

Example: Internal error is raised due to unavailable actions or timeout from LLM.

User: Hey, how much money do I have?

Bot: Sorry, I am having trouble with that. Please try again later.

Example showcasing internal error due to unavailable actions or timeout from LLM

Example: Internal error is raised due to exceeded input limit.

User: [User sends a message exceeding the set input limit]

Bot: I'm sorry, but your message is too long for me to process. Please keep your message concise and within a reasonable length.

Example showcasing internal error due to exceeded input limit

Example: Internal error is raised due to empty user message.

User:

Bot: I see an empty message. What can I assist you with?

Example showcasing internal error due to empty user message

Context Attributes

error_type and info serve as context attributes for managing errors in pattern_internal_error. info attribute is a dictionary meant to contain additional information like max_characters. error_type acts as a switch-case selector. It determines the appropriate error message based on the encountered scenario. The message is then sent to the user.

  • rasa_internal_error_user_input_too_long, set when user input exceeds the user_input.max_character limit of the LLMCommandGenerator.
  • rasa_internal_error_user_input_empty, set by blank inputs.

These context attributes are not available outside of the pattern_internal_error.

9. Cannot Handle

This pattern is triggered to gracefully handle the following situations:

  • When the LLM-based command generator encounters scenarios where it is unable to predict a valid command (e.g. LLM hallucinates attempting to start a non-existing flow) this mechanism prompts the user to rephrase their request. Additionally, MultiStepLLMCommandGenerator can directly predict the command when the scope of the user message is beyond starting, canceling, or clarifying a flow.

  • When the Enterprise Search policy cannot retrieve any relevant documents from the vector store, it triggers this mechanism. In this case, the bot may need to prompt the user to rephrase their request or inform the user that relevant information couldn't be found.

  • User indulges in an off-topic conversation (chitchat) and the assistant is configured to respond with predefined responses but it is trained without the IntentlessPolicy in the pipeline.

Context Attributes

The pattern pattern_cannot_handle has the context attribute reason. reason is set to:

  • cannot_handle_chitchat, when pattern_chitchat attempts to invoke action_trigger_chitchat without an IntentlessPolicy defined.

The context attribute is not be available outside of pattern_cannot_handle.

10. Human Handoff

When the user requests to be connected to a human agent or when the assistant cannot handle the user's request, the assistant can handoff the conversation.

Example: User requests to be connected to a human agent.

User: I want to be connected to a human agent.

Bot: 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?

Example showcasing human handoff

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.

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 Cannot Handle pattern, 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.

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