🚀 原文地址:https://rasa.com/docs/rasa/business-logic

机器人通常需要向用户询问信息来帮助他们,我们可以使用表单来收集必需的用户信息和实现一个请求。对话机器人通常支持用户目标,包括在为用户做某些事情之前从用户那里收集所需的信息。例如,餐厅搜索机器人需要收集一些有关用户偏好的信息才能为他们找到合适的餐厅。
image.png

本篇文档介绍的是在收集用户信息时业务逻辑的处理,从而实现一个请求。在上面示例中,业务逻辑包括用户的偏好美食、聚会规模和座位偏好。

1. 使用表单来处理业务逻辑的分步指南

表单通过提示用户输入信息进行工作,直到它收集到所有必需的信息,该信息存储在插槽中。一旦所有插槽被填满,机器人就会满足用户的初始请求。

1.1 定义表单

要定义表单,我们需要定义:

  • 插槽映射:所需要收集的信息
  • 响应:机器人应该如何询问每条信息

    1)插槽映射

    对于餐厅搜索的例子,我们想要从用户收集以下信息

  • 食物

  • 人数
  • 是否想坐在外面

你可以在域文件(domain.yml)定义表单,并在表单名称下指定所需插槽的列表:

  1. forms:
  2. restaurant_form:
  3. required_slots:
  4. - cuisine
  5. - num_people
  6. - outdoor_seating

这些插槽需要添加到领域中 slots 部分,以及定义填充插槽时的插槽映射。对于任何 from_entity 填充的插槽,该实体还需要添加到域(domain.yml)中。表单填充的插槽通常不应该影响对话,所以我们需要将 influence_conversation 设置为 false

  1. entities:
  2. - cuisine
  3. - number
  4. slots:
  5. cuisine:
  6. type: text
  7. mappings:
  8. - type: from_entity
  9. entity: cuisine
  10. num_people:
  11. type: float
  12. mappings:
  13. - type: from_entity
  14. entity: number
  15. outdoor_seating:
  16. type: bool
  17. mappings:
  18. - type: from_intent
  19. intent: affirm
  20. value: true
  21. conditions:
  22. - active_loop: restaurant_form
  23. requested_slot: outdoor_seating
  24. - type: from_intent
  25. intent: deny
  26. value: false
  27. conditions:
  28. - active_loop: restaurant_form
  29. requested_slot: outdoor_seating

number 插槽是由实体填充,DucklingEntityExtractor 可以提取数字等实体,要使用 DucklingEntityExtractor 需要在 NLU 管道(config.yml)中添加。

  1. language: en
  2. pipeline:
  3. # other components
  4. - name: DucklingEntityExtractor
  5. dimensions: ["number"]

2)带条件的插槽映射

根据用户的意图来填充 outdoor_seating 插槽,如果是 affirm,则插槽值为 true;如果是 deny,则为 false

但是,如果用户正在回答“你想坐在外面吗?”这个问题,则该插槽只可以设置为 truefalse。为了强制执行此条件,outdoor_seating 插槽条件要求 restaurant_form 处于活跃状态,并且要求插槽是 outdoor_seating。如果没有条件,并且用户在早些时候发送了带有确认或拒绝意图的消息,则在激活表单时就已经填充了 outdoor_seating 插槽。因此,该表格不会提示用户选择户外座位。

3)验证插槽

通常,我们需要在接受用户输入之前对其进行验证,例如通过检查给定的菜系是否在机器人可用的菜系数据库中。

4)请求插槽

要指定机器人应该如何询问所需信息,我们可以在域文件(domain.yml)中定义名为 utter_ask_{slotname} 的响应:

  1. responses:
  2. utter_ask_cuisine:
  3. - text: "What cuisine?"
  4. utter_ask_num_people:
  5. - text: "How many people?"
  6. utter_ask_outdoor_seating:
  7. - text: "Do you want to sit outside?"

1.2 更新配置

表单的常规对话路径应该定义为规则,这意味着你需要将 RulePolicy 添加到域文件中(domain.yml)的策略中:

  1. policies:
  2. - name: RulePolicy

1.3 创建规则

