🚀 原文地址:

领域定义了机器人操作的宇宙,它指定了机器人应该知晓的意图、实体、插槽、响应、表单和操作。同样,它还定义了会话的配置信息。

以下是完整的域示例:

  1. version: "3.0"
  2. intents:
  3. - affirm
  4. - deny
  5. - greet
  6. - thankyou
  7. - goodbye
  8. - search_concerts
  9. - search_venues
  10. - compare_reviews
  11. - bot_challenge
  12. - nlu_fallback
  13. - how_to_get_started
  14. entities:
  15. - name
  16. slots:
  17. concerts:
  18. type: list
  19. influence_conversation: false
  20. mappings:
  21. - type: custom
  22. venues:
  23. type: list
  24. influence_conversation: false
  25. mappings:
  26. - type: custom
  27. likes_music:
  28. type: bool
  29. influence_conversation: true
  30. mappings:
  31. - type: custom
  32. responses:
  33. utter_greet:
  34. - text: "Hey there!"
  35. utter_goodbye:
  36. - text: "Goodbye :("
  37. utter_default:
  38. - text: "Sorry, I didn't get that, can you rephrase?"
  39. utter_youarewelcome:
  40. - text: "You're very welcome."
  41. utter_iamabot:
  42. - text: "I am a bot, powered by Rasa."
  43. utter_get_started:
  44. - text: "I can help you find concerts and venues. Do you like music?"
  45. utter_awesome:
  46. - text: "Awesome! You can ask me things like \"Find me some concerts\" or \"What's a good venue\""
  47. actions:
  48. - action_search_concerts
  49. - action_search_venues
  50. - action_show_concert_reviews
  51. - action_show_venue_reviews
  52. - action_set_music_preference
  53. session_config:
  54. session_expiration_time: 60 # value in minutes
  55. carry_over_slots_to_new_session: true

1. 多个领域文件

领域可以定义在单个 YAML 文件中,也可以拆分为多个文件。当拆分为多个文件时,领域内容将会被自动读取并整合在一起,你可以通过以下命令行接口,来基于多个领域文件训练一个模型:

  1. $ rasa train --domain path_to_domain_directory

2. 意图

在域文件中,intents 键下应该列出在 NLU 数据和对话训练数据中所有使用到的意图。

2.1 忽略某些意图的实体

如果需要忽略某些意图的所有实体,我们可以在域文件中添加 use_entities: [] 参数:

  1. intents:
  2. - greet:
  3. use_entities: []

如果要忽略某些实体或者明确仅考虑某些实体,我们可以采用如下方式:

  1. intents:
  2. - greet:
  3. use_entities:
  4. - name
  5. - first_name
  6. ignore_entities:
  7. - location
  8. - age

这些意图所排除的实体将不会被特征化,因为它们也不会影响下一个动作的预测。当存在这样一个意图,我们并不关心实体被提取时,使用 ignore_entities 非常有用。

如果我们所列出的意图并没有该参数时,实体将会正常特征化。

:::info 💡 如果不希望实体影响下个动作的预测,请为同名的插槽设置 influence_conversation: false。 :::

3. 实体

通过 NLU 管道中实体提取器所提取的实体,我们将其放置在 entities 部分。

例如:

  1. entities:
  2. - PERSON # entity extracted by SpacyEntityExtractor
  3. - time # entity extracted by DucklingEntityExtractor
  4. - membership_type # custom entity extracted by DIETClassifier
  5. - priority # custom entity extracted by DIETClassifier

如果使用了实体角色和分组的功能,我们还需要列出实体的角色和分组:

  1. entities:
  2. - city: # custom entity extracted by DIETClassifier
  3. roles:
  4. - from
  5. - to
  6. - topping: # custom entity extracted by DIETClassifier
  7. groups:
  8. - 1
  9. - 2
  10. - size: # custom entity extracted by DIETClassifier
  11. groups:
  12. - 1
  13. - 2

4. 插槽

插槽相当于机器人的记忆,将用户提供的信息通过键值对的方式来存储(例如家乡和城市),以及外部世界所收集到的信息(例如从数据中查询的结果)。

