🚀 原文地址:https://rasa.com/docs/rasa/responses

响应是机器人发送给用户的消息,它通常仅为文本,但也可以包括图像和按钮等内容。

1. 定义响应

响应位于域文件或单独的 responses.yml 文件,每个响应名称都应该以 utter_ 开头。例如,我们可以在响应名称 utter_greetutter_bye 下添加问候和说再见的响应:

  1. intents:
  2. - greet
  3. responses:
  4. utter_greet:
  5. - text: "Hi there!"
  6. utter_bye:
  7. - text: "See you!"

如果使用了检索意图,则需要为这些意图添加响应:

  1. # @file: domain.yml
  2. intents:
  3. - chitchat
  4. responses:
  5. utter_chitchat/ask_name:
  6. - text: Oh yeah, I am called the retrieval bot.
  7. utter_chitchat/ask_weather:
  8. - text: Oh, it does look sunny right now in Berlin.

:::warning 🛑 注意
——————————
请注意检索意图的响应名称的特殊格式,每个名称以 utter_ 开头,后面跟检索意图的名称(上例为 chitchat),最后是指定不同响应的后缀(此处为 ask_nameask_weather)。 :::

1.1 在响应中使用变量

我们可以使用变量来将信息插入到响应中,变量用大括号括起来。下面的示例中,我们就使用了 name 变量:

  1. responses:
  2. utter_greet:
  3. - text: "Hey, {name}. How are you?"

当使用 utter_greet 响应时,Rasa 会自动使用 name 插槽的值进行填充。如果这样的插槽不存在或为空,则变量将填充为 None。

填充变量的另一种方法是使用自定义操作,我们可以为响应提供值以填充特定变量。如果你使用 Rasa SDK 作为 Action Server,我们可以在 dispatcher.utter_message 函数中将变量作为参数来传递所需要的值。

  1. dispatcher.utter_message(
  2. template="utter_greet",
  3. name="Sara"
  4. )

如果我们使用其他的 Action Server,可以在服务器返回响应中添加额外参数来提供值:

  1. {
  2. "events":[
  3. ...
  4. ],
  5. "responses":[
  6. {
  7. "template":"utter_greet",
  8. "name":"Sara"
  9. }
  10. ]
  11. }

1.2 随机响应

🛑 Rasa 官方上将随机响应称之为响应变体(Response Variations),个人觉得翻译成随机响应或随机回复会更好一点。

如果我们给响应名称添加了多种响应可供选择,那么机器人的回复将会更有意思。在下面例子中,当 utter_greet 被预测为下一个动作时,Rasa 将随机选择两个响应中随机选择一个来使用。

  1. responses:
  2. utter_greet:
  3. - text: "Hey, {name}. How are you?"
  4. - text: "Hey, {name}. How is your day going?"

1.3 特定通道下的响应

如果需要根据用户连接到的通道指定不同的响应,那么我们可以使用特定通道的响应。在下面示例中,第一个响应中使用了 channel 键指定了 slack 通道,而第二个响应并未指定特殊通道:

  1. responses:
  2. utter_ask_game:
  3. - text: "Which game would you like to play on Slack?"
  4. channel: "slack"
  5. - text: "Which game would you like to play?"

:::warning 🛑 注意
——————————
确保 channel 键的值与输入通道的 name 方法返回的值匹配。如果使用的是内置通道,则 channel 的键值还将与 credentials.yml 文件中使用的通道名称相匹配。 :::

当机器人在给定响应名称下寻找合适的随机响应时,它会优先选择当前通道与特定通道匹配的响应。如果并没有特定通道的响应,机器人将从任何非特定通道的响应中随机选择。在上面的示例中,第二个响应没有指定通道,机器人可以将其用于除了 slack 之外的所有通道。

:::danger ⌛ 警告
——————————
对于每个响应名称,尝试至少有一个非特定通道的响应,这将使得机器人能在所有环境下做出正确响应,例如在新频道、shell 和交互学习中。 :::

1.4 条件响应

当然,我们还可以使用条件响应。它基于一个或多个槽值选择特定的响应。条件随机响应定义在域或响应 YAML 文件中,类似于标准随机响应,但具有附加 condition 键,此键指定插槽名称和值约束的列表。

在对话期间触发响应时,根据当前对话状态检查每个条件响应的约束。如果所有约束槽值等于当前对话状态的相应槽值,则随机响应可以被机器人所使用。

:::warning 🛑 注意
——————————
对话状态槽值和约束槽值的比较由 == 运算符执行,该运算符也要求槽值的类型匹配。例如,如果将约束指定为 value: true,则该插槽需要填充布尔值 true,而不是字符串 true。 :::

