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.

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

9. Cannot Handle

This pattern is triggered to gracefully handle the following situations:

  • When the LLMCommandGenerator 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.

  • 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.

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.

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.

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_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 I can 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: "placeholder_this_utterance_needs_the_rephraser"
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_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: custom
flows:
pattern_cancel_flow:
description: A meta flow that's started when a flow is cancelled.
name: pattern_cancel_flow
steps:
- action: action_cancel_flow
- action: utter_flow_cancelled_rasa
pattern_cannot_handle:
description: |
pattern that is triggered when the command generators fail to create (any) valid commands
name: pattern cannot handle
steps:
- noop: true
next:
# chitchat fallback
- if: "'{{context.reason}}' == 'cannot_handle_chitchat'"
then:
- action: utter_cannot_handle
next: "END"
# default
- else:
- action: utter_ask_rephrase
next: "END"
pattern_chitchat:
description: handle interactions with the user that are not task-oriented
name: pattern chitchat
steps:
- action: action_trigger_chitchat
pattern_clarification:
description: handle clarifications with the user
name: pattern clarification
steps:
- action: action_clarify_flows
- action: utter_clarification_options_rasa
pattern_code_change:
description: flow used to clean the stack after a bot update
name: pattern code change
steps:
- action: utter_inform_code_change
- action: action_clean_stack
pattern_collect_information:
description: flow used to fill a slot
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: action_listen
next: "start"
pattern_completed:
description: a flow has been completed and there is nothing else to be done
name: pattern completed
steps:
- action: utter_can_do_something_else
pattern_continue_interrupted:
description: A flow that should will be started to continue an interrupted flow.
name: pattern continue interrupted
steps:
- action: utter_flow_continue_interrupted
pattern_correction:
description: Handle a correction of a slot value.
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: human handoff
name: pattern human handoff
steps:
- action: utter_human_handoff_not_available
pattern_internal_error:
description: internal error
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_restart:
description: flow used to restart the conversation
name: pattern restart
nlu_trigger:
- intent: restart
steps:
- action: action_restart
pattern_search:
description: handle a knowledge-based question or request
name: pattern search
steps:
- action: utter_no_knowledge_base
# - action: action_trigger_search to use doc search policy if present
pattern_session_start:
description: flow used to start the conversation
name: pattern session start
nlu_trigger:
- intent: session_start
steps:
- action: action_session_start
pattern_skip_question:
description: flow used to handle users intent to skip questions (steps)
name: pattern skip question
steps:
- action: utter_skip_question_answer