插槽是域文件中定义在 slots 部分,包含槽名、类型、是否影响以及如何影响机器人的行为。以下示例中,定义了 slot_name 的插槽,其类型为 text,以及预定义插槽映射 from_entity

  1. slots:
  2. slot_name:
  3. type: text
  4. mappings:
  5. - type: from_entity
  6. entity: entity_name

4.1 插槽和对话行为

可以设定 influence_conversation 属性来指定插槽是否会话产生影响。如果你想将信息存储在插槽内而不影响对话,在定义插槽时通过 influence_conversation: false 来设定。

下面的示例定义了一个用于存储用户年龄的 age 插槽,但是该插槽并不会影响对话的流程。这意味着机器人在预测下一次动作时,都将会忽略 age 槽中的值。

  1. slots:
  2. age:
  3. type: text
  4. # this slot will not influence the predictions
  5. # of the dialogue policies
  6. influence_conversation: false

当定一个插槽时,如果你省略了 influence_conversation 或者将其设置为 true,除非该插槽的类型为 any,否则将会影响下一个动作的预测。由此可知,插槽是否会影响对话将取决于其类型。

下面示例中定义了一个影响会话的插槽 home_city,文本类型的插槽将根据槽值影响机器人的行为。值得注意的是,文本插槽中的值不会有区别,例如 New York or Hong Kong 或者 Bangalore。

  1. slots:
  2. # this slot will influence the conversation depending on
  3. # whether the slot is set or not
  4. home_city:
  5. type: text
  6. influence_conversation: true

例如,考虑这两种输入:“What is the weather like?”和“What is the weather like in Bangalore?”,对话将基于 home_city 插槽是否设置,根据 NLU 自动决定产生分歧。

  • 如果插槽已经设置,机器人将预测 action_forecast 动作。
  • 如果没有设置插槽,则需要在预测天气之前,获取到 home_city 的信息。
  1. slots:
  2. # this slot will influence the conversation depending on
  3. # whether the slot is set or not
  4. home_city:
  5. type: text
  6. influence_conversation: true

4.2 插槽类型

1)文本类型

当插槽的类型为 text 时,它用于存储文本信息。示例如下:

  1. slots:
  2. cuisine:
  3. type: text
  4. mappings:
  5. - type: from_entity
  6. entity: cuisine

如果 influence_conversation 设置为 true,机器人的行为是否会改变取决于插槽是否设置。不同的文本并不会进一步影响会话,这意味着下面示例中的两个故事是一样的:

  1. stories:
  2. - story: French cuisine
  3. steps:
  4. - intent: inform
  5. - slot_was_set:
  6. - cuisine: french
  7. - story: Vietnamese cuisine
  8. steps:
  9. - intent: inform
  10. - slot_was_set:
  11. - cuisine: vietnamese

2)布尔类型

当插槽的类型为 bool 时,它用于存储 true 或者 false 值。示例如下:

  1. slots:
  2. is_authenticated:
  3. type: bool
  4. mappings:
  5. - type: custom

如果 influence_conversation 设置为 true,机器人的行为是否会改变取决于插槽是否为空、true 或者 false。值得注意的是,如果 bool 插槽为空时,与插槽设置为 false 影响会话方式是不同的。

3)类别类型

当插槽的类型为 categorical 时,它用于存储 N 个选项中一个值。示例如下:

  1. slots:
  2. risk_level:
  3. type: categorical
  4. values:
  5. - low
  6. - medium
  7. - high
  8. mappings:
  9. - type: custom

如果 influence_conversation 设置为 true,机器人的行为是否会改变取决于插槽的值。这意味着上述示例中插槽中的值是 lowmediumhigh 哪一个,机器人的行为也会有所不同。

对于没有处在列表中的值,Rasa 会设置一个默认值 __other__ 来进行响应。值得注意的是,__other__ 并不需要我们去定义,如果定义了 __other__ 的话,所有未知的值都将映射到该值上。事实上,不设置也是相同的效果。

4)浮点类型

当插槽的类型为 float 时,它用于存储真实的数字,其中 max_value 默认值为 1.0min_value 默认值为 0.0。示例如下:

  1. slots:
  2. temperature:
  3. type: float
  4. min_value: -100.0
  5. max_value: 100.0
  6. mappings:
  7. - type: custom

