机器人通常需要向用户询问信息来帮助他们,我们可以使用表单来收集必需的用户信息和实现一个请求。对话机器人通常支持用户目标,包括在为用户做某些事情之前从用户那里收集所需的信息。例如,餐厅搜索机器人需要收集一些有关用户偏好的信息才能为他们找到合适的餐厅。
本篇文档介绍的是在收集用户信息时业务逻辑的处理,从而实现一个请求。在上面示例中,业务逻辑包括用户的偏好美食、聚会规模和座位偏好。
1. 使用表单来处理业务逻辑的分步指南
表单通过提示用户输入信息进行工作,直到它收集到所有必需的信息,该信息存储在插槽中。一旦所有插槽被填满,机器人就会满足用户的初始请求。
1.1 定义表单
要定义表单,我们需要定义:
你可以在域文件(domain.yml)定义表单,并在表单名称下指定所需插槽的列表:
forms:
restaurant_form:
required_slots:
- cuisine
- num_people
- outdoor_seating
这些插槽需要添加到领域中 slots
部分,以及定义填充插槽时的插槽映射。对于任何 from_entity
填充的插槽,该实体还需要添加到域(domain.yml)中。表单填充的插槽通常不应该影响对话,所以我们需要将 influence_conversation
设置为 false
:
entities:
- cuisine
- number
slots:
cuisine:
type: text
mappings:
- type: from_entity
entity: cuisine
num_people:
type: float
mappings:
- type: from_entity
entity: number
outdoor_seating:
type: bool
mappings:
- type: from_intent
intent: affirm
value: true
conditions:
- active_loop: restaurant_form
requested_slot: outdoor_seating
- type: from_intent
intent: deny
value: false
conditions:
- active_loop: restaurant_form
requested_slot: outdoor_seating
number
插槽是由实体填充,DucklingEntityExtractor
可以提取数字等实体,要使用 DucklingEntityExtractor
需要在 NLU 管道(config.yml)中添加。
language: en
pipeline:
# other components
- name: DucklingEntityExtractor
dimensions: ["number"]
2)带条件的插槽映射
根据用户的意图来填充 outdoor_seating
插槽,如果是 affirm
,则插槽值为 true
;如果是 deny
,则为 false
。
但是,如果用户正在回答“你想坐在外面吗?”这个问题,则该插槽只可以设置为 true
或 false
。为了强制执行此条件,outdoor_seating
插槽条件要求 restaurant_form
处于活跃状态,并且要求插槽是 outdoor_seating
。如果没有条件,并且用户在早些时候发送了带有确认或拒绝意图的消息,则在激活表单时就已经填充了 outdoor_seating
插槽。因此,该表格不会提示用户选择户外座位。
3)验证插槽
通常,我们需要在接受用户输入之前对其进行验证,例如通过检查给定的菜系是否在机器人可用的菜系数据库中。
4)请求插槽
要指定机器人应该如何询问所需信息,我们可以在域文件(domain.yml)中定义名为 utter_ask_{slotname}
的响应:
responses:
utter_ask_cuisine:
- text: "What cuisine?"
utter_ask_num_people:
- text: "How many people?"
utter_ask_outdoor_seating:
- text: "Do you want to sit outside?"
1.2 更新配置
表单的常规对话路径应该定义为规则,这意味着你需要将 RulePolicy
添加到域文件中(domain.yml)的策略中:
policies:
- name: RulePolicy
1.3 创建规则
表单负责向用户询问所有必需信息的逻辑,因此我们只需要两个规则来实现表单的常规对话路径:一种是定义何时开始,另一种则是定义会发生什么。对于餐厅搜索示例,在现实生活中,机器人根据用户的喜好查找餐厅。在下面这个规则示例(rules.yml)中,机器人将发出一个包含用于搜索详细信息的响应。
rules:
- rule: activate restaurant form
steps:
- intent: request_restaurant # intent that triggers form activation
- action: restaurant_form # run the form
- active_loop: restaurant_form # this form is active
- rule: submit form
condition:
- active_loop: restaurant_form # this form must be active
steps:
- action: restaurant_form # run the form
- active_loop: null # the form is no longer active because it has been filled
- action: utter_submit # action to take after the form is complete
- action: utter_slots_values # action to take after the form is complete
通过拆分表单的激活和提交,如果用户提供意外输入或者闲聊中断表单,规则仍然适用。
1.4 更新NLU训练数据
我们需要为激活表单的意图添加示例,以及用户将如何提供所需信息的示例。
1)表单激活意图
我们需要为激活表单的意图(nlu.yml)添加训练示例,为意图 request_restaurant
添加示例:
nlu:
- intent: request_restaurant
examples: |
- im looking for a restaurant
- can i get [swedish](cuisine) food in any area
- a restaurant that serves [caribbean](cuisine) food
- id like a restaurant
- im looking for a restaurant that serves [mediterranean](cuisine) food
- can i find a restaurant that serves [chinese](cuisine)
用 from_entity
填充的插槽可以被任何用户话语填充,无论何种意图,只要提取了正确的实体。这意味着,如果用户在他们的第一条消息中提供了 cuisine
实体,则该位置将在表单的开头填充,并且机器人不会再次向他们询问美食。
2)表单填充意图
当表单填充查插槽时,它不会注意预测的是哪个意图,除非插槽映射明确要求或排除意图。对于餐厅搜索示例,outdoor_seating
插槽被映射到两个意图上,所以你需要为这些意图添加训练数据。
对于 cuisine
和 number
插槽,因为未指定意图,因此我们可以向通用 inform
意图添加示例。我们需要来标注 cuisine
实体,以便 DIETClassifier
可以学习提取它。我们不需要标注 number
实体,因为 DucklingEntityExtractor
是一种基于规则的提取器,未针对训练数据进行训练。每个意图仅显示几个示例,为了能让机器人正常工作,我们应该添加此处显示的更多训练数据:
nlu:
- intent: affirm
examples: |
- Yes
- yes, please
- yup
- intent: deny
examples: |
- no don't
- no
- no I don't want that
- intent: inform
examples: |
- [afghan](cuisine) food
- how bout [asian oriental](cuisine)
- what about [indian](cuisine) food
- uh how about [turkish](cuisine) type of food
- um [english](cuisine)
- im looking for [tuscan](cuisine) food
- id like [moroccan](cuisine) food
- for ten people
- 2 people
- for three people
- just one person
- book for seven people
- 2 please
- nine people
更新域文件来包含以下意图:
intents:
- request_restaurant
- affirm
- deny
- inform
1.5 定义响应
在域文件(domain.yml)中添加提交表单后发送的响应:
responses:
utter_submit:
- text: "All done!"
utter_slots_values:
- text: "I am going to run a restaurant search using the following parameters:\n
- cuisine: {cuisine}\n
- num_people: {num_people}\n
- outdoor_seating: {outdoor_seating}"
2. 总结
表单可以简化收集用户消息的逻辑,要定义像上面的餐厅搜索示例这样的最小表单,以下是我们需要执行的操作流程:
- 在配置文件 config.yml 中添加
RulePolicy
策略 - 在域中定义所需插槽的表单
- 在域中给所有必需的插槽添加插槽映射
- 添加激活和提交表单的规则
- 添加用于激活表单的意图示例
- 添加用于填充必要插槽的意图示例
- 定义表单完成后机器人要采取的操作或响应
- 使用定义的新意图和动作来更新领域
要尝试新定义的表单,请通过运行 rasa train
来重新训练模型,然后通过 rasa shell
来启动。由于 DucklingEntityExtractor 用于提取实体,因此我们在后台启动 Duckling
。