响应是机器人发送给用户的消息,它通常仅为文本,但也可以包括图像和按钮等内容。
1. 定义响应
响应位于域文件或单独的 responses.yml 文件,每个响应名称都应该以 utter_ 开头。例如,我们可以在响应名称 utter_greet 和 utter_bye 下添加问候和说再见的响应:
intents:- greetresponses:utter_greet:- text: "Hi there!"utter_bye:- text: "See you!"
如果使用了检索意图,则需要为这些意图添加响应:
# @file: domain.ymlintents:- chitchatresponses:utter_chitchat/ask_name:- text: Oh yeah, I am called the retrieval bot.utter_chitchat/ask_weather:- text: Oh, it does look sunny right now in Berlin.
:::warning
🛑 注意
——————————
请注意检索意图的响应名称的特殊格式,每个名称以 utter_ 开头,后面跟检索意图的名称(上例为 chitchat),最后是指定不同响应的后缀(此处为 ask_name 和 ask_weather)。
:::
1.1 在响应中使用变量
我们可以使用变量来将信息插入到响应中,变量用大括号括起来。下面的示例中,我们就使用了 name 变量:
responses:utter_greet:- text: "Hey, {name}. How are you?"
当使用 utter_greet 响应时,Rasa 会自动使用 name 插槽的值进行填充。如果这样的插槽不存在或为空,则变量将填充为 None。
填充变量的另一种方法是使用自定义操作,我们可以为响应提供值以填充特定变量。如果你使用 Rasa SDK 作为 Action Server,我们可以在 dispatcher.utter_message 函数中将变量作为参数来传递所需要的值。
dispatcher.utter_message(template="utter_greet",name="Sara")
如果我们使用其他的 Action Server,可以在服务器返回响应中添加额外参数来提供值:
{"events":[...],"responses":[{"template":"utter_greet","name":"Sara"}]}
1.2 随机响应
🛑 Rasa 官方上将随机响应称之为响应变体(Response Variations),个人觉得翻译成随机响应或随机回复会更好一点。
如果我们给响应名称添加了多种响应可供选择,那么机器人的回复将会更有意思。在下面例子中,当 utter_greet 被预测为下一个动作时,Rasa 将随机选择两个响应中随机选择一个来使用。
responses:utter_greet:- text: "Hey, {name}. How are you?"- text: "Hey, {name}. How is your day going?"
1.3 特定通道下的响应
如果需要根据用户连接到的通道指定不同的响应,那么我们可以使用特定通道的响应。在下面示例中,第一个响应中使用了 channel 键指定了 slack 通道,而第二个响应并未指定特殊通道:
responses:utter_ask_game:- text: "Which game would you like to play on Slack?"channel: "slack"- 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:
slots:logged_in:type: boolinfluence_conversation: Falsemappings:- type: customname:type: textinfluence_conversation: Falsemappings:- type: customresponses:utter_greet:- condition:- type: slotname: logged_invalue: truetext: "Hey, {name}. Nice to see you again! How are you?"- text: "Welcome. How is your day going?"
stories:- story: greetsteps:- action: action_log_in- slot_was_set:- logged_in: true- intent: greet- action: utter_greet
在上述示例中,第一个响应 Hey, {name}. Nice to see you again! How are you? 将在执行 utter_greet 操作且 logged_in 插槽为 true 时启用。第二个响应由于没有条件,将被视为默认值,在 logged_in 不等于 true 时启用。
:::danger
⌛ 警告
——————————
强烈建议始终提供无条件的默认响应变体,以防止在条件与填充插槽不匹配时没有响应。
:::
在对话期间,Rasa 将从所有满足约束条件的条件响应中进行选择。如果有多个符合条件的响应,Rasa 将随机选择一个。例如下面这个示例:
responses:utter_greet:- condition:- type: slotname: logged_invalue: truetext: "Hey, {name}. Nice to see you again! How are you?"- condition:- type: slotname: eligible_for_upgradevalue: truetext: "Welcome, {name}. Did you know you are eligible for a free upgrade?"- text: "Welcome. How is your day going?"
如果 logged_in 和 eligible_for_upgrade 都是 true 的情况下,那么第一个和第二个响应都可以使用,机器人将随机选择一个。我们可以继续使用特定通道的响应和天剑响应,如下面示例:
slots:logged_in:type: boolinfluence_conversation: Falsemappings:- type: customname:type: textinfluence_conversation: Falsemappings:- type: customresponses:utter_greet:- condition:- type: slotname: logged_invalue: truetext: "Hey, {name}. Nice to see you again on Slack! How are you?"channel: slack- text: "Welcome. How is your day going?"
Rasa 将按照以下顺序优先选择响应:
- 具有匹配通道的条件响应
- 具有匹配通道的默认响应
- 没有匹配通道的条件响应
- 没有匹配通道的默认响应
2. 富文本响应
我们可以通过添加视觉和交互元素来丰富回复,许多通道都支持多种类型的元素。2.1 按钮
以下是使用按钮的响应示例:responses:utter_greet:- text: "Hey! How are you?"buttons:- title: "great"payload: "/mood_great"- title: "super sad"payload: "/mood_sad"
按钮列表中的每个按钮都应该有两个键:
title:用户看到的按钮显示的文本payload:单击按钮时用户向机器人发送的消息
如果我们希望按钮也将实体传递给机器人:
responses:utter_greet:- text: "Hey! Would you like to purchase motor or home insurance?"buttons:- title: "Motor insurance"payload: '/inform{{"insurance":"motor"}}'- title: "Home insurance"payload: '/inform{{"insurance":"home"}}'
也可以通过以下方式传递多个实体:
'/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 意图的消息进行分类,并提取分别属于 ORG 和 GPE 类型的实体 Rasa 和 Germany。
🧬 在 DOMAIN.YML 中转义大括号
—————————————————
我们需要在 domain.yml 文件中使用双花括号编写 /intent{entities} 速记响应,以便机器人不会将其视为响应中的变量,并在花括号中插入内容。
:::
:::danger
⌛ 检查通道
—————————————————
请记住,如何显示定义的按钮取决于输出通道的实现。例如,某些通道可以提供的按钮数量是有限制的。
:::
2.1.1 案例:按钮+条件响应
| ```yaml version: “3.1”
nlu:
intent: greet examples: |
- hey
- hello
- hi
intent: goodbye examples: |
- 拜拜
- 再见
| ```yamlversion: "3.1"rules:- rule: 打招呼steps:- intent: greet- action: utter_greet- rule: 获取性别steps:- intent: set_gender- action: utter_gender
| | —- | —- |
version: '3.0'session_config:session_expiration_time: 60carry_over_slots_to_new_session: trueintents:- greet- goodbye- set_genderentities:- genderslots:gender:type: textinfluence_conversation: Falsemappings:- type: from_entityentity: genderresponses:utter_greet:- buttons:- payload: '/set_gender{{"gender": "male"}}'title: 男性- payload: '/set_gender{{"gender": "female"}}'title: 女性text: Hey! How are you?utter_gender:- condition:- type: slotname: gendervalue: maletext: "你好,先生"- text: "你好,女士"
$ rasa shellYour input -> hello2022-06-01 12:35:42 DEBUG rasa.core.processor - Received user message 'hello' with intent '{'name': 'greet', 'confidence': 0.9999994039535522}' and entities '[]'? Hey! How are you? (Use arrow keys)» 1: 男性 (/set_gender{"gender": "male"})2: 女性 (/set_gender{"gender": "female"})Type out your own message...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'}]'2022-06-01 12:36:27 DEBUG rasa.core.processor - Current slot values:gender: femalesession_started_metadata: None你好,先生
2.2 图像
我们可以通过在 image 键下提供图像的 URL 给响应添加图像:
utter_cheer_up:- text: "Here is something to cheer you up:"image: "https://i.imgur.com/nGF1K8f.jpg"
2.3 自定义输出有效载荷
我们可以使用 custom 键将任意输出发送到输出通道,输出通道接收存储在 custom 键下的对象作为 JSON 负载。以下是如何将日期选择器发送到 Slack 输出通道上的示例:
responses:utter_take_bet:- custom:blocks:- type: sectiontext:text: "Make a bet on when the world will end:"type: markdwnaccessory:type: datepickerinitial_date: '2019-05-21'placeholder:type: plain_texttext: Select a date
3. 在对话中使用响应
3.1 调用响应作为动作
如果响应的名称以 utter_ 开头,则响应可以直接用作操作,而无需在域文件中 actions 部分列出,我们在域文件中添加如下响应:
responses:utter_greet:- text: "Hey! How are you?"
我们可以在故事中使用相同的响应作为操作:
stories:- story: greet usersteps:- intent: greet- action: utter_greet
当 utter_greet 操作运行时,它会将响应中的消息发送回用户。
:::info
🧬 不断变化的响应
—————————————————
如果想更改文本或响应的任何其他部分,我们需要在更改之后重新训练。
:::
3.2 从自定义动作中调用响应
在自定义操作中,我们可以调用响应生成回复。如果使用的是 Rasa SDK 服务器,我们可以使用 dispatch 来生成响应消息:
from rasa_sdk.interfaces import Actionclass ActionGreet(Action):def name(self):return 'action_greet'def run(self, dispatcher, tracker, domain):dispatcher.utter_message(template="utter_greet")return []
如果使用的是其他 Action Server,那么我们应该返回如下 JSON 内容来调用 utter_greet 响应:
{"events":[],"responses":[{"template":"utter_greet"}]}
