目录
前言
本文主要分享一下个人在使用rasa2开发对话机器人过程中踩过的一些坑和些许流程设计经验。
配置:Win10,python 3.6,rasa2.8.4
很多一搜就有的分享我就不再一一重复,人家已经写的很好了,本次主要聊点不常见的东西。
- 自定义action
- form使用与槽位控制
-
Boolean Slot和Categorical Slot
-
条件控制与流程跳转
时间充足或感兴趣的朋友可以顺序阅读,也可以根据自己的需要从目录直接进入相关部分。
自定义action
官方说明“A custom action is an action that can run any code you want.”,any code you want,意义不言而喻。rasa有很多policy,不同的policy有不同的机制,根据policy预测出action进而执行。乐观情况下,对话会按照剧本(story)进行,走到哪个action,执行相应动作。简单的Response行为直接回复一句话,定义在domain的responses小节,在story里面引用就行。
如果对话进行到这一步,想执行复杂一些的操作,比如,连数据库、修改slot、entity、调用API,就可以在actions.py中新增一个action类。
class BookHT(Action):
"""
此类用于完成业务后登记信息,比如有名字、年龄
预先在domain文件中定义了两个槽位:name-名字,age-年龄
使用mongodb存储数据
"""
def name(self) -> Text:
return "action_register" # action名字
def run(
self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict
) -> List[EventType]:
# 从tracker取出信息
user_name = tracker.get_slot('name')
user_age = tracker.get_slot('age')
res = my_set.insert_one({"name": user_name, "age": user_age}) # 信息入库
book_date = str(date.today())
# 告诉用户,信息已登记
dispatcher.utter_message(response="utter_restaurant", date=book_date)
return [SlotSet('use_search', False)] # 关闭控制变量,后续说明作用
form使用与槽位控制
form可用于槽位的自动收集,需在domain中定义form和form所需槽位,一般情况下,槽位值来自实体值,type需设置为from_entity,具体如下:
# domain.yml
entities: # 实体定义 - name - ageslots: # 槽位定义 age: type: text influence_conversation: false auto_fill: true name: type: text influence_conversation: false auto_fill: true control: influence_conversation: true type: categoricalforms: # form定义,槽位名和实体名不用一致,此处凑巧 test_form: required_slots: name: - type: from_entity entity: name age: - type: from_entity entity: age
from可以开启也可以关闭,一般在story中开启,在rule中关闭。在story中开启,好理解一些,比如有个预约活动的story,由“我要参加活动”这样的intent触发,即可开启form。之所以不在story中关闭,是因为story的触发前提一般是intent,intent主要由用户触发。很难要求用户知道有一个form在运行,然后明确说出“我要停止form”吧。在rule中可以由条件触发,这个条件我们自己设置,用户无感知。
开启form
- story: not_book steps: - checkpoint: check_book # 流程分支 - slot_was_set: # 分支条件检验 - form_state: true - action: action_stop_search # 修改变量值 # 开启form - action: test_form - active_loop: test_form
关闭from
- rule: stop_form condition: - active_loop: test_form steps: - action: test_form - active_loop: null - slot_was_set: # 不可缺少 - requested_slot: null - action: action_register
最初我关闭form缺少对 requested_slot的修改,form结束时,对话不太正常,多返回一个【】空消息,应当是便利form发现没有缺失槽位,返回空。如果加上requested_slot: null,大概不用再去遍历槽位,少了这个环节也就没有多余的返回了。
# 错误示例,缺少requested_slot - rule: stop_form condition: - active_loop: test_form steps: - action: test_form - active_loop: null - action: action_register
Boolean Slot和Categorical Slot
布尔槽位最多产生两个分支,通常应用于是否分支,如酒店登记:已预订和未预订
# 已预订
- story: is_book
steps:
- checkpoint: check_book # 流程分支
- slot_was_set: # 分支条件检验
- book_state: true
- action: utter_book_info #
# 未预订
- story: not_book
steps:
- checkpoint: check_book # 流程分支
- slot_was_set: # 分支条件检验
- book_state: false
- action: action_stop_search # 修改变量值
# 开启form
- action: test_form
- active_loop: test_form
注意:
布尔槽位必须成对使用,比如我只关心预订的分支怎么走,没预订就不管了,在story只配置一个分支,训练rasa core会报错。因为对话很可能不按剧本发展,比如用户就是没预订,那机器人就要凌乱了。
但是使用类别槽位(categorical slot)不会这样,系统会自动补充一个default分类,所以我只设置预订分支也是可以的。类别槽位最强的作用是可以产生2个以上分支,3个5个分支,布尔槽位肯定是办不到的。
条件控制与流程跳转
- 通过checkpoint与主story关联
- 在每个checkpoint设置不同变量值,控制是否执行该分支
- story: main_progress
...... # 处理业务
- action: action_change_value # 修改变量,以便后续checkpoint得到对应变量值
- checkpoint: task
- story: sub_progressA
- checkpoint: task
- slot_was_set:
- control: A
......
- story: sub_progressB
- checkpoint: task
- slot_was_set:
- control: B
......
- story: sub_progressC
- checkpoint: task
- slot_was_set:
- control: C
......
注意:
slot_was_set,并不是动作,不会完成赋值操作,而是检查某变量是否被赋予值(如text类型slot),是否被赋予指定值(如boolean slot和categorical slot)。满足条件,对话才能按照happy path往下进行。因此,可以在主流程中完成控制变量的赋值,比如action: action_change_value ,在子流程校验并通行。