跳转至

对话修复

对话修复是指对话机器人处理偏离预期路径的对话的能力。Rasa 使用一组可自定义的模式自动处理对话修复。

3.7 版本新特性

对话修复是 Rasa 的新语言模型 (CALM) 对话式 AI 方法的一部分,从 3.7.0 版本开始可用。

概述

描述了对话机器人的业务逻辑。在教程示例中,transfer_money 流指定对话机器人需要向用户询问 recipientamount_of_money

“预期流经”是指每次对话机器人向用户询问信息时,用户都会提供一个成功填充请求槽的答案。对话修复可以处理所有与预期路径不同的对话。

例如:

  • 对话机器人询问金额,但用户说了其他话。
  • 用户中断当前流并将上下文切换到另一个主题。
  • 用户改变了之前所说的话的想法。

Rasa 有处理每种情况的默认模式。每种模式都是预构建的。可以通过向对话机器人添加同名的流来自定义。

对话修复案例

1. 离题

当用户从一个流转到另一个流时,就会出现离题。

示例:在转账过程中,用户可能会询问其当前余额。

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

用户在转账过程中离题

2. 更正

更正发生在用户修改输入数据或纠正错误时。

示例:用户可能会改变转账接收人。

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

用户更正收款人姓名

重要

更正后,流将重新追溯以与更正后的数据保持一致。用户可能会看到基于更正的替代流。

3. 取消

当用户中途停止流时,就会发生取消。

示例:用户在启动流后选择不汇款。

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

用户取消转账

4. 跳过收集步骤

当用户试图绕过 collect 步骤时,通过拒绝提供所请求的信息或请求跳过当前步骤。

示例:用户拒绝回答机器人问题。

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

用户拒绝提供所请求的信息

5. 闲聊

参与不影响流的离题互动。

示例:用户与对话机器人进行随意交谈,对话机器人以自由格式的回复进行响应。

User: Hi

Bot: Hi! I'm your Financial Assistant!

User: are you a bot?

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

与对话机器人闲聊

默认行为 依赖于领域内定义的不属于任何流的响应,由无意图策略确定适当的响应。如果未配置 IntentlessPolicy,对话机器人将激活无法处理模式,从而通知用户无法处理他们的请求。这实际上禁用了闲聊。

此外,你还可以选择明确禁用闲聊。有关如何执行此动作的说明,请参阅本节

你可以自定义默认行为以启用 自由格式的响应。请参阅本节了解如何执行此动作。

6. 完成

流以达成用户目标或用户放弃而结束。

示例:用户查询账户余额。

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?

流完成

7. 澄清

当无法明确识别用户请求并可能匹配多个流时,需要澄清。

示例:用户请求可以匹配两个程。

User: cash

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

澄清

8. 内部错误

错误源自意外的系统或流问题:

  1. 不可用的动作、无响应的模块或来自依赖服务的错误(例如 LLM 的超时响应)。
  2. 用户输入超出预定义限制(如果设置了限制)。
  3. 用户发送空消息。
  4. 来自依赖服务的错误,例如来自 LLM 的超时响应。
  5. (使用企业搜索策略)在连接到向量存储、文档检索期间或从 LLM 时发生错误。单击此处了解更多详细信息。

以下是展示不同内部错误场景的示例:

示例:由于 LLM 的动作不可用或超时而引发内部错误。

User: Hey, how much money do I have?

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

由于 LLM 的动作不可用或超时而引发内部错误

示例:由于超出输入限制而引发内部错误。

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.

由于超出输入限制而引发内部错误

示例:由于用户消息为空而引发内部错误。

User:

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

由于用户消息为空而引发内部错误

上下文属性

error_typeinfo 用作管理 pattern_internal_error 中错误的上下文属性。info 属性是一个字典,用于包含 max_characters 等附加信息。error_type 用作 switch-case 选择器。它根据遇到的场景确定适当的错误消息。然后将消息发送给用户。

  • rasa_internal_error_user_input_too_long,当用户输入超过 LLMCommandGeneratoruser_input.max_character 限制时设置。
  • rasa_internal_error_user_input_empty,由空白输入设置。

这些上下文属性在 pattern_internal_error 之外不可用。

9. 无法处理