在下面的示例中,我们将定义一个具有约束条件的响应,即 login 插槽设置为 true

  1. slots:
  2. logged_in:
  3. type: bool
  4. influence_conversation: False
  5. mappings:
  6. - type: custom
  7. name:
  8. type: text
  9. influence_conversation: False
  10. mappings:
  11. - type: custom
  12. responses:
  13. utter_greet:
  14. - condition:
  15. - type: slot
  16. name: logged_in
  17. value: true
  18. text: "Hey, {name}. Nice to see you again! How are you?"
  19. - text: "Welcome. How is your day going?"
  1. stories:
  2. - story: greet
  3. steps:
  4. - action: action_log_in
  5. - slot_was_set:
  6. - logged_in: true
  7. - intent: greet
  8. - action: utter_greet

在上述示例中,第一个响应 Hey, {name}. Nice to see you again! How are you? 将在执行 utter_greet 操作且 logged_in 插槽为 true 时启用。第二个响应由于没有条件,将被视为默认值,在 logged_in 不等于 true 时启用。

:::danger ⌛ 警告
——————————
强烈建议始终提供无条件的默认响应变体,以防止在条件与填充插槽不匹配时没有响应。 :::

在对话期间,Rasa 将从所有满足约束条件的条件响应中进行选择。如果有多个符合条件的响应,Rasa 将随机选择一个。例如下面这个示例:

  1. responses:
  2. utter_greet:
  3. - condition:
  4. - type: slot
  5. name: logged_in
  6. value: true
  7. text: "Hey, {name}. Nice to see you again! How are you?"
  8. - condition:
  9. - type: slot
  10. name: eligible_for_upgrade
  11. value: true
  12. text: "Welcome, {name}. Did you know you are eligible for a free upgrade?"
  13. - text: "Welcome. How is your day going?"

如果 logged_ineligible_for_upgrade 都是 true 的情况下,那么第一个和第二个响应都可以使用,机器人将随机选择一个。我们可以继续使用特定通道的响应和天剑响应,如下面示例:

  1. slots:
  2. logged_in:
  3. type: bool
  4. influence_conversation: False
  5. mappings:
  6. - type: custom
  7. name:
  8. type: text
  9. influence_conversation: False
  10. mappings:
  11. - type: custom
  12. responses:
  13. utter_greet:
  14. - condition:
  15. - type: slot
  16. name: logged_in
  17. value: true
  18. text: "Hey, {name}. Nice to see you again on Slack! How are you?"
  19. channel: slack
  20. - text: "Welcome. How is your day going?"

Rasa 将按照以下顺序优先选择响应:

  1. 具有匹配通道的条件响应
  2. 具有匹配通道的默认响应
  3. 没有匹配通道的条件响应
  4. 没有匹配通道的默认响应

    2. 富文本响应

    我们可以通过添加视觉和交互元素来丰富回复,许多通道都支持多种类型的元素。

    2.1 按钮

    以下是使用按钮的响应示例:
    1. responses:
    2. utter_greet:
    3. - text: "Hey! How are you?"
    4. buttons:
    5. - title: "great"
    6. payload: "/mood_great"
    7. - title: "super sad"
    8. payload: "/mood_sad"

按钮列表中的每个按钮都应该有两个键:

  • title:用户看到的按钮显示的文本
  • payload:单击按钮时用户向机器人发送的消息

如果我们希望按钮也将实体传递给机器人:

  1. responses:
  2. utter_greet:
  3. - text: "Hey! Would you like to purchase motor or home insurance?"
  4. buttons:
  5. - title: "Motor insurance"
  6. payload: '/inform{{"insurance":"motor"}}'
  7. - title: "Home insurance"
  8. payload: '/inform{{"insurance":"home"}}'

也可以通过以下方式传递多个实体:

  1. '/intent_name{{"entity_type_1":"entity_value_1", "entity_type_2": "entity_value_2"}}'

:::info 🧬 使用按钮绕过 NLU
—————————————————
我们可以使用按钮绕过 NLU 预测,并处罚特定的意图和实体。以 / 开头的消息会直接发送到 RegexInterpreter,它期望 NLU 输入采用缩短 /inten{entities} 格式。在上面的例子中,如果用户点击一个按钮,用户输入将被直接分类为 mood_great 或者 mood_sad 意图。

我们可以使用以下格式包含意图传递给 RegexInterpreter 的实体:/inform{"ORG":"Rasa", "GPE":"Germany"}RegexInterpreter 将对上面带有 inform 意图的消息进行分类,并提取分别属于 ORGGPE 类型的实体 RasaGermany

🧬 在 DOMAIN.YML 中转义大括号
—————————————————
我们需要在 domain.yml 文件中使用双花括号编写 /intent{entities} 速记响应,以便机器人不会将其视为响应中的变量,并在花括号中插入内容。 :::

