响应是机器人发送给用户的消息,它通常仅为文本,但也可以包括图像和按钮等内容。
1. 定义响应
响应位于域文件或单独的 responses.yml 文件,每个响应名称都应该以 utter_
开头。例如,我们可以在响应名称 utter_greet
和 utter_bye
下添加问候和说再见的响应:
intents:
- greet
responses:
utter_greet:
- text: "Hi there!"
utter_bye:
- text: "See you!"
如果使用了检索意图,则需要为这些意图添加响应:
# @file: domain.yml
intents:
- chitchat
responses:
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: bool
influence_conversation: False
mappings:
- type: custom
name:
type: text
influence_conversation: False
mappings:
- type: custom
responses:
utter_greet:
- condition:
- type: slot
name: logged_in
value: true
text: "Hey, {name}. Nice to see you again! How are you?"
- text: "Welcome. How is your day going?"
stories:
- story: greet
steps:
- 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: slot
name: logged_in
value: true
text: "Hey, {name}. Nice to see you again! How are you?"
- condition:
- type: slot
name: eligible_for_upgrade
value: true
text: "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: bool
influence_conversation: False
mappings:
- type: custom
name:
type: text
influence_conversation: False
mappings:
- type: custom
responses:
utter_greet:
- condition:
- type: slot
name: logged_in
value: true
text: "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: |
- 拜拜
- 再见
| ```yaml
version: "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: 60
carry_over_slots_to_new_session: true
intents:
- greet
- goodbye
- set_gender
entities:
- gender
slots:
gender:
type: text
influence_conversation: False
mappings:
- type: from_entity
entity: gender
responses:
utter_greet:
- buttons:
- payload: '/set_gender{{"gender": "male"}}'
title: 男性
- payload: '/set_gender{{"gender": "female"}}'
title: 女性
text: Hey! How are you?
utter_gender:
- condition:
- type: slot
name: gender
value: male
text: "你好,先生"
- text: "你好,女士"
$ rasa shell
Your input -> hello
2022-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: female
session_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: section
text:
text: "Make a bet on when the world will end:"
type: markdwn
accessory:
type: datepicker
initial_date: '2019-05-21'
placeholder:
type: plain_text
text: Select a date
3. 在对话中使用响应
3.1 调用响应作为动作
如果响应的名称以 utter_
开头,则响应可以直接用作操作,而无需在域文件中 actions
部分列出,我们在域文件中添加如下响应:
responses:
utter_greet:
- text: "Hey! How are you?"
我们可以在故事中使用相同的响应作为操作:
stories:
- story: greet user
steps:
- intent: greet
- action: utter_greet
当 utter_greet
操作运行时,它会将响应中的消息发送回用户。
:::info
🧬 不断变化的响应
—————————————————
如果想更改文本或响应的任何其他部分,我们需要在更改之后重新训练。
:::
3.2 从自定义动作中调用响应
在自定义操作中,我们可以调用响应生成回复。如果使用的是 Rasa SDK 服务器,我们可以使用 dispatch
来生成响应消息:
from rasa_sdk.interfaces import Action
class 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"
}
]
}