触发此模式是为了妥善处理以下情况:

  • 基于 LLM 的命令生成器遇到无法预测有效命令的情况(例如,LLM 产生幻觉试图启动不存在的流)时,此机制会提示用户重新措辞其请求。此外,当用户消息的范围超出启动、取消或澄清流时,MultiStepLLMCommandGenerator 可以直接预测命令。
  • 企业搜索策略无法从向量存储中检索任何相关文档时,会触发此机制。在这种情况下,对话机器人可能需要提示用户重新措辞其请求或通知用户无法找到相关信息。
  • 用户沉迷于离题的对话(闲聊),对话机器人设置为使用预定义的响应进行回复,但它是在没有管道中的 IntentlessPolicy 的情况下进行训练的。

上下文属性

模式 pattern_cannot_handle 具有 reason 上下文属性。reason 设置为:

  • cannot_handle_chitchat,当 pattern_chitchat 尝试在未定义 IntentlessPolicy 的情况下调用 action_trigger_chitchat 时。

上下文属性在 pattern_cannot_handle 之外不可用。

10. 人工处理

当用户请求连接到人工或对话机器人无法处理用户请求时,对话机器人可以转接对话。

示例:用户请求连接到人工。

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?

人工处理

配置

默认行为

Rasa 为每个开箱即用的对话修复案例提供了一个默认行为。每个案例都通过一个模式来处理,该模式是专门为处理该案例而设计的特殊流:

  • pattern_continue_interrupted 用于离题。
  • pattern_correction 用于更正。
  • pattern_cancel_flow 用于取消。
  • pattern_skip_question 用于跳过收集步骤。
  • pattern_chitchat 用于闲聊。
  • pattern_completed 用于完成。
  • pattern_clarification 用于澄清。
  • pattern_internal_error 用于内部错误。
  • pattern_cannot_handle 用于无法处理。
  • pattern_human_handoff 用于人工处理。

这些流的语法与其他流相同。

信息

对话修复案例应开箱即用。这意味着,如果默认行为对于对话机器人的用例来说已经足够好,那么对话机器人的项目目录中就不需要处理修复案例的模式所对应的流。

信息

上下文响应改写器可帮助模式中的默认响应自然地适应对话的上下文。

修改默认行为

可以通过创建与用于处理相应案例的模式同名的流(如 pattern_correction)来覆盖每个对话修复案例的默认行为。如果模式使用需要修改的默认动作,你可以通过实施新的自定义动作来覆盖默认动作的实施,并在流中使用该自定义动作。

信息

确保修改完成后对话机器人得到重新训练。

信息

由于大多数这些模式会中断另一个流,因此它们应该保持简短和简单。

示例配置

修改流结束时 Rasa 的响应:

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?"

常见修改

以下是对默认行为的一些常见修改。

要求确认

你可以修改更正的默认实现,并在更新槽之前要求用户确认,例如,这将导致如下对话:

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

常见的纠正场景

为了实现上述确认,创建一个名为 pattern_correction 的流,其定义如下:

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

还要确保将使用的响应和槽添加到领域文件中:

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

实现人工处理

目前,人工处理的默认行为是通知用户对话机器人无法处理请求。然而,在有客户服务可用的情况下,实现人工处理变得很重要。你可以通过编写自定义动作并覆盖名为 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

还要确保将使用的动作、响应和槽添加到领域文件中:

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

根据当前流做出回应

你可以根据被中断的流更改模式的行为。这可以通过在模式的 if 条件中使用 context 对象来实现

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

在上面的例子中,仅当中断的流名为 transfer_money 时,才使用 inform_user 步骤。

闲聊自由格式生成

默认情况下,闲聊通过 action_trigger_chitchat 运行,该动作调用 IntentlessPolicy 来提供相关的预定义响应。

要切换到自由格式生成的响应,需通过创建名为 pattern_chitchat 的流来覆盖 pattern_chitchat 的默认行为,该流定义如下:

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

警告

将使用 LLM 生成自由格式的响应。对话机器人可能会回答超出预期领域的查询。

禁用闲聊

默认情况下,如果未配置 Intentless 策略,对话机器人将默认采用无法处理模式,通过通知用户无法处理请求来有效地限制闲聊。

要完全限制随意对话,需通过创建名为 pattern_chitchat 的流来覆盖 pattern_chitchat 的默认行为。与其使用触发 action_trigger_chitchat 的通常行为,不如将其配置为使用预定义响应:

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

参考:默认模式配置

作为参考,以下是对话修复的完整默认配置:

默认模式
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 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: "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

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_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 doc 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