如果 influence_conversation 设置为 true,机器人的行为是否会改变取决于插槽的值。如果槽值处于最大最小值中间,那么具体值将会被使用。所有小于最小值的值,将会被当做最小值来处理,所有大于最大值的值,将会被当做最大值来处理。因为,如果将最大值设置为 1,那么对于 2 和 3.5 的槽值将没有区别。

5)列表类型

当插槽的类型为 list 时,它用于存储列表值。示例如下:

  1. slots:
  2. shopping_items:
  3. type: list
  4. mappings:
  5. - type: from_entity
  6. entity: shopping_item

如果 influence_conversation 设置为 true,机器人的行为是否会改变取决于插槽是否为空。槽值中列表的长度并不会影响对话,它仅仅与列表长度为 0 或者非 0 有关。

6)任何类型

当插槽的类型为 any 时,它用于存储任意值,也就是说可以是任意类型,例如字典或者列表。示例如下:

  1. slots:
  2. shopping_items:
  3. type: any
  4. mappings:
  5. - type: custom

如果插槽的类型为 any,那么在会话过程中总是被忽略的,并且此类型的插槽并不能设置 influence_conversationtrue

7)自定义类型

可能你的订餐系统仅能处理最多 6 人的预定,我们通常希望槽值可以影响下一个选中的动作,而不仅仅是指定的操作,
这种情况下我们就可以通过自定义一个插槽类来实现次功能。

下面示例中我们定一个 NumberOfPeopleSlot 的插槽类,它的目的是将槽值转换为一个向量,以便 Rasa 机器学习模型可以对其进行处理。NumerOfPeopleSlot 有 3 种可能的值,均使用长度为 2 的向量来进行标识:

  • (0, 0):还未设置
  • (1, 0):在 1 到 6 之间
  • (0, 1):大于 6 人
  1. from rasa.shared.core.slots import Slot
  2. class NumberOfPeopleSlot(Slot):
  3. def feature_dimensionality(self):
  4. return 2
  5. def as_feature(self):
  6. r = [0.0] * self.feature_dimensionality()
  7. if self.value:
  8. if self.value <= 6:
  9. r[0] = 1.0
  10. else:
  11. r[1] = 1.0
  12. return r

通常我们会将自定义插槽类作为单独一个模块,还不是和自定义动作放在一起。

Rasa 通过 addons.my_custom_slots.NumberOfPeopleSlot 来引用自定义插槽,具体如下:

  1. slots:
  2. people:
  3. type: addons.my_custom_slots.NumberOfPeopleSlot
  4. influence_conversation: true
  5. mappings:
  6. - type: custom

按照上述配置好之后,Rasa 就可以使用自定义插槽类了,接下来根据 people 插槽的值添加不同训练故事。下面示例中,我们添加了 2 个故事,一个是人数在 1-6之间,另一个是大于 6 人。我们可以在这些范围内选择任意值来放置在故事中,因为他们都采用相同的方式来特征化。

  1. stories:
  2. - story: collecting table info
  3. steps:
  4. # ... other story steps
  5. - intent: inform
  6. entities:
  7. - people: 3
  8. - slot_was_set:
  9. - people: 3
  10. - action: action_book_table
  11. - story: too many people at the table
  12. steps:
  13. # ... other story steps
  14. - intent: inform
  15. entities:
  16. - people: 9
  17. - slot_was_set:
  18. - people: 9
  19. - action: action_explain_table_limit

4.3 插槽映射

1)from_entity

2)from_entity的唯一映射匹配

3)from_text

from_text 映射将使用用户最后说的文本内容来填充 slot_name 插槽。如果 intent_nameNone 的话,那么无论意图的名称如何,该插槽都会被填充。否则,只有当意图是 intent_name 时才会填充插槽。

如果消息的意图是 excluded_intent,则插槽映射将不会起作用。

  1. slots:
  2. slot_name:
  3. type: text
  4. mappings:
  5. - type: from_text
  6. intent: intent_name
  7. not_intent: excluded_intent

:::info 💡 如果在使用 from_text 插槽映射时希望保持 Rasa 2.x 表单的功能,我们必须使用定义了 active_looprequested_slot 的映射条件。 :::

4)from_intent

