Actions/Forms
最常见的对话模式之一是从用户那里收集一些信息,以便做一些事情(预订餐厅、调用API、搜索数据库等)。这也称为槽填充。
Usage
要使用Rasa Open Source表单,您需要确保将Rule Policy添加到策略配置中。例如:
policies:
- name: RulePolicy
Defining a Form
在domain文件中配置forms。form的名称和stories或rules使用的名称一致。同时还要定义槽值映射关系,每个form可以设置一个或多个槽值映射关系。
下面的示例为:restaurant_form中配置从实体cuisine中填充槽cuisine,从实体number中填充槽num_people。
forms:
restaurant_form:
required_slots:
cuisine:
- type: from_entity
entity: cuisine
num_people:
- type: from_entity
entity: number
可以在ignored_intents键下为整个表单定义一个要忽略的意图列表。在ignored_intents下列出的intent将被添加到表单中每个槽映射的not_intent键中。
例如,当意图是chitchat时,如果你不希望表单中任何需要的槽被填满,那么你需要定义以下内容(在表单名称后面和ignored_intents关键字下面):
forms:
restaurant_form:
ignored_intents:
- chitchat
required_slots:
cuisine:
- type: from_entity
entity: cuisine
num_people:
- type: from_entity
entity: number
一旦表单操作第一次被调用,表单就会被激活,并提示用户输入下一个所需的槽值。它通过查找一个名为utter_ask<form_name><slot_name>或utter_ask_<slot_name>的响应来实现这一点,如果没有找到前者。确保在域文件中为每个所需槽定义这些响应。
Activating a Form
要激活表单,您需要添加一个故事或规则,它描述了助手应该在什么时候运行表单。在特定意图触发表单的情况下,你可以使用以下规则:
rules:
- rule: Activate form
steps:
- intent: request_restaurant
- action: restaurant_form
- active_loop: restaurant_form
注意:active_loop: restaurant_form步骤表示在运行restaurant_form之后应该激活该表单。
Deactivating a Form
一旦词槽都填充完毕后,form将自动失效。你可以用一个规则或一个故事来描述你的助手在form结束的行为。如果您没有添加一个适用的故事或规则,那么在form完成后,助手将自动listen下一个用户消息。下面的示例在your_form表单填满所有需要的槽后运行utter_all_slots_filled语句。
rules:
- rule: Submit form
condition:
# Condition that form is active.
- active_loop: restaurant_form
steps:
# Form is deactivated
- action: restaurant_form
- active_loop: null
- slot_was_set:
- requested_slot: null
# The actions we want to run when the form is submitted.
- action: utter_submit
- action: utter_slots_values
用户可能想要离开当前会话。关于如何为这种情况编写故事或规则,请参阅 编写故事/不快乐表单路径规则。
Slot Mapping
Rasa Open Source提供了四个预定义的映射,用于根据最新的用户消息填充表单的槽。如果您需要自定义函数来提取所需的信息,请参见自定义槽映射。
from_entity
from_entity映射根据提取的实体填充槽。它将寻找一个名为entity_name的实体来填充槽slot_name。如果intent_name为None,则无论意图名称如何,槽都将被填满。否则,只有当用户的意图是intent_name时,这个槽才会被填满。
如果提供了role_name和/或group_name,则实体的角色/组标签也需要匹配给定的值。如果消息的意图是exclusided_intent,则槽映射将不应用。注意,你也可以为参数intent和not_intent.ation定义意图列表。
forms:
your_form:
required_slots:
slot_name:
- type: from_entity
entity: entity_name
role: role_name
group: group name
intent: intent_name
not_intent: excluded_intent
在' from_entity '映射中,当一个提取的实体唯一地映射到一个插槽时,即使这个插槽没有被表单请求,这个插槽也会被填满。如果映射不是唯一的,则提取的实体将被忽略。
forms:
your_form:
required_slots:
departure_city:
- type: from_entity
entity: city
role: from
- type: from_entity
entity: city
arrival_city:
- type: from_entity
entity: city
role: to
- type: from_entity
entity: city
arrival_date:
- type: from_entity
entity: date
在上面的示例中,实体date 唯一填充词槽arrival_date,实体city对应角色from 唯一填充词槽departure_city,实体city对应角色to唯一填充词槽arrival_city,因此如果其中某个词槽没有请求他们可以用来配合来进行相应的词槽填充。但是,实体city不包含角色可以填充词槽departure_city和arrival_city,这取决于请求的是哪个词槽,所以如果在请求词槽arrival_date时提取了一个实体city,那么它将被form忽略。
form_text
from_text映射将使用下一个用户语句来填充词槽slot_name。如果intent_name为None,则无论意图名称如何,槽都将被填满。否则,只有当用户的意图是intent_name时,这个槽才会被填满。
如果消息的意图是exclusided_intent,则槽映射将不应用。注意,可以为参数intent和not_intent定义意图列表。如果消息的意图是exclusided_intent,则槽映射将不应用。注意,可以为参数intent和not_intent定义意图列表。
forms:
your_form:
required_slots:
slot_name:
- type: from_text
intent: intent_name
not_intent: excluded_intent
form_intent
如果用户意图为intent_name或None, from_intent映射将用my_value填充词槽 slot_name。如果消息的意图是exclusided_intent,则槽映射将不应用。注意,您还可以为参数intent和not_intent定义意图列表。
注意:from_intent槽映射将不会在表单的初始激活期间应用。要根据激活form的意图填充一个槽,可以使用from_trigger_intent映射。
forms:
your_form:
required_slots:
slot_name:
- type: from_intent
value: my_value
intent: intent_name
not_intent: excluded_intent
form_trigger_intent
from_trigger_intent映射将用my_value填充slot slot_name,如果表单是由一个用户消息用意图 intent_name激活的。如果消息的意图是exclusided_intent,则槽映射将不应用。注意,您还可以为参数intent和not_intent定义意图列表。
forms:
your_form:
required_slots:
slot_name:
- type: from_trigger_intent
value: my_value
intent: intent_name
not_intent: excluded_intent
Writing Stories / Rules for Unhappy Form Paths
您的用户并不总是响应您要求他们提供的信息。通常情况下,用户会问问题、聊天、改变主意,或者以其他方式偏离快乐的道路。
当一个表单是active,如果用户的输入没有填满请求的槽,表单动作的执行将被拒绝,即表单将自动引发ActionExecutionRejection。以下是表单会引发ActionExecutionRejection的具体场景:
请求了一个词槽,但是用户没有使用他们的最后一条消息填充插槽,并且您没有定义用于验证插槽或提取插槽的自定义操作。
一个slot被请求,但是您用于验证slot或提取slot的自定义操作没有返回任何SlotSet事件。
要有意拒绝表单执行,还可以返回ActionExecutionRejected事件,作为自定义验证或槽映射的一部分。
要处理可能导致表单执行被拒绝的情况,可以编写包含预期中断的规则或事例。例如,如果你希望你的用户与你的机器人聊天,你可以添加一个规则来处理:
rules:
- rule: Example of an unhappy path
condition:
# Condition that form is active.
- active_loop: restaurant_form
steps:
# This unhappy path handles the case of an intent `chitchat`.
- intent: chitchat
- action: utter_chitchat
# Return to form after handling the `chitchat` intent
- action: restaurant_form
- active_loop: restaurant_form
在某些情况下,用户可能会在form操作过程中改变主意,决定不再执行最初的请求。在这种情况下,助理应该停止索要所要求的插槽。
您可以使用默认动作action_deactivate_loop优雅地处理这种情况,该动作将停用表单并重置所请求的槽。这类对话的一个例子如下:
stories:
- story: User interrupts the form and doesn't want to continue
steps:
- intent: request_restaurant
- action: restaurant_form
- active_loop: restaurant_form
- intent: stop
- action: utter_ask_continue
- intent: stop
- action: action_deactivate_loop
- active_loop: null
强烈建议您使用 interactive learning来构建这些规则或故事。如果你手写这些规则/故事,你可能会错过重要的东西。
Advanced Usage
表单可以使用自定义操作完全自定义。
Validating Form Input
从用户输入提取槽值后,可以验证提取的槽。默认情况下,Rasa开放源码只验证在请求插槽后是否填充了插槽。
您可以实现一个自定义操作validate_<form_name>来验证任何提取的槽。确保将这个动作添加到你的domain的动作部分:
actions:
- validate_restaurant_form
当表单被执行时,它将运行您的自定义操作。
这个自定义操作可以扩展FormValidationAction类,以简化验证提取的槽的过程。在本例中,需要为每个提取的槽编写名为validate_<slot_name>的函数。
下面的示例显示了一个自定义操作的实现,该操作验证名为cuisine的槽是否有效。
from typing import Text, List, Any, Dict
from rasa_sdk import Tracker, FormValidationAction
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk.types import DomainDict
class ValidateRestaurantForm(FormValidationAction):
def name(self) -> Text:
return "validate_restaurant_form"
@staticmethod
def cuisine_db() -> List[Text]:
"""Database of supported cuisines"""
return ["caribbean", "chinese", "french"]
def validate_cuisine(
self,
slot_value: Any,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: DomainDict,
) -> Dict[Text, Any]:
"""Validate cuisine value."""
if slot_value.lower() in self.cuisine_db():
# validation succeeded, set the value of the "cuisine" slot to value
return {"cuisine": slot_value}
else:
# validation failed, set this slot to None so that the
# user will be asked for the slot again
return {"cuisine": None}
您还可以扩展Action类并使用跟踪器检索提取的槽。Slots_to_validate以完全自定义验证过程。