:::danger ⌛ 检查通道
—————————————————
请记住,如何显示定义的按钮取决于输出通道的实现。例如,某些通道可以提供的按钮数量是有限制的。 :::

2.1.1 案例:按钮+条件响应

| ```yaml version: “3.1”

nlu:

  • intent: greet examples: |

    • hey
    • hello
    • hi
  • intent: goodbye examples: |

    • 拜拜
    • 再见
  1. | ```yaml
  2. version: "3.1"
  3. rules:
  4. - rule: 打招呼
  5. steps:
  6. - intent: greet
  7. - action: utter_greet
  8. - rule: 获取性别
  9. steps:
  10. - intent: set_gender
  11. - action: utter_gender

| | —- | —- |

  1. version: '3.0'
  2. session_config:
  3. session_expiration_time: 60
  4. carry_over_slots_to_new_session: true
  5. intents:
  6. - greet
  7. - goodbye
  8. - set_gender
  9. entities:
  10. - gender
  11. slots:
  12. gender:
  13. type: text
  14. influence_conversation: False
  15. mappings:
  16. - type: from_entity
  17. entity: gender
  18. responses:
  19. utter_greet:
  20. - buttons:
  21. - payload: '/set_gender{{"gender": "male"}}'
  22. title: 男性
  23. - payload: '/set_gender{{"gender": "female"}}'
  24. title: 女性
  25. text: Hey! How are you?
  26. utter_gender:
  27. - condition:
  28. - type: slot
  29. name: gender
  30. value: male
  31. text: "你好,先生"
  32. - text: "你好,女士"
  1. $ rasa shell
  2. Your input -> hello
  3. 2022-06-01 12:35:42 DEBUG rasa.core.processor - Received user message 'hello' with intent '{'name': 'greet', 'confidence': 0.9999994039535522}' and entities '[]'
  4. ? Hey! How are you? (Use arrow keys)
  5. » 1: 男性 (/set_gender{"gender": "male"})
  6. 2: 女性 (/set_gender{"gender": "female"})
  7. Type out your own message...
  8. 2022-06-01 12:36:27 DEBUG rasa.core.processor - Received user message '/set_gender{"gender": "male"}' with intent '{'name': 'set_gender', 'confidence': 1.0}' and entities '[{'entity': 'gender', 'value': 'male', 'start': 11, 'end': 29, 'extractor': 'RegexMessageHandler'}]'
  9. 2022-06-01 12:36:27 DEBUG rasa.core.processor - Current slot values:
  10. gender: female
  11. session_started_metadata: None
  12. 你好,先生

2.2 图像

我们可以通过在 image 键下提供图像的 URL 给响应添加图像:

  1. utter_cheer_up:
  2. - text: "Here is something to cheer you up:"
  3. image: "https://i.imgur.com/nGF1K8f.jpg"

2.3 自定义输出有效载荷

我们可以使用 custom 键将任意输出发送到输出通道,输出通道接收存储在 custom 键下的对象作为 JSON 负载。以下是如何将日期选择器发送到 Slack 输出通道上的示例:

  1. responses:
  2. utter_take_bet:
  3. - custom:
  4. blocks:
  5. - type: section
  6. text:
  7. text: "Make a bet on when the world will end:"
  8. type: markdwn
  9. accessory:
  10. type: datepicker
  11. initial_date: '2019-05-21'
  12. placeholder:
  13. type: plain_text
  14. text: Select a date

3. 在对话中使用响应

3.1 调用响应作为动作

如果响应的名称以 utter_ 开头,则响应可以直接用作操作,而无需在域文件中 actions 部分列出,我们在域文件中添加如下响应:

  1. responses:
  2. utter_greet:
  3. - text: "Hey! How are you?"

我们可以在故事中使用相同的响应作为操作:

  1. stories:
  2. - story: greet user
  3. steps:
  4. - intent: greet
  5. - action: utter_greet

utter_greet 操作运行时,它会将响应中的消息发送回用户。

:::info 🧬 不断变化的响应
—————————————————
如果想更改文本或响应的任何其他部分,我们需要在更改之后重新训练。 :::

3.2 从自定义动作中调用响应

在自定义操作中,我们可以调用响应生成回复。如果使用的是 Rasa SDK 服务器,我们可以使用 dispatch 来生成响应消息:

  1. from rasa_sdk.interfaces import Action
  2. class ActionGreet(Action):
  3. def name(self):
  4. return 'action_greet'
  5. def run(self, dispatcher, tracker, domain):
  6. dispatcher.utter_message(template="utter_greet")
  7. return []

如果使用的是其他 Action Server,那么我们应该返回如下 JSON 内容来调用 utter_greet 响应:

  1. {
  2. "events":[],
  3. "responses":[
  4. {
  5. "template":"utter_greet"
  6. }
  7. ]
  8. }