Actions/Forms
最常見的對話模式之一是從用戶那里收集一些信息赌渣,以便做一些事情(預訂餐廳靶溜、調用API今瀑、搜索數(shù)據(jù)庫等)。這也稱為槽填充且警。
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>的響應來實現(xiàn)這一點徙邻,如果沒有找到前者排嫌。確保在域文件中為每個所需槽定義這些響應。
Activating a Form
要激活表單缰犁,您需要添加一個故事或規(guī)則淳地,它描述了助手應該在什么時候運行表單怖糊。在特定意圖觸發(fā)表單的情況下,你可以使用以下規(guī)則:
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將自動失效。你可以用一個規(guī)則或一個故事來描述你的助手在form結束的行為遣钳。如果您沒有添加一個適用的故事或規(guī)則扰魂,那么在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
用戶可能想要離開當前會話。關于如何為這種情況編寫故事或規(guī)則倦淀,請參閱 編寫故事/不快樂表單路徑規(guī)則蒋畜。
Slot Mapping
Rasa Open Source提供了四個預定義的映射,用于根據(jù)最新的用戶消息填充表單的槽晃听。如果您需要自定義函數(shù)來提取所需的信息百侧,請參見自定義槽映射。
from_entity
from_entity映射根據(jù)提取的實體填充槽能扒。它將尋找一個名為entity_name的實體來填充槽slot_name佣渴。如果intent_name為None,則無論意圖名稱如何初斑,槽都將被填滿辛润。否則,只有當用戶的意圖是intent_name時见秤,這個槽才會被填滿砂竖。
如果提供了role_name和/或group_name,則實體的角色/組標簽也需要匹配給定的值鹃答。如果消息的意圖是exclusided_intent乎澄,則槽映射將不應用。注意测摔,你也可以為參數(shù)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铡羡,則槽映射將不應用。注意意鲸,可以為參數(shù)intent和not_intent定義意圖列表烦周。如果消息的意圖是exclusided_intent,則槽映射將不應用怎顾。注意读慎,可以為參數(shù)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夭委,則槽映射將不應用。注意募强,您還可以為參數(shù)intent和not_intent定義意圖列表株灸。
注意:from_intent槽映射將不會在表單的初始激活期間應用。要根據(jù)激活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屹蚊,則槽映射將不應用。注意捆交,您還可以為參數(shù)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胃惜,如果用戶的輸入沒有填滿請求的槽,表單動作的執(zhí)行將被拒絕哪雕,即表單將自動引發(fā)ActionExecutionRejection船殉。以下是表單會引發(fā)ActionExecutionRejection的具體場景:
請求了一個詞槽,但是用戶沒有使用他們的最后一條消息填充插槽斯嚎,并且您沒有定義用于驗證插槽或提取插槽的自定義操作利虫。
一個slot被請求,但是您用于驗證slot或提取slot的自定義操作沒有返回任何SlotSet事件堡僻。
要有意拒絕表單執(zhí)行糠惫,還可以返回ActionExecutionRejected事件,作為自定義驗證或槽映射的一部分钉疫。
要處理可能導致表單執(zhí)行被拒絕的情況硼讽,可以編寫包含預期中斷的規(guī)則或事例。例如牲阁,如果你希望你的用戶與你的機器人聊天固阁,你可以添加一個規(guī)則來處理:
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操作過程中改變主意城菊,決定不再執(zhí)行最初的請求备燃。在這種情況下,助理應該停止索要所要求的插槽役电。
您可以使用默認動作action_deactivate_loop優(yōu)雅地處理這種情況赚爵,該動作將停用表單并重置所請求的槽。這類對話的一個例子如下:
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來構建這些規(guī)則或故事法瑟。如果你手寫這些規(guī)則/故事冀膝,你可能會錯過重要的東西。
Advanced Usage
表單可以使用自定義操作完全自定義霎挟。
Validating Form Input
從用戶輸入提取槽值后窝剖,可以驗證提取的槽。默認情況下酥夭,Rasa開放源碼只驗證在請求插槽后是否填充了插槽赐纱。
您可以實現(xiàn)一個自定義操作validate_<form_name>來驗證任何提取的槽。確保將這個動作添加到你的domain的動作部分:
actions:
- validate_restaurant_form
當表單被執(zhí)行時熬北,它將運行您的自定義操作疙描。
這個自定義操作可以擴展FormValidationAction類,以簡化驗證提取的槽的過程讶隐。在本例中起胰,需要為每個提取的槽編寫名為validate_<slot_name>的函數(shù)。
下面的示例顯示了一個自定義操作的實現(xiàn)巫延,該操作驗證名為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以完全自定義驗證過程。