如果用户的意图是 intent_name,那么 from_intent 映射将使用 my_value 来填充 slot_name 插槽。如果我们没有指定 intent 参数,那么如论消息的意图如何,只要意图未在 not_intent 参数下列出,插槽便会对其进行映射。

以为为常用的参数:

  • value:必须提供,用来填充 slot_name 插槽的值
  • intent:可选项,只有在该预测意图时应用插槽映射
  • not_intent:可选项,当在预测该意图时不应用插槽映射
  1. slots:
  2. slot_name:
  3. type: any
  4. mappings:
  5. - type: from_intent
  6. value: my_value
  7. intent: intent_name
  8. not_intent: excluded_intent

5)from_trigger_intent

如果一个表单被带有 intent_name 意图的用户消息所激活,那么 from_trigger_intent 映射将使用 my_value 来填充 slot_name 插槽。如果消息的意图列在 excluded_intent 下,那么插槽映射将不会起作用。

  1. slots:
  2. slot_name:
  3. type: any
  4. mappings:
  5. - type: from_trigger_intent
  6. value: my_value
  7. intent: intent_name
  8. not_intent: excluded_intent

4.4 映射条件

要在表单的上下文中应用插槽映射,请在插槽映射的 conditions 键中指定表单的名称,在 active_loop 键下列出条件映射所适用的表单名称。

条件映射也可以包含 requested_slot 的名称,如果 requesed_slot 并未有提及,无论表单请求的是哪个插槽,当相关信息被提取时插槽就会被设置。

  1. slots:
  2. slot_name:
  3. type: text
  4. mappings:
  5. - type: from_text
  6. intent: intent_name
  7. conditions:
  8. - active_loop: your_form
  9. requested_slot: slot_name
  10. - active_loop: another_form

:::info 💡 如果插槽映射中并未包含 conditions,那么无论表单是否处于活跃状态,插槽映射都将起作用。只要插槽被列在表单的 requested_slot 中,当表单激活时,如果插槽为空的话,那么表单会提示输入该插槽。 :::

4.5 自定义插槽映射

当 Rasa 提供的预插槽映射都不适用于你的场景,我们通过插槽验证动作来自定义插槽映射。值得注意的是,插槽映射的类型必须为 custom,例如

  1. slots:
  2. day_of_week:
  3. type: text
  4. mappings:
  5. - type: custom
  6. action: action_calculate_day_of_week

你还可以通过列出动作的类型而不必要指定具体动作,使用 custom 插槽映射来列出所有插槽,这些插槽将会被任意自定义动作所填充。例如:

  1. slots:
  2. handoff_completed:
  3. type: boolean
  4. mappings:
  5. - type: custom

插槽并不会在每一个用户轮次进行更新,仅在自定义动作预测返回的时 SlotSet 事件时才会更新。

4.6 初始化插槽值

我们可以在域文件中给插槽提供一个初始值:

  1. slots:
  2. num_fallbacks:
  3. type: float
  4. initial_value: 0
  5. mappings:
  6. - type: custom

5. 响应

6. 表单

7. 动作

8. 会话配置

会话表示的是机器人与用户之间的对话,通常它有 3 种开始形式:

  1. 用户开始与机器人进行对话
  2. 在可配置的非活动时间后,用户发送了信息
  3. 使用 /session_start 意图消息来启动一次手动会话

我们可以在域文件中通过添加 session_config 键,来定义出发新会话时的非活动时长。

可配置的参数有:

  • session_expiration_time:定义了新会话开始后的非活动时间(单位:分钟)。
  • carry_over_slots_to_new_session:决定是否将现有设置插槽转移到新会话。

默认 session 配置如下:

9. 配置

在领域文件中的 config 键可配置 store_entities_as_slots 参数,此参数仅在阅读故事时作为上下文使用,同时 Rasa 会将它们传递给跟踪器。如果该参数被设置为 true,且当前故事中存在适用的实体,该参数将从实体中隐式设置插槽。因此,此插槽将会跳过在故事中手动添加显式 slot_was_set 步骤。默认情况下,该特性是打开的。同样地,我们也可以通过将 store_entities_as_slots 参数设置为 false 来关闭此功能。

  1. config:
  2. store_entities_as_slots: false