一、前言
一般来说,机器人可以跟人对话,机器人说什么是最难的,顶多是人工编写几种规则和模版来回复即可。但是要让机器人理解人的意图,确实非常难的事情。因为语言具有多样性,多义词,一语双关,长短句等,尤其是中文的博大精深。因此机器人需要特别多的数据,也就是模拟人的问法,让机器人理解这些意图特征,理解人的问法,以及人是如何回复别人的问题,这部分内容在Rasa里面称为训练数据。
Rasa使用YAML格式作为一种统一和可扩展的方式来管理所有的训练数据,包括NLU数据、stories数据和rules规则。可以将训练数据拆分为任意数量的YAML文件,每个文件可以包含NLU数据、故事和规则的任意组合。训练数据解析器使用最上层的key确定训练数据类型。
开发者还在寻找 Markdown 数据格式?它在 Rasa 3.0 中被删除,但仍然可以找到markdown NLU data和markdown stories的文档。如果您仍然有 Markdown 格式的训练数据,那么推荐的方法是使用 Rasa 2.x 将您的数据从 Markdown 转换为 YAML。迁移指南 解释了如何执行此操作。
1.1 High-Level Structure
每个文件可以包含一个或多个带有key以及对应的训练数据。一个文件可以包含多个key,但每个key在单个文件中只能出现一次。可用的key包括:
-
- version
- nlu
- stories
- rules
开发者应该在所有 YAML 训练数据文件中指定版本key。如果开发者未在训练数据文件中指定版本key,Rasa 将假定开发者使用的是已安装的 Rasa 版本支持的最新训练数据格式。Rasa 版本高于开发者机器上安装的版本的训练数据文件将被跳过。目前,Rasa 3.x 的最新训练数据格式规范是 3.1。
1.2 example
这里拿一个样例来说明,nlu、stroies和rules数据都在一个文件中来展现:
version: "3.1" nlu: - intent: greet examples: | - Hey - Hi - hey there [Sara](name) - intent: faq/language examples: | - What language do you speak? - Do you only handle english? stories: - story: greet and faq steps: - intent: greet - action: utter_greet - intent: faq - action: utter_faq rules: - rule: Greet user steps: - intent: greet - action: utter_greet
要测试指定stories,需要将它们放入一个单独的文件中,并使用前缀test_:
stories: - story: greet and ask language - steps: - user: | hey intent: greet - action: utter_greet - user: | what language do you speak intent: faq/language - action: utter_faq
二、NLU 训练数据
NLU训练数据由按意图分类的示例用户对话组成。NLU训练数据还包括实体,可以从用户消息中提取结构化信息。您还可以向训练数据中添加额外的信息,如正则表达式和查找表,以帮助模型正确识别意图和实体。NLU训练数据在NLU键下定义。可以在此项下添加的内容包括:
- 按用户意图分组的培训示例
例如带上标注的实体,但是标注信息是可选。
nlu: - intent: check_balance examples: | - What's my [credit](account) balance? - What's the balance on my [credit card account]{"entity":"account","value":"credit"}
- 同义词
nlu: - synonym: credit examples: | - credit card account - credit account
- 正则表达式
nlu: - regex: account_number examples: | - \d{10,12}
- 查表
nlu: - lookup: banks examples: | - JPMC - Comerica - Bank of America
2.1 Training Examples(训练数据样例)
train examples按意图分组并列在 examples字段下。通常,开发者会在每一行列出一个示例,如下所示:
nlu: - intent: greet examples: | - hey - hi - whats up
但是,如果开发者有自定义 NLU 组件并且需要示例的元数据,也可以使用扩展格式:
nlu: - intent: greet examples: - text: | hi metadata: sentiment: neutral - text: | hey there!
metadata字段可以包含任意键值数据,这些数据与示例相关联并且可由 NLU 中的组件访问。在上面的示例中,情感元数据可以被管道中的自定义组件用于情感分析。
开发者还可以在意图级别指定此元数据:
nlu: - intent: greet metadata: sentiment: neutral examples: - text: | hi - text: | hey there!
在这案例里,metadata 字段所包含的内容会应用到每一个intent样例中。
如果开发者需要明确检索意图,你的NLU样例可能会跟下面一样:
nlu: - intent: chitchat/ask_name examples: | - What is your name? - May I know your name? - What do people call you? - Do you have a name for yourself? - intent: chitchat/ask_weather examples: | - What's the weather like today? - Does it look sunny outside today? - Oh, do you mind checking the weather for me please? - I like sunny days in Berlin.
所有检索意图都添加了一个后缀,用于标识Bot的特定响应字段。 在上面的例子中, ask_name 和 ask_weather 是后缀。 后缀与检索意图名称由 / 分隔符分隔。
2.2 Entities(实体)
Entities是可以从用户消息中提取到结构化的信息,在训练数据中使用实体名称进行标注。 除了实体名称之外,开发者还可以使用同义词、角色或组来标注实体。
在训练数据中,标注的实体样例如下所示:
nlu: - intent: check_balance examples: | - how much do I have on my [savings](account) account - how much money is in my [checking]{"entity": "account"} account - What's the balance on my [credit card account]{"entity":"account","value":"credit"}
标注实体的完整语法如下:
[<entity-text>]{"entity": "<entity name>", "role": "<role name>", "group": "<group name>", "value": "<entity synonym>"}
role, group, and value关键词是在标注时是可选的。value 字段的内容可以参考 synonyms。如果你希望理解role 和 group 字段的内容,可以参考entity roles and groups.
2.3 Synonyms(同义词)
同义词将提取的实体映射到提取的文本之外的值。开发者可以使用以下格式定义同义词:
nlu: - synonym: credit examples: | - credit card account - credit account
开发者还可以直接在训练数据中定义同义词,通过指定value字段来设置同义词:
nlu: - intent: check_balance examples: | - how much do I have on my [credit card account]{"entity": "account", "value": "credit"} - how much do I owe on my [credit account]{"entity": "account", "value": "credit"}
如果需要了解更多关于同义词的信息,可以去这里 NLU Training Data page.
2.4 Regular Expressions(正则表达式)
开发者可以用正则表达式来提高意图分类和实体抽取的效果,正则表达式主要是用 RegexFeaturizer 和 RegexEntityExtractor 模块。
定义正则表达式的格式如下:
nlu: - regex: account_number examples: | - \d{10,12} - intent: inform examples: | - my account number is [1234567891](account_number) - This is my account number [1234567891](account_number)
account_number是正则表达式的名称。当用作特征RegexFeaturizer时,正则表达式的名称无关紧要。使用RegexEntityExtractor时,正则表达式的名称应与Bot要提取的实体名称对应上。
如果需要了解更多关于正则表达式的信息,可以去这里 NLU Training Data page.
2.5 Lookup Tables(查找表)
查找表用于生成不区分大小写的正则表达式列表。它们可以与使用正则表达式的方式相同,与pipeline中的regexfeatureizer和RegexEntityExtractor组件结合使用。可以使用查找表来帮助提取具有已知可能值集的实体。保持开发者的查找表尽可能具体。例如,要提取国家名称,可以添加世界上所有国家的查找表。其实这个地方就是添加词库的功能。
nlu: - lookup: banks examples: | - JPMC - Comerica - Bank of America
三、Conversation Training Data(对话数据)
stories和 rules都是用户和对话助手之间的对话流程表示,主要是用于训练对话管理模型。stories用于训练机器学习模型来识别对话中的模式并推广到看不见的对话路径。 rules描述了bot需要始终遵循相同路径的原则以及训练 RulePolicy规则策略。
3.1 Stories(故事)
stories通常由以下几个部分组成:
- story: 故事的名称。该名称是任意的,不用于训练;开发者可以将其用作故事的可读参考,方便统计和说明。
- metadata: 任意且可选,不用于训练,您可以使用它来存储有关故事的相关信息,例如作者。
- steps列表: 组成故事的用户消息和操作。
样例如下:
stories: - story: Greet the user metadata: author: Somebody key: value steps: # list of steps - intent: greet - action: utter_greet
每一个step可以是以下之一构成:
- 用户消息,主要是由意图和实体组成。
- 语句,在其下包含两个或多个用户消息。
- 机器人动作。
- 表单。
- 槽位事件。
- checkpoint(检查点),它将故事与另一个故事联系起来。
User Messages
所有用户消息都可以用 intent 字段和 entities 字段来指定,这个字段是可选的。
在编写故事时,开发者不必处理用户发送的消息的具体内容。相反,开发者可以利用 NLU pipline的输出,它使用意图和实体的组合来引用用户可以发送的具有相同含义的所有可能消息。
用户消息遵循的格式如下:
stories: - story: user message structure steps: - intent: intent_name # Required entities: # Optional - entity_name: entity_value - action: action_name
在样例“I want to check my credit balance”中,“credit”就是一个entities。训练数据中包含的实体也很重要,因为policy会根据意图和实体的组合来学习预测下一个动作(但是,开发者也可以使用use_entities属性更改此行为)。
Actions
Bot执行的所有动作都使用action字段来指定,后面跟动作名称。在编写故事时,一般会有两种类型的操作:
1.响应。由"utter_"开始,并且返回的是具体的消息。例如:
stories: - story: story with a response steps: - intent: greet - action: utter_greet
2.自定义动作。由“action_”开头,运行任意代码并发送任意数量的消息(或不发送)。例如:
stories: - story: story with a custom action steps: - intent: feedback - action: action_store_feedback
Forms
Forms是一种特定类型的自定义动作,它包含循环遍历一组必需的槽位以及向用户询问此信息的逻辑。开发者在Domain中来定义一个表单。Forms一旦定义,开发者应该作为规则指定表单的路径。开发者应该在故事中包括形式中断或其他“不确定的路径”,以便模型可以预测看不见的对话序列。表单作为动作中的一个步骤,通常采用以下格式:
stories: - story: story with a form steps: - intent: find_restaurant - action: restaurant_form # Activate the form - active_loop: restaurant_form # This form is currently active - active_loop: null # Form complete, no form is active - action: utter_restaurant_found
action步骤激活表单并开始遍历所需的槽位。 active_loop: restaurant_form 步骤表示当前有一个action表单。 与 slot_was_set 步骤非常相似,表单步骤不会将表单设置为活动状态,而是指示它应该已经被激活。 同样,active_loop: null 步骤表示在执行后续步骤之前不应激活任何表单。
表单可以被中断并保持活动状态; 在这种情况下,中断应该发生在 action: <form to activate> 步骤之后,然后是 active_loop: <active form> 步骤。 表格的中断可能如下所示:
stories: - story: interrupted food steps: - intent: request_restaurant - action: restaurant_form - intent: chitchat - action: utter_chitchat - active_loop: restaurant_form - active_loop: null - action: utter_slots_values
Slots
槽位事件在 slot_was_set 字段下指定:带有槽位名称和可选的槽位值。槽位充当机器人的内存,根据domain中指定的槽位映射,由默认 action_extract_slots 字段设置,或由自定义action设置。 它们在 slot_was_set 步骤中被故事引用。 例如:
stories: - story: story with a slot steps: - intent: celebrate_bot - slot_was_set: - feedback_value: positive - action: utter_yay
这意味着stories要求 feedback_value 的当前值为positive,以便对话按指定继续进行。
是否需要包含槽位的值取决于插槽类型以及该值是否可以或应该影响对话。 如果该值无关紧要,例如 文本插槽,您可以仅列出插槽的名称:
stories: - story: story with a slot steps: - intent: greet - slot_was_set: - name - action: utter_greet_user_by_name
Checkpoints
检查点由 checkpoint 字段指定,在故事的开头或结尾。
检查点是将故事连接在一起的方法。 它们可以是故事的第一步或最后一步。 如果它们是故事中的最后一步,那么在训练模型时,该故事将与以同名检查点开始的其他故事相关联。 这是一个以检查点结尾的故事示例,以及以相同检查点开始的故事示例:
stories: - story: story_with_a_checkpoint_1 steps: - intent: greet - action: utter_greet - checkpoint: greet_checkpoint - story: story_with_a_checkpoint_2 steps: - checkpoint: greet_checkpoint - intent: book_flight - action: action_book_flight
如果检查点设置在故事开头,也可以为插槽设置条件,例如:
stories: - story: story_with_a_conditional_checkpoint steps: - checkpoint: greet_checkpoint # This checkpoint should only apply if slots are set to the specified value slot_was_set: - context_scenario: holiday - holiday_name: thanksgiving - intent: greet - action: utter_greet_thanksgiving
检查点可以帮助简化开发中的训练数据并减少其中的冗余,但不要过度使用它们。 使用大量检查点会导致故事难以理解。 如果在不同的故事中经常重复一系列步骤,那么使用它们是有意义的,但是没有检查点的故事更容易阅读和编写。
3.2 Rules(规则)
规则一般在rules字段下定义,看起来类似于故事。 规则还有一个steps字段,其中包含与故事相同的步骤列表。 规则还可以包含 conversation_started 和 conditions 字段。 这些用于指定应用规则的条件。
带有条件的规则如下所示:
rules: - rule: Only say `hey` when the user provided a name condition: - slot_was_set: - user_provided_name: true steps: - intent: greet - action: utter_greet
如果需要了解更多关于rules的信息,可以到这里Rules.
四、Test Stories(测试stories)
test stories检查用户消息是否被正确分类以及动作预测。test stories使用与故事相同的格式,除了用户消息步骤可以包括user指定用户消息的实际文本和标注实体。 这是一个测试故事的例子
stories: - story: A basic end-to-end test steps: - user: | hey intent: greet - action: utter_ask_howcanhelp - user: | show me [chinese]{"entity": "cuisine"} restaurants intent: inform - action: utter_ask_location - user: | in [Paris]{"entity": "location"} intent: inform - action: utter_ask_price
开发者可以通过执行以下命令来进行测试:
rasa test
如果还需了解更多关于测试的信息,可以到这里Testing Your Assistant.
五、End-to-end Training(端到端训练)
通过端到端训练,开发者必处理 NLU pipline提取的特定意图。 相反,开发者可以使用user字段将用户消息的文本直接放在故事中。
这些端到端的用户消息遵循以下格式:
stories: - story: user message structure steps: - user: the actual text of the user message - action: action_name
此外,开发者可以添加可被TED Policy 提取的实体标签。 实体标签的语法与 NLU 训练数据中的相同。 例如,以下故事包含用户话语 I can always go for sushi。 通过使用 NLU 训练数据 [sushi](cuisine) 中的语法,开发者可以将寿司标记为 cuisine 类型的实体。
stories: - story: story with entities steps: - user: I can always go for [sushi](cuisine) - action: utter_suggest_cuisine
同样,开发者可以将机器人话语直接放在stories中,方法是使用bot字段,然后使用开发者希望机器人说出的文本。
只有bot字段的故事可能如下所示:
stories: - story: story with an end-to-end response steps: - intent: greet entities: - name: Ivan - bot: Hello, a person with a name!
开发者也可以有一个混合的端到端的story:
stories: - story: full end-to-end story steps: - intent: greet entities: - name: Ivan - bot: Hello, a person with a name! - intent: search_restaurant - action: utter_suggest_cuisine - user: I can always go for [sushi](cuisine) - bot: Personally, I prefer pizza, but sure let's search sushi restaurants - action: utter_suggest_cuisine - user: Have a beautiful day! - action: utter_goodbye
Rasa 端到端训练与标准 Rasa 方法完全集成。这意味着开发者可以混合stories,其中一些步骤由操作或意图定义,而其他步骤由用户消息或机器人响应直接定义。
六、参考文献
Introduction to Rasa Open Source & Rasa Pro