表单负责向用户询问所有必需信息的逻辑,因此我们只需要两个规则来实现表单的常规对话路径:一种是定义何时开始,另一种则是定义会发生什么。对于餐厅搜索示例,在现实生活中,机器人根据用户的喜好查找餐厅。在下面这个规则示例(rules.yml)中,机器人将发出一个包含用于搜索详细信息的响应。

  1. rules:
  2. - rule: activate restaurant form
  3. steps:
  4. - intent: request_restaurant # intent that triggers form activation
  5. - action: restaurant_form # run the form
  6. - active_loop: restaurant_form # this form is active
  7. - rule: submit form
  8. condition:
  9. - active_loop: restaurant_form # this form must be active
  10. steps:
  11. - action: restaurant_form # run the form
  12. - active_loop: null # the form is no longer active because it has been filled
  13. - action: utter_submit # action to take after the form is complete
  14. - action: utter_slots_values # action to take after the form is complete

通过拆分表单的激活和提交,如果用户提供意外输入或者闲聊中断表单,规则仍然适用。

1.4 更新NLU训练数据

我们需要为激活表单的意图添加示例,以及用户将如何提供所需信息的示例。

1)表单激活意图

我们需要为激活表单的意图(nlu.yml)添加训练示例,为意图 request_restaurant 添加示例:

  1. nlu:
  2. - intent: request_restaurant
  3. examples: |
  4. - im looking for a restaurant
  5. - can i get [swedish](cuisine) food in any area
  6. - a restaurant that serves [caribbean](cuisine) food
  7. - id like a restaurant
  8. - im looking for a restaurant that serves [mediterranean](cuisine) food
  9. - can i find a restaurant that serves [chinese](cuisine)

from_entity 填充的插槽可以被任何用户话语填充,无论何种意图,只要提取了正确的实体。这意味着,如果用户在他们的第一条消息中提供了 cuisine 实体,则该位置将在表单的开头填充,并且机器人不会再次向他们询问美食。

2)表单填充意图

当表单填充查插槽时,它不会注意预测的是哪个意图,除非插槽映射明确要求或排除意图。对于餐厅搜索示例,outdoor_seating 插槽被映射到两个意图上,所以你需要为这些意图添加训练数据。

对于 cuisinenumber 插槽,因为未指定意图,因此我们可以向通用 inform 意图添加示例。我们需要来标注 cuisine 实体,以便 DIETClassifier 可以学习提取它。我们不需要标注 number 实体,因为 DucklingEntityExtractor 是一种基于规则的提取器,未针对训练数据进行训练。每个意图仅显示几个示例,为了能让机器人正常工作,我们应该添加此处显示的更多训练数据:

  1. nlu:
  2. - intent: affirm
  3. examples: |
  4. - Yes
  5. - yes, please
  6. - yup
  7. - intent: deny
  8. examples: |
  9. - no don't
  10. - no
  11. - no I don't want that
  12. - intent: inform
  13. examples: |
  14. - [afghan](cuisine) food
  15. - how bout [asian oriental](cuisine)
  16. - what about [indian](cuisine) food
  17. - uh how about [turkish](cuisine) type of food
  18. - um [english](cuisine)
  19. - im looking for [tuscan](cuisine) food
  20. - id like [moroccan](cuisine) food
  21. - for ten people
  22. - 2 people
  23. - for three people
  24. - just one person
  25. - book for seven people
  26. - 2 please
  27. - nine people

更新域文件来包含以下意图:

  1. intents:
  2. - request_restaurant
  3. - affirm
  4. - deny
  5. - inform

1.5 定义响应

在域文件(domain.yml)中添加提交表单后发送的响应:

  1. responses:
  2. utter_submit:
  3. - text: "All done!"
  4. utter_slots_values:
  5. - text: "I am going to run a restaurant search using the following parameters:\n
  6. - cuisine: {cuisine}\n
  7. - num_people: {num_people}\n
  8. - outdoor_seating: {outdoor_seating}"

2. 总结

表单可以简化收集用户消息的逻辑,要定义像上面的餐厅搜索示例这样的最小表单,以下是我们需要执行的操作流程:

  • 在配置文件 config.yml 中添加 RulePolicy 策略
  • 在域中定义所需插槽的表单
  • 在域中给所有必需的插槽添加插槽映射
  • 添加激活和提交表单的规则
  • 添加用于激活表单的意图示例
  • 添加用于填充必要插槽的意图示例
  • 定义表单完成后机器人要采取的操作或响应
  • 使用定义的新意图和动作来更新领域

要尝试新定义的表单,请通过运行 rasa train 来重新训练模型,然后通过 rasa shell 来启动。由于 DucklingEntityExtractor 用于提取实体,因此我们在后台启动 Duckling