有时候我们希望机器人在没有用户提示的情况下与用户联系,例如,如果希望机器人在用户打开聊天窗口时发出消息,或者希望在用户有一段时间没有发送消息时提示用户。
1. 首次接触
在大多数案例中,当用户打开机器人的聊天窗口时,我们希望机器人发送第一条消息。这样做可以让用户了解机器人能做什么和不能做什么,并让他们进行更成功的对话。某些消息或语音通道具备现有配置选项,可以在用户首次开始对话时向机器人发送有效负载,但我们也可以将此选项添加到自定义通道中。
将频道配置为发送有效负载后,需要制定机器人应该如何反应和问候用户。我们可以为此重新使用现有意图的行为,也可以为此制定新的意图和规则。以下是有关如何制定欢迎规则的示例。
1.1 更新配置
由于我们为此行为使用规则,所以需要将RulePolicy
添加到配置文件中:
policies:
- name: RulePolicy
1.2 添加规则
要让机器人仅在对话开始时使用欢迎消息响应greet
意图,需要添加以下规则:
rules:
- rule: welcome user
# this rule only applies at the beginning of a conversation
conversation_start: true
step:
- intent: greet
- action: utter_welcome
1.3 添加响应
最后,将utter_welcome
回复添加到领域中:
responses:
utter_welcome:
- text: "Hi there! What can I help you with today?"
2. 外部事件
有时我们希望外部设备改变正在进行的对话过程,例如,如果我们在 Raspberry Pi(树莓派)上连接了一个传感器,我们可以使用它通过机器人在植物需要浇水的时候进行通知。
2.1 触发意图
要让来自外部设备的事件更改正在进行的对话过程,我们可以让设备发送请求到对话的trigger_intent
端点,trigger_intent
端点将用户意图(可能带有实体)注入到对话中。对于 Rasa,就好像我们输入了一条按照特定意图和实体分类的消息。然后,机器人将像往常一样预测并执行下一个动作。
例如,以下请求会将EXTERNAL_dry_plant
意图和plant
实体注入到 ID 为user123
的对话中:
$ curl -H "Content-Type: application/json" \
-X POST \
-d '{
"name": "EXTERNAL_dry_plant",
"entities": {"plant": "Orchid"}
}' \
"http://localhost:5005/conversations/user123/trigger_intent?output_channel=latest"
2.2 获取对话ID
在现实生过中,外部设备会从 API 或数据库中获取对话 ID。在给植物浇水示例中,我们可能有一个植物数据库、给植物浇水的用户以及用户的对话 ID。树莓派将直接从数据中获取对话 ID,要在本地用提醒机器人示例,我们还需要手动获取对话 ID。
2.3 添加NLU训练数据
在给植物浇水示例中,树莓派需要将带有EXTERNAL_dry_plant
意图的消息发送到trigger_intent
端点。此意图将保留给树莓派使用,因此不会有任何 NLU 训练样本。
intents:
- EXTERNAL_dry_plant
:::info
💡 注意
——————————
我们应该使用EXTERNAL_
前缀命名来自其他设备的意图,因为这样在处理训练数据时,可以更轻松地查看哪些意图来自外部设设备。
:::
2.4 更新领域
要告诉机器人哪种植物需要浇水,我们可以定义一个实体,并将其与意图一起作为请求发送出去。为了能够直接在响应中使用实体值,需要为给plant
插槽定义from_entity
插槽映射:
entities:
- plant
slots:
plant:
type: text
influence_conversation: false
mappings:
- type: from_entity
entity: plant
2.5 添加规则
我们需要一个规则来告诉机器人在收到树莓派消息时如何响应:
rules:
- rule: warn about dry plant
steps:
- intent: EXTERNAL_dry_plant
- action: utter_warn_dry
2.6 添加响应
我们需要为utter_warn_dry
定义响应文本:
responses:
utter_warn_dry:
- text: "Your {plant} needs some water!"
2.7 尝试一下
要尝试给植物浇水的示例,我们需要启动 Rasa X 或 CallbackChannel。
:::info
🔔 当心
————————————
外部事件和提醒在请求-响应通道(例如test
通道或者rasa shell
)中不起作用,实现提醒或外部事件的机器人自定义连接器应该建立在CallbackInput
通道而不是RestInput
通道之上。
:::
使用会话 ID,在终端中执行以下 POST 请求来模拟外部事件:
$ curl -H "Content-Type: application/json" \
-X POST -d '{
"name": "EXTERNAL_dry_plant",
"entities": {"plant": "Orchid"}
}' \
"http://localhost:5005/conversations/user1234/trigger_intent?output_channel=latest"
3. 提醒器
我们可以使用提醒让机器人在设定时间后与用户进行联系,以下介绍的是提醒机器人示例,我们可以克隆项目并按照 README 中的说明尝试完整版。
3.1 调度提醒器
1)定义提醒器
为了调度提醒器,我们需要定义一个返回ReminderScheduled
事件的自定义操作。例如,以下自定义操作会在五秒后进行提醒:
import datetime
from rasa_sdk.events import ReminderScheduled
from rasa_sdk import Action
class ActionSetReminder(Action):
"""Schedules a reminder, supplied with the last message's entities."""
def name(self) -> Text:
return "action_set_reminder"
async def run(
self,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any],
) -> List[Dict[Text, Any]]:
dispatcher.utter_message("I will remind you in 5 seconds.")
date = datetime.datetime.now() + datetime.timedelta(seconds=5)
entities = tracker.latest_message.get("entities")
reminder = ReminderScheduled(
"EXTERNAL_reminder",
trigger_date_time=date,
entities=entities,
name="my_reminder",
kill_on_user_message=False,
)
return [reminder]
ReminderScheduled
事件的第一个参数是提醒的名称,上述示例中为EXTERNAL_reminder
。提醒器名称稍后将用作触发对提醒器操作的意图。使用EXTERNAL_
前缀命名的提醒器名称,可以更方便地查看训练数据中的情况。
我们可以看到最后一条消息的实体也传递给了提醒器,这允许对提醒器作出反应的动作能充分利用用户的调度信息。
例如,如果我们想让机器人提醒给朋友打电话,你可以给它发送一条消息,比如“提醒我给保罗打电话”。如果“保罗”被提取为PERSON
实体,则对提醒器作出反应的动作就可以使用该实体,并回复“记得给保罗打电话”。
2)添加规则
为了调度提醒器,我们还需要添加一条规则:
rules:
- rule: Schedule a reminder
steps:
- intent: ask_remind_call
entities:
- PERSON
- action: action_schedule_reminder
3)添加训练数据
我们应该添加 NLU 训练数据来调度提醒器:
nlu:
- intent: ask_remind_call
examples: |
- remind me to call John
- later I have to call Alan
- Please, remind me to call Vova
- please remind me to call Tanja
- I must not forget to call Juste
同时,我们还需要将其添加到领域中:
intents:
- ask_remind_call
4)更新管道
通过在配置文件 config.yml 的管道中添加SpacyNLP
和SpacyEntityExtractor
,我们无需训练数据中注释任何名称,因为Spacy
本身具备PERSON
维度:
pipeline:
- name: SpacyNLP
model: "en_core_web_md"
- name: SpacyEntityExtractor
dimensions: ["PERSON"]
3.2 对提醒作出反应
1)定义反应
在收到trigger_intent
端点的 POST 请求后,机器人会联系用户。但是,提醒会在一定时间后使用我们在ReminderScheduled
事件中定义的名称,自动将请求发送到正确的对话 ID。
要定义对提醒的反应,我们仅需要编写一个规则,告诉机器人在收到提醒意图时要采取什么动作。在呼叫提醒示例中,我们希望通过使用提醒器附带的实体,从而提醒呼叫特定的人,因此我们需要编写自定义操作来执行此操作:
class ActionReactToReminder(Action):
"""Reminds the user to call someone."""
def name(self) -> Text:
return "action_react_to_reminder"
async def run(
self,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any],
) -> List[Dict[Text, Any]]:
name = next(tracker.get_slot("PERSON"), "someone")
dispatcher.utter_message(f"Remember to call {name}!")
return []
2)添加规则
要告诉机器人在触发提醒时要运行什么操作,需要添加相对应的规则:
rules:
- rule: Trigger `action_react_to_reminder` for `EXTERNAL_reminder`
steps:
- intent: EXTERNAL_reminder
- action: action_react_to_reminder
3)添加训练数据
我们需要定义触发对提醒作出反应的意图,这并不需要我们添加任何示例,因为意图是为提醒保留的。
intents:
- intent: EXTERNAL_reminder
3.3 取消提醒
1)定义取消提醒的动作
要取消已经安排的提醒,我们需要一个返回ReminderCancelled
事件的自定义操作。返回ReminderCancelled
会取消当前安排的所有提醒。如果只是想取消某些提醒,我们可以指定一些参数来缩小计划提醒的范围:
ReminderCancelled(intent="EXTERNAL_greet")
取消所有EXTERNAL_greet
意图的提醒ReminderCancelled(entities={})
取消给定实体的所有提醒ReminderCancelled("...")
取消在创建过程中提供的具有给定名称的唯一提醒
对于来电提醒示例,我们可以定义取消所有提醒的自定义操作action_forget_reminders
:
class ForgetReminders(Action):
"""Cancels all reminders."""
def name(self) -> Text:
return "action_forget_reminders"
async def run(
self,
dispatcher,
tracker: Tracker,
domain: Dict[Text, Any]
) -> List[Dict[Text, Any]]:
dispatcher.utter_message(f"Okay, I'll cancel all your reminders.")
# Cancel all reminders
return [ReminderCancelled()]
:::info
🔔 当心
————————————
每当我们关闭 Rasa 服务器时,所有提醒都会取消。
:::
2)添加规则
我们需要添加取消提醒的规则:
rules:
- rule: Cancel a reminder
steps:
- intent: ask_forget_reminders
- action: action_forget_reminders
3)添加训练数据
我们需要定义一个触发取消提醒的意图:
nlu:
- intent: ask_forget_reminders
examples: |
- Forget about the reminder
- do not remind me
- cancel the reminder
- cancel all reminders please
并且我们需要将其添加到领域文件中去:
intents:
- intent: ask_forget_reminders
3.4 尝试一下
要尝试提醒,我们需要启动 Rasa X 或 CallbackChannel
。除此之外,我们还需要启动操作服务器来调度、响应和取消提醒。
然后,如果向机器人发送提醒(例如“提醒我给保罗打电话”),我们应该会在 5 秒后收到一条提醒,上面写着“记得给保罗打电话”。