当前位置: 首页 > news >正文

【Rasa】入门案例学习

Rasa初体验--构建对话机器人

NLU数据

version: "3.1"nlu:- intent: greetexamples: |- Hi- Hey!- Hello- Good day- Good morning- intent: subscribeexamples: |- I want to get the newsletter- Can you send me the newsletter?- Can you sign me up for the newsletter?- intent: informexamples: |- My email is example@example.com- random@example.com- Please send it to anything@example.com- Email is something@example.com

格式概述

开源Rasa使用YAML作为一种统一且可扩展的方式来管理所有训练数据,包括NLU数据、故事和规则。

你可以将训练数据拆分为任意数量的YAML文件,每个文件可以包含NLU数据、故事和规则的任意组合。训练数据解析器使用顶级键来确定训练数据类型。

领域使用与训练数据相同的YAML格式,也可以扩多个文件拆分或合并到一个文件中。领域包括响应和表单的定义。

领域

领域定义了对话机器人的全部操作。它指定对话机器人的意图、实体、槽、响应、表单和动作。它还定义了对话会话的配置。

多个领域文件

领域可以定义为单个YAML文件,也可以拆分为目录中的多个文件。

当拆分为多个文件的时候,领域内容可被直接读取并自动合并在一起。

你可以通过运行如下命令在命令行界面中训练具有拆分领域文件的模型:

rasa train --domain path_to_domain_directory

意图

领域文件中的intents键列出了NLU数据和对话训练数据中使用的所有意图。

忽略某些意图的实体

要忽略某些实体或者显示地仅考虑某些实体,你可以使用如下语法:

intents:
- greet:use_entities:- name- first_name
- farewall:ignore_entities:- location- age- last_name

对于任何单一意图,只能是use_entities或ignore_entities

这些意图的排除实体将不被特征化,因此不会影响下一个动作的预测,当你有一个不关心被提取的实体的意图时,这很有用。

实体

实体部分列出了可以由NLU管道中的任何实体提取器提取的所有实体。

entities:- PERSON- time- membership_type- priority

当使用多个领域文件时,可以在任何领域文件中指定实体,并可以在任何领域文件中被任何意图使用或忽略。

如果使用实体角色和分组功能,你还需要在本节中列出实体的角色和组。

例如:

entities:- city:roles:- from- to- topping:groups:- 1- 2- size:groups:- 1- 2

默认情况下,实体会影响动作预测。为了防止提取到的实体影响特定意图的对话,你可以忽略某些意图的实体。

要忽略所有意图的实体,不必在每个意图的ignore_entities标志下列出,可以在实体下将influence_conversation设置为false

entities:
- location:influence_conversation: false

此语法与将实体添加到领域中每个意图的ignore_entities列表具有相同的效果

显式设置influence_conversation: true 不会改变任何行为,因为这是默认设置

槽式对话机器人的记忆。它作为键值存储用于存储用户提供的信息(例如:家乡)以及收集的有关外部的信息(例如:数据库查询结果)

槽在领域的slots部分中定义,包括它们的名称、类型和他们是否以及如何影响对话机器人的行为。

以下示例定义了一个名为“slot_name”的槽,类型为text,预定义槽映射from_entity

slots:slot_name:type: textmappings:- type: from_entityentity: entity_name

槽和对话行为

你可以使用influence_conversation属性来指定槽是否影响对话

如果你想在槽中存储信息而不影响对话,请在定义槽时设置influence_conversation:false

以下示例定义了一个age槽,它将存储有关用户年龄的信息,但不会影响对话的流程。这意味着对话机器人每次预测下一个动作的时候都会忽略槽的值。

slots:age:type: textinfluence_conversation: false

槽类型

①文本类型槽

        类型:text

        用途:存储文本值

        示例:

slots:cuisine:type: textmappings:- type: from_entityentity: cuisine

        描述:如果influence_conversation设置为true,对话机器人的行为将根据slot是否设置而改变。但是不同的文本不会进一步影响对话,这意味着如下两个故事是相等的:

stories:
- story: French cuisinesteps:- intent: inform- slot_was_set:- cuisine: frech- story: Vietnamese cuisinesteps:- intent: inform- slot_was_set:- cuisine: vietnamese

②布尔类型槽

        类型:bool

        用途:存储true或false值

        示例:

slots:is_authenticated:type: boolmappings:- type: custom

③分类型槽

        类型:categorical

        用途:存储N个可选值之一的槽

        示例:

slots:risk_level:type: categoricalvalues:- low- medium- highmappings:- type: custom

        描述:__other__会自动添加到用户定义的值中。所有遇到的未在槽值中明确定义的值都映射到__other__。__other__不应用作用户定义的值,负责它将作为所有未见过值映射到的默认值。

④浮点类型槽

        类型:float

        用途:存储实数

        示例:

slots:temperature:type: floatmin_value: -100.0max_value: 100.0mappings:- type: custom

        描述:如果该值介于min_value和max_value之间,则使用数字指定的值。所有低于min_value的值将被视为min_value,所有高于max_value的值将被视为max_value。

⑤列表类型槽

        类型:list

        用途:存储列表值

        示例:

slots:shopping_items:type: listmappings:- type: from_entityentity: shopping_item

        描述:如果influence_conversation设置为true,对话机器人的行为将根据列表是否为空而改变。存储在槽中的列表长度不会影响对话。只有列表长度是零还是非零才重要。

⑥任意类型槽

        类型:any

        用途:存储任意数据(可以为任意类型,例如:词典或列表)

        示例:

slots:shopping_items:type: anymappings:- type: custom

        描述:any类型槽在对话期间总是被忽略。对于any类型槽,influence_conversation属性不能设置为true。如果要存储影响对话的自定义数据结构,请使用自定义槽类型。

⑦自定义槽

也许你的餐厅预订系统最多只能处理6个人的预订。在这种情况下,你希望槽的值影响下一个选定的动作。你可以通过自定义槽类型来做到这一点。

下面代码定义了一个名为NumberOfPeopleSlot的自定义槽类型。特征化定义了如何将槽的值转换为向量,以便开源Rasa机器学习模型可以处理它。NumberOfPeopleSlot有三个可能的值,可以用长度为2的向量表示。

(0,0):未设置

(1,0):介于1和6之间

(0,1):多于6

定义my_custom_slots.py如下:

from rasa.shared.core.slots import Slotclass NumberOfPeopleSlot(Slot):def feature_dimensionality(self):return 2def as_feature(self):r = [0.0] * self.feature_dimensionality()if self.value:if self.value <= 6:r[0] = 1.0else:r[1] = 1.0return r

你可以将自定义槽类型作为独立的Python模块实现,与自定义动作代码分开。将自定义槽的代码保存在名为__init__.py的空文件同级目录中,以便将其识别为Python模块。然后,你可以通过其他模块引用自定义槽类型。

例如,假设你已将上面的代码保存在addons/my_custom_slots.py中,这是一个与你的对话机器人相关的目录:

则你的自定义槽类型的模块路径为addons.my_custom_slots.NumberOfPeopleSlot:

slots:people:type: addons.my_custom_slots.NumberOfPeopleSlotinfluence_conversation: truemappings:- type: custom

槽映射

开源Rasa带有4个预定义的映射,用于根据最新的用户消息填充槽。

除了预定义的映射,你还可以定义自定义槽映射。所有自定义槽映射都应该包含custom类型的映射。

槽映射被指定为领域文件中mappings键下的YAML字典列表。槽映射按照他们在领域中列出的书序排列优先级,第一个找到的槽映射将用于填充槽。

默认行为是在每个用户消息之后应用槽映射,而不考虑对话上下文。

请注意,你还可以为可选参数intent和not_intent定义意图列表。

①from_entity

from_entity槽映射根据提取的实体填充槽。需要如下参数:

        entity:用于填充槽的实体

如下参数是可选的,可用于进一步指定映射何时应用:

        intent:仅在预测此意图时应用映射

        not_intent:预测此意图时不应用映射

        role:仅当提前的实体具有此角色时才应用映射

        group:仅当提取的实体数据有该组时才应用映射

entities:
- entity_name
slots:slot_name:type: anymappings:- type: from_entityentity: entity_namerole: role_namegroup: group_nameintent: intent_namenot_intent: excluded_intent

②from_text

from_text映射将使用最后一个用户消息的文本来填充slot_name槽。如果intent_name为None,则无论意图名称如何,都会填充槽。否则,只有当用户的意图时intent_name是才会填充槽。

如果消息的意图时excluded_intent,则槽映射将不适用。

slots:slot_name:type: textmappings:- type: from_textintent: intent_namenot_intent: excluded_intent

③from_intent

如果用户意图是intent_name,则from_intent映射将使用my_value值填充slot_name槽。如果你选择不指定参数意图,则只要未在not_intent参数下列出该意图,则无论消息的意图如何,都将应用槽映射。

如下参数是必须的:

        value:填充slot_name槽的值

如下参数是可选的,可用于进一步指定槽映射将何时应用:

        intent

        not_intent

slots:slot_name:type: anymappings:- type: from_intentvalue: my_valueintent: intent_namenot_intent: excluded_intent

④from_trigger_intent

如果表单具有intent_name意图的用户消息激活,则from_trigger_intent映射将使用my_value值填充slot_name槽。如果消息的意图是excluded_intent,则槽映射将不适用。

slots:slot_name:type: anymappings:- type: from_trigger_intentvalue: my_valueintent: intent_namenot_intent: excluded_intent

映射条件

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

条件还可以包括请求槽的名称。如果requested_slot未提及,如果提取了相关信息,则将设置该槽,而不管表单正在请求哪个槽。

slots:slot_name:type: textmappings:- type: from_textintent: intent_nameconditions:- active_loop: your_formrequested_slot: slot_name- active_loop: another_form

①自定义槽映射

当预定义映射不适合你的用例时,可以使用到槽验证动作来定义自定义槽映射。你必须将此槽映射定义为custom类型,例如:

slots:day_of_week:type: textmappings:- type: customaction: action_calculate_day_of_week

你还可以使用custom槽映射来列出会话过程中将由任意自定义动作填充的槽,方法是列出类型而不列出特定动作。例如:

slots:handoff_completed:type: booleanmappings:- type: custom

此槽不会在每个用户轮次时更新,但只会在预测为其返回SlotSet事件的自定义动作时更新。

②初始槽值

你可以为领域文件中的槽提供初始值:

slots:num_fallbacks:type: floatinitial_value: 0mappings:- type: custom

高层级结构

每个文件可以包含一个或多个带有训练数据的键,一个文件可以包含多个键,但每个键在单个文件中只能出现一次。可用的键有:

version

nlu

stories

rules

你应该在所有YAML训练数据文件中指定version键。

示例:

version: "3.1"nlu:
- intent: greetexamples: |- Hey- Hi- hey there [Sara](name)- intent: faq/languageexamples: |- What language do you speak?- Do you only handle english?stories:
- story: greet and faqsteps:- intent: greet- action: utter_greet- intent: faq- action: utter_faqrules:
- rule: Greet usersteps:- intent: greet- action: utter_greet

要指定测试故事,你需要将其放在一个单独的文件中:(tests/test_stories.yml)

stories:
- story: greet and ask languagesteps:- user: |heyintent: greet- action: utter_greet- user: |what language do you speakintent: faq/language- action: utter_faq

测试故事使用与故事相同的格式,除了用户消息步骤可以包含一个user用来指定用户消息的实际文本标注实体。

NLU训练数据

NLU训练数据由按意图分类的用户话语样本组成。训练样本还可以包括实体。实体是从用户信息中提取的结构化信息。你还可以在训练数据中添加额外的信息,例如正则表达式和查找表,来帮助模型正确的识别意图和实体。

NLU训练数据在nlu键下定义。可以在此键下添加的项目有:

①按用户意图分组的训练样本,例如可选带标注的实体

nlu:
- intent: check_balanceexamples: |- What's my [credit](account) balance?- What's the balance on my [credit card account]{"entity":"account","value":"credit"}

②同义词

nlu:
- synonym: creditexamples: |- credit card account- credit account

③正则表达式

nlu:
- regex: account_numberexamples: |- \d{10,12}

④查找表

nlu:
- lookup: banksexamples: |- JPMC- Comerica- Bank of America

训练样本

训练样本按照意图分组并列在examples键下。通常会在每一行列出一个样本,如下所示:

nlu:
- intent: greetexamples: |- hey- hi- what's up

但是,如果有自定的NLU组件并且需要样本元数据,也可以使用扩展格式:

nlu:
- intent: greetexamples: - text: |himetadata:sentiment: neutral- text: |hey there!

metadata键可以包含任意键值数据,这些数据与样本相关联并可被NLU管道中的组件访问。

在上面的示例中,情感元数据可以被管道中的自定义组件用于情感分析。

你还可以再意图级别指定此元数据。在这种情况下,metadata键的内容将传递给每个意图样本。

nlu:
- intent: greetmetadata:sentiment: neutralexamples:- text: |hi- text: |hey there!

如果你想制定检索意图,则NLU样本如下:

nlu:
- intent: chitchat/ask_nameexamples: |- What is your name?- May I know your name?- What do people call you?- Do you have a name for yourself?- intent: chitchat/ask_weatherexamples: |- What's the weather like today?- Does it look sunny outside today?- Oh, do you mind checking the weather for me please?- I like sunniy days in Berlin.

所有检索意图都添加了一个后缀用于标识对话机器人的特定响应键。在上面的例子中,ask_nameask_weather 是后缀。后缀与检索意图名称由 / 分隔。

实体

实体是从用户消息中提取的结构化信息。

在训练样本中实体采用实体名称进行标注。除了实体名称之外,你还可以使用同义词,角色和分组来标注实体。

在训练样本中,实体标注如下所示:


- intent: check_balanceexamples: |- 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、value可选,value字段表示同义实体。

同义词

同义词通过将提取的实体映射到一个值而非提取的文字来规范化训练数据。

nlu:
- synonym: creditexamples: |- credit card account- credit account

你还可以通过指定实体的值在训练样本中定义同义词:

nlu:
- intent: check_balanceexamples: |- 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"}

正则表达式

你可以使用RegexFeaturizer和RegexEntityExtractor组件用正则表达式来改进意图分类和实体提取

定义正则表达式的格式如下:

nlu:
- regex: account_numberexamples: |- \d{10,12}

这里account_number是正则表达式的名称。

当用作RegexFeaturizer的特征时,正则表达式的名称无关紧要。

使用RegexEntityExtractor时,正则表达式的名称应与你要提取的实体名称匹配。

查找表

查找表适用于生成不区分大小写的正则表达式模式的单词列表。格式如下:

nlu:
- lookup: banksexamples: |- JPMC- Bank of America

当你在训练数据中提供查找表时,该表的内容将组合成一个大的正则表达式。此正则表达式用于检查每个训练样本以查看它是否包含查找表中词条的匹配项。

查找表正则表达式的处理方式与直接在训练数据中指定正则表达式相同,可以与RegexFeaturizer和RegexEntityExtractor一起使用。查找表的名称受制于正则表达式功能名称相同的约束。

对话训练数据

故事和规则都是用户和机器人之间对话的表示。它们用于训练对话管理模型。故事用于训练机器学习模型,来识别对话中的模式并泛化至未见过的对话路径。规则描述了应该始终遵循相同路径并用于训练RulePolicy的小段对话。

故事

故事由以下部分组成:

story:故事的名称。名称可以为任意值,不用做训练。

metadata:任意且可选,不用于训练。你可以使用它来存储有关数据的相关信息,例如:作者。

steps列表:构成故事的用户消息和动作。

stories:
- story: Greet the usermetadata: author: Somebodykey: valuesteps:- intent: greet- action: utter_greet

每个步骤可为如下之一:

1.一个用户消息,由意图和实体表示

2.一个or语句,包含两个或多个用户消息

3.一个动作

4.一个表单

5.一个设置事件的槽

6.一个检查点,其将故事与另一个故事相连

用户消息

所有用户消息都会指定intent键和一个可选的entities键

在编写故事时,你不必处理用户发送的消息的具体内容。相反,你可以利用NLU管道的输出,其使用意图和实体的组合来表示与用户发送的具有相同含义的所有可能消息

用户消息遵循如下格式:

stories:
- story: user message structuresteps:- intent: intent_nameentities:- entity_name: entity_value- action: action_name

例如,要表达 I want to check my credit balance这句话,且其中credit为一个实体:

stories:
- story: story with entitiessteps: - intent: account_balanceentities:- account_type: credit- action: action_credit_account_balance

此处包含实体很重要,因为策略会根据意图和实体的组合来学习预测下一个动作(但是你可以使用use_entities属性来改变此行为)

动作

对话机器人执行的所有动作都使用action键指定,后跟动作的名称。在编写故事时,你会遇到两种类型的动作:

响应:以utter_开头并向用户发送特定消息。例如:

stories:
- story: story with a responsesteps:- intent: greet- action: utter_greet

自定义动作:以action_开头,运行任意代码并发送任意数量的消息(或不发送)

stories:
- story: story with a custom actionsteps:- intent: feedback- action: action_store_feedback

表单

表单是一种特定类型的自定义动作,其中包含在一组所需槽并要求用户提供此信息上的循环逻辑。你可以在领域的forms部分定义一个表单。一旦定义,你应该指定表单的预期路径作为规则。

你应该在故事中包含表单的中断或其他非预期路径,以便模型可以泛化至未见过的对话序列。作为故事的一个步骤,表单采用以下格式:

stories:
- story: story with a formsteps:- intent: find_restaurant- action: restaurant_form- active_loop: restaurant_form- active_loop: null- action: utter_restaurant_found

action步骤激活表单后开始在所需的槽上执行循环。active_loop:restaurant_form步骤表示当前有一个活动表单。与slot_was_set步骤相似,form步骤不会将表单设置为活动状态,而是指示它应该已经被激活。同样,active_loop:null步骤表示在采取后续步骤之前不应该激活任何表单。

表单可以被中断并保持活动状态。在这种情况下,中断应该出现在action: <form_to_activate>步骤之后,然后是active_loop: <active form>步骤。

表单的中断如下所示:

stories:
- story: interrupted foodsteps: - intent: request_restaurant- action: restaurant_form- intent: chitchat- action: utter_chitchat- active_loop: restaurant_form- active_loop: null- action: utter_slots_values

槽事件通过slot_was_set键进行指定,同时带有槽的名称和可选的槽值

槽充当机器人的记忆。槽由默认动作action_extract_slots根据领域中指定的槽映射设置,或由自定义动作设置。它们在slot_was_set步骤中被故事引用。例如:

stories:
- story: story with a slotsteps:- intent: celebrate_bot- slot_was_set:- feedback_value: positive- action: utter_yay

这意味着故事要求feedback_value槽的值为positive,对话才能够继续

是否需要包含槽的值取决于槽类型以及该值是否可以或应该影响对话。如果值无关紧要,例如:text槽,你可以只列出槽的名称:

stories:
- story: story with a slotsteps:- intent: greet- slot_was_set:- name- action: utter_greet_user_by_name

默认情况下,任何槽的初始值为null,你可以使用它来检查槽是否未设置:

stories:
- story: Frech cuisinesteps:- intent: inform- slot_was_set:- cuisine: null

槽如何工作:

        故事并不设置槽。如果槽映射适用,则槽必须由默认动作action_extract_slots设置,或者在slot_was_set步骤之前由自定义动作设置。

检查点

检查点使用checkpoint键指定,可以在故事的开头或结尾。

检查点是将故事连接在一起的方式。它们可以是故事的第一步,也可以是最后一步。如果是故事的最后一步,则将该故事与其他故事相连,该故事以训练模型时的同名检查点开始。

如下是一个检查点结尾,以及以相同检查点开始的故事示例:

stories:
- story: story_with_a_checkpoint_1steps:- intent: greet- action: utter_greet- checkpoint: greet_checkpoint- story: story_with_a_checkpoint_2steps:- checkpoint: greet_checkpoint- intent: book_flight- action: action_book_flight

故事开头的检查点可以以设置的槽为条件,例如:

stories:
- story: story_with_a_conditional_checkpointsteps:- checkpoint: greet_checkpoint#This checkpoint should only apply if slots are set to the specified valueslot_was_set:- context_scenario: holiday- holiday_name: thanksgiving- intent:greet- action: utter_greet_thanksgiving

检查点可以帮助简化训练数据并减少其中的冗余,但不要过度使用它们。

使用大量的检查点会让故事难以理解。

如果在不同的故事中经常重复一系列步骤,则使用检查点是有意义的。但是没有检查点的故事更容易阅读和编写。

或语句

or步骤是以相同的方式处理多个意图或槽事件的方法,同时无需为每个意图编写单独的故事。

例如,如果你要求用户确认某事,你可能希望以相同的方式处理affirm和thankyou意图。带有or步骤的故事在训练时转换为多个单独的故事。

例如,以下故事将在训练时转换为两个故事:

stories:
- story: story with ORsteps:- intent: signup_newsletter- action: utter_ask_confirm- or:- intent: affirm- intent: thankyou- action: action_signup_newsletter

你还可以将or语句与槽事件一起使用。如下意味着故事需要name槽被设置的值为joe或bob。这个故事将在训练时被转换为两个故事:

stories:
- story: story with orsteps:- intent: greet- action: utter_greet- intent: tell_name- or:- slot_was_set:- name: joe- slot_was_set:- name: bob# ...next actions

注意:过度使用检查点和或语句会减慢训练速度。

规则

规则列在rules键下,看起来同故事类似。规则也有一个steps键,其中包含与故事相同的步骤列表。

规则还可以包含conversation_started和condition键。这些用于指定规则适用的条件。

一个带有条件的规则如下所示:

rules:
- rule: only say "hey" when the user provided a namecondition:- slot_was_set:- user_provided_name: truesteps:- intent: greet- action: utter_greet

测试故事

测试故事用于检查一个消息是否被正确的进行分类和动作预测。

测试故事使用与故事相同的格式,除了用户消息步骤可以包含一个user用来指定用户消息的实际文本和标注实体。

如下是一个测试故事的例子:

stories:
- story: A basic end-to-end teststeps:- user: |heyintent: greet- action: utter_ask_howcanhelp- user: |show me [chinese]{"entity":"cuisine"} restaurantintent: inform- action: utter_ask_location- user: |in [Paris]{"entity":"location"}intent: inform- action: utter_ask_price

端到端训练

通过端到端训练,你不必处理NLU管道提取的消息的特定意图。相反,你可以使用user键将用户消息的文本直接放在故事中。

这些端到端的用户消息遵循如下格式:

stories:
- story: user message structuresteps:- user: the actual text of the user message- action: action_name

此外,你可以添加可由TED策略提取的实体标签。实体标签的语法与NLU训练数据中的语法相同。

例如,一下故事包含用户消息I can always go for sushi。通过使用NLU训练数据中的语法[sushi](cuisine),你可以将sushi标记为cuisine类型的一个实体。

stories:
- story: story with entitiessteps:- user: I can always go for [sushi](cuisine)- action: utter_suggest_cuisine

同样,你可以将对话机器人消息直接放在故事中,方法是使用bot键,后面为机器人的消息文本。

包含机器人消息的故事示例如下:

stories:
- story: story with an end-to-end responsesteps:- intent: greetentities: - name: Ivan- bot: Hello,a person with a name!

你还可以设置一个混合的端到端的故事:

stories:
- story: full end-to-end storysteps:- intent: greetentities:- 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完全集成。这意味着你可以混合故事,其中一些步骤由动作或意图定义,其他步骤由用户消息或对话机器人响应直接定义。

响应

responses:utter_greet:- text: |Hello! How can I help you?- text: |Hi!utter_ask_email:- text: |What is your email address?utter_subscribed:- text: |Check your inbox at {email} in order to finish subscribing to the newsletter.- text: |You're all set! Check your inbox at {email} to confirm your subscription.

定义响应

响应位于领域文件或者单独的responses.yml文件的responses键下。每个响应名称都应该以utter_开头。例如,你可以在响应utter_greet和utter_bye下添加问候和再见的响应。

intents:- greetresponses:utter_greet:- text: "Hi there!"utter_bye:- text: "See you!"

如果在对话机器人中使用检索意图,还需要为对话机器人对这些意图的回复添加响应:

intents:- chitchatresponses:utter_chitchat/ask_name:- text: Oh yeah, I am called the retrieval bot.utter_chitchat/ask_weather:- text: Oh, it does look sunny right now in Berlin.

在响应中使用变量

你可以使用变量将信息插入到响应中。在响应中,变量用大括号括起来。例如,如下的name变量:

responses:utter_greet:- text: "Hey, {name}. How are you?"

当使用utter_greet响应时,Rasa会自动使用名为name的槽中找到的值来填充变量。如果槽值不存在或为空,则该变量将填充为None

填充变量的另一种方法是在自定义动作中。在自定义动作代码中,你可以为响应提供值来填充特定变量。如果将Rasa SDK用于动作服务,可以将变量的值作为关键字参数传递给dispatcher.utter_message:

dispatcher.utter_message(template="utter_greet",name="Sara"
)

比如在Rasa SDK中可以这样写:

from rasa_sdk import Action, Tracker
from rasa_sdk.executor import CollectingDispatcherclass CustomActionExample(Action):def name(self) -> str:return "action_custom_example"def run(self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:name = "Sara"dispatcher.utter_message(template="utter_greet", name=name)return []

在这个例子中,自定义动作action_custom_example使用“utter_message”方法触发一个名为“utter_greet”的模板,并为模板中的“name”变量提供值Sara

如果您使用的是不同的自定义动作服务,可以通过在服务返回的响应中添加额外的参数来提供值。例如:

{"events":[...],"responses":[{"template":"utter_greet","name":"Sara"}]
}

响应变体

为给定的响应提供多种响应变体以供选择可以使得对话机器人的回复更有趣:

responses:utter_greet:- text: "Hey, {name}. How are you?"- text: "Hey, {name}. How is your day going?"

在上例中,当utter_greet被预测为下一个动作时,Rasa将随机选择两个响应变体中的一个来使用。

特定频道的响应变体

要根据用户连接的频道指定不同的响应变体,请使用特定于频道的响应变体。

在如下示例中,channel键的第一个响应变体特定于slack频道,而第二个变体则不是特定于通道:

responses:utter_ask_game:- text: "Which game would you like to play on Slack?"channel: "slack"- text: "Which game would you like to play?"

注意:确保 channel 键与输入频道的 name() 方法返回的值相匹配。如果你使用的是内置频道,此值也将与 credentials.yml 文件中使用的频道名称相匹配。

当对话机器人在给定响应名称下寻找合适的响应变体时,它会首先尝试从当前频道的特定频道辩题中进行选择。如果不存在此类变体,则对话机器人将从非频道特定的响应变体中进行选择。

注意:

对于每个响应,至少有一个没有channel键的响应变体,这使得对话机器人在所有环境中都可以正确的响应。

条件响应变体

也可以使用条件响应变体基于一个或多个槽值来选择特定响应变体。

条件响应变体在领域或响应YAML文件中定义,类似于标准响应变体,但具有额外的condition键。此键指定name和value槽约束的列表。

当在对话期间触发响应时,将根据当前对话状态检查每个条件响应变化的约束。如果所有约束槽值都等于当前对话状态的对应槽值,则响应变体可以被对话机器人使用。

在下面的示例中,将定义一个具有一个约束的条件响应变体,即logged_in槽设置为true:

domain.yml

slots:logged_in:type: boolinfluence_conversation: Falsemappings:- type: customname:type: textinfluence_conversation: Falsemappings:- type: customresponses:utter_greet:- condition:- type: slotname: logged_invalue: truetext: "Hey, {name}.Nice to see you again!How are you?"- text: "Welcome. How is your day going?"

stories.yml

stories:
- story: greetsteps:- action: action_log_in- slot_was_set:- logged_in: true- intent: greet- action: utter_greet

在上述示例中,只要执行utter_greet动作并将logged_in槽设置为true,就会使用第一个响应变体("Hey, {name}. Nice to see you again! How are you?")。没有条件的第二个辩题将被视为默认值,并在logged_in不等于true时使用。

注意:

强烈建议始终提供没有条件的默认响应变体,以防止没有条件响应与已填充槽匹配的情况发生。

在对话期间,Rasa将从所有满足约束条件的响应变体中进行选择。如果有多个符合条件的条件响应变体,Rasa将随机选择一个。例如,考虑如下响应:

responses:utter_greet:- condition:- type: slotname: logged_invalue: truetext: "Hey, {name}.Nice to see you again! How are you?"- condition:- type: slotname: eligible_for_upgradevalue: truetext: "Welcome, {name}. Did you know you are eligible for a free upgrade?"- text: "Welcome. How is your day going?"

如果logged_in和eligible_for_upgrade都设置为true,那么第一个和第二个响应变体都可以使用,并且将由对话机器人以相同的概率选择。

你可以继续使用特定于频道的响应变体以及条件响应变体,如下例所示:

slots:logged_in:type: boolinfluence_conversation: Falsemappings:- type: customname:type: textinfluence_conversation: Falsemappings:- type: customresponses:utter_greet:- condition:- type: slotname: logged_invalue: truetext: "Hey, {name}. Nice to see you again on Slack! How are you?"channel: slack- text: "Welcome. How is your day going?"

Rasa将按以下顺序优先选择响应:

1.匹配频道的条件响应

2.匹配频道的默认响应

3.未匹配频道的条件响应

4.未匹配频道的默认响应

富响应

可以通过添加视觉和交互元素来丰富响应。

按钮

responses:utter_greet:- text: "Hey! How are you?"buttons:- title: "great"payload: "/mood_great"- title: "super sad"payload: "/mood_sad"

按钮列表中的每个按钮都应该有两个键:

title:按钮上显示的文本

payload:单击按钮时从用户发送给助手的消息

如果你希望按钮将实体也传递给对话机器人:

responses:utter_greet:- text: "Hey! Would you like to purchase motor or home insurance?"buttons:- title: "Motor insurance"payload: '/inform{{"insurance":"motor"}}'- title: "Home insurance"payload: '/inform{{"insurance":"home"}}'

可以通过如下方式传递多个实体:

'/intent_name{{"entity_type_1":"entity_value_1","entity_type_2":"entity_value_2"}}'

图片

你可以通过在image键下提供图像的URL来将图像添加到响应中:

utter_cheer_up:
- text: "Here is something to cheer you up:"image: "https://i.imgur.com/esltfjrwls.jpg"

自定义输出荷载

你可以使用custom键将任意输出发送到输出频道。输出频道接受存储在custom键下的对象作为JSON有效荷载。

如下是如何将日期选择器发送到Slack输出频道的示例:

responses:utter_take_bet:- custom:blocks:- type: sectiontext:text: "Make a bet on when the world will end:"type: mrkdwnaccessory:type: datepickerinitial_date: '2019-05-21'placeholder:type: plain_texttext: Select a date

在对话中使用响应

将响应作为动作调用

如果响应的名称以utter_开头,则可以直接将响应用作动作,而不会在领域的actions部分中列出。

将响应添加到领域中:

responses:utter_greet:- text: "Hey! How are you?"

你可以在故事中使用相同的响应作为动作:

stories:
- story: greet usersteps:- intent: greet- action: utter_greet

当utter_greet动作运行时,它会将响应中的消息发送回用户

从自定义动作中调用响应

你可以使用响应从自定义动作中生成响应消息。如果你使用Rasa SDK作为动作服务,可以使用调度程序生成响应消息,例如:

actions.py:

from rasa_sdk.interfaces import Actionclass ActionGreet(Action):def name(self):return "action_greet"def run(self,dispatcher,tracker,domain):dispatcher.utter_message(template="utter_greet")return []

如果你使用不同的自定义动作服务,服务应返回如下JSON来调用utter_greet响应:

{"events":[],"responses":[{"template":"utter_greet"}]
}

故事

故事是用于训练对话机器人根据用户之前的对话内容做出正确响应的示例对话。故事的格式展示了用户消息的意图,然后是对话机器人的动作和响应。

你的第一个故事应该为一个对话流,其中对话机器人以简单直接的方式来帮助用户实现他们的目标。之后,可以为用户不想提供信息或切换到其他主题的情况添加故事。

stories:
- story: greet and subscribesteps:- intent: greet- action: utter_greet- intent: subscribe - action: newsletter_form- active_loop: newsletter_form

编写对话数据

对话数据包括用于Rasa对话机器人对话管理模型训练数据的故事和规则。精心编写的对话数据可以使得对话机器人能够可靠地遵循设置的对话路径并泛化道预期外的路径。

设计故事

在设计故事时,需要考虑两种对话交互:预期的和非预期的路径。预期的路径描述了当用户遵循预期的对话流程,并在收到提示时始终提供必要的信息。但是,用户经常会因为问题、闲聊或询问其他信息而偏离预期的路径,我们称这些为非预期的路径。

我们建议在设计非预期的路径时采用对话驱动的开发。

何时编写故事或规则

规则是对话管理用于处理应始终遵循相同路径的对话片段的一种训练数据。

规则在实现如下场景中很有用:

        单轮交互:有些消息不需要上下文就可以进行回答。规则是一种将意图映射到响应的简单方法,可以为这些消息指定固定的答案。

        回退行为:结合FallbackClassifier,可以编写规则来响应具有一定回退行为的低置信度用户消息。

        表单:激活和提交表单通常都会遵循固定的路径。你可以编写规则来处理表单的非预期输入。

因为规则无法泛化未遇到过的对话,因此你应该将他们保留为单轮对话片段,并使用故事来训练多轮对话。

一个对话机器人将意图为greet的用户消息返回固定响应utter_greet的规则示例如下:

rules:
- rule: Greeting Rulesteps:- intent: greet- action: utter_greet

对于多轮交互,你需要定义一个故事,例如:

stories:
- story: Greeting and ask user how they're doingsteps:- intent: greet- action: utter_greet- action: utter_ask_how_doing- intent: doing_greet- action: utter_happy

管理对话流

以下是管理故事中对话流的一些提示:

何时使用槽来影响对话

槽充当的是对话机器人的内存。当定义一个槽时,你可以定义一个槽是否应该影响对话,influence_conversation属性设置为false的槽仅用于存储信息;influence_conversation属性设置为true的槽可以基于存储的信息来影响对话流。

stories:
- story: Welcome message, premium usersteps:- intent: greet- action: action_check_profile- slot_was_set:- premium_account: true- action: utter_welcome_premium- story: Welcome message, basic usersteps:- intent: greet- action: action_check_profile- slot_was_set:- premium_account: false- action: utter_welcome_basic- action: utter_ask_upgrade

如果你不希望槽影响对话流,则应将槽的influence_conversation属性设置为false,不需要在故事中对不影响对话的槽包含slot_was_set事件。

实现分支逻辑

在编写故事时,有时候下一个动作将取决于一个自定义动作的返回值。在这些情况下,重要的是要在返回槽和直接使用自定义动作代码来影响对话机器人下一步做什么之间找到平衡。

当某个值仅用于确定对话机器人的响应的情况时,可以考虑将决策逻辑嵌入自定义动作中,而不是在故事中使用一个特征化的槽。浙江有助于降低整体复杂性并使得故事更易于管理。

例如,你可以将这些故事:

stories:
- story: It's raining nowsteps:- intent: check_for_rain- action: action_check_for_rain- slot_was_set:- rainint: true- action: utter_is_raining- action: utter_bring_umbrella- story: It isn't raining nowsteps:- intent: check_for_rain- action: action_check_for_rain- slot_was_set:- raining: false- action: utter_not_raining- action: utter_no_umbrella_needed

通过如下自定义动作代码:

def run(self,dispatcher,tracker,domain):is_raining=check_rain()if is_raining:dispatcher.utter_message(template="utter_is_raining")dispatcher.utter_message(template="utter_bring_umbrella")else:dispatcher.utter_message(template="utter_not_raining")dispatcher.utter_message(template="utter_no_bring_needed")return []

转换成一个单独的故事:

stories:
- story: check for rainsteps:- intent: check_for_rain- action: action_check_for_rain

在某个值用于影响未来的动作流的情况下,则返回一个特征化槽来确定故事。例如,如果你想收集有关新用户的信息,而不是返回用户的信息,则故事可能如下:

stories:
- story: greet new usersteps:- intent: greet- action: check_user_status- slot_was_set:- new_user: true- action: utter_greet- action: new_user_form- active_loop: new_user_form- active_loop: null- story: greet returning usersteps:- intent: greet- action: check_user_status- slot_Was_set:- new_user: false- action: utter_greet- action: utter_how_can_help

使用或语句和检查点

或语句和检查点可用于减少必须编写的故事数量。但你应该谨慎使用它们。过度使用或语句和检查点会减慢训练速度,创建过多的检查点会让你的故事难以理解。

或语句

在对话机器人以相同方式处理不同意图或槽事件中,可以使用或语句作为创建新故事的替代方法。

stories:
- story: newsletter signupsteps:- intent: signup_newsletter- action: utter_ask_confirm_signup- intent: affirm- action: action_signup_newsletter- story: newsletter signup, confirm via thankssteps:- intent: signup_newsletter- action: utter_ask_confirm_signup- intent: thanks- action: action_signup_newsletter

用或语句合并为一个故事:

stories:
- story: newsletter signup with orsteps:- intent: signup_newsletter- action: utter_ask_confirm_singup- or:- intent: affirm- intent: thanks- action: action_signup_newsletter

在训练阶段,这个故事将被划分为两个原始故事

检查点

检查点对于将故事模块化成经常重复的单独部分时很有用。例如,如果你希望对话机器人在每个对话流结束时询问用户反馈,可以使用检查点来避免在每个故事结束时包含反馈交互:

stories:
- story: beginning of conversationsteps:- intent: greet- action: utter_greet- intent: goodbye- action: utter_goodbye- checkpoint: ask_feedback- story: user provides feedbacksteps:- checkpoint: ask_feedback- action: utter_ask_feedback- intent: inform- action: utter_thank_you- action: utter_anything_else- story: user doesn't have feedbacksteps:- checkpoint: ask_feedback- action: utter_ask_feedback- intent: deny- action: utter_no_problem- action: utter_anything_else

注意:检查点旨在使不同故事中重复使用某些对话部分变得更加容易。但是强烈反对在现有检查点内部使用检查点,这会显著增加训练时间并使故事难以理解。

在故事中创建逻辑中断

在设计对话流时,经常会创建长的故事来从头到尾补货完整的对话交互。在很多情况下,由于需要考虑分支路径,这会增加需要训练故事的数量。相反,可以考虑将较长的故事分成较小的对话块来处理子任务。

一个用户处理信用卡丢失的预期路径可能如下所示:

stories:
- story: Customer loses a credit card, reviews transactions, and gets a new cardsteps:- intent: card_lost- action: check_transactions- slot_was_set:- reviewed_transactions: ["starbucks"]- action: utter_ask_fraudulent_transactions- intent: inform- action: action_update_transactions- intent: affirm- action: utter_confirm_transaction_dispute- action: utter_replace_card- action: mailing_address_form- active_loop: mailing_address- active_loop: null- action: utter_sent_replacement- action: utter_anything_else- intent: affirm- action: utter_help

处理一个信用卡丢失设计一系列子任务,包括用于欺诈交易的消费历史检查、确认替换卡的邮寄地址、然后跟进用户的其他要求。在对话中,对话机器人会在多个地方提示用户输入,创建需要用到的分支路径。

例如:当提示utter_ask_fraudulent_transactions时,如果并不适用,用户可能会以deny意图进行响应。当用户被问及对话机器人是否可以帮助他们时,用户可以以deny意图进行响应。

我们可以将这个长故事分成几个小故事:

stories:
- story: Customer loses a credit cardsteps:- intent: card_lost- action: utter_card_locked- action: spending_history_form- active_loop: spending_history_form- active_loop: null- slot_was_set:- reviewed_transactions: ["starbucks"]- action: utter_ask_fraudulent_transactions- story: Customer reviews transactions and gets a new cardsteps:- action: utter_ask_fraudulent_transactions- intent: inform- action: action_update_transactions- slot_was_set:- reviewed_transactions: ["target", "starbucks"]- intent: affirm- action: utter_confirm_transaction_dispute- action: utter_replace_card- action: mailing_address_form- active_loop: mailing_address- active_loop: null- action: utter_sent_replacement- action: utter_anything_else- story: Customer has something else they need help withsteps:- action: utter_anything_else- intent: affirm- action: utter_help

处理上下文切换

通常,用户不会用你向他们询问的消息做出回应,而是会用不相关的问题来偏离预期的路径。

使用规则进行上下文切换

在单轮插入语情况下,可以使用规则而非故事来处理上下文切换。

 在这个示例中,用户在支付信用卡账单的过程中询问账户余额,之后被引导回信用卡支付表单。因为无论上下文如何询问用户余额都应该始终得到相同的响应,因此你可以在现有流程中创建一个可以自动触发的规则:

rules:
- rule: Check my account balancesteps:- intent: check_account_balance- action: action_get_account_balance

默认情况下,表单将持续保持活动状态并重新提示必要的信息,而无需创建额外的训练故事。

使用故事进行上下文切换

当用户的插入语需要多轮对话时,你需要编写额外的故事来处理上下文切换。如果你有两个不同对话流并希望用户能在流之间切换,则需要创建故事来指定切换将如何发生以及如何维护上下文。

例如,如果你想在用户询问时切换上下文,然后在询问完成后返回原始流程:

 你需要创建一个故事来描述这种上下文切换交互:

stories:
- story: Context switch from credit card payment to money transfersteps:- intent: pay_credit_card- action: credit_card_payment_form- active_loop: credit_card_payment_form- intent: transfer_money- active_loop: null- action: transfer_money_form- active_loop: transfer_money_form- active_loop: null- action: utter_continue_credit_card_payment

管理对话数据文件

你可以将训练数据作为单个文件或包含多个文件的目录提供给开源Rasa。在编写故事和规则时,通常最好根据所表示的对话类型创建单独的文件。

例如,你可以创建一个chitchat.yml文件来处理闲聊,创建一个faqs.yml来处理faq。

表单

在很多情况下,对话机器人需要从用户收集信息。例如:当一个用户想要订阅时事通讯时,对话机器人必须询问其电子邮箱地址。

slots:email:type: textmappings:- type: from_textcondition:- active_loop: newsletter_form- requested_slot: emailforms:newsletter_form:required_slots:- email

用法

要在开源Rasa中使用表单,你需要确保将规则策略添加到策略配置中。例如:

policies:
- name: RulePolicy

定义表单

通常将表单添加到领域中的forms部分来定义表单。

表单的名称也可以是你在故事或者规则中用于处理表单执行的动作的名称。

你需要为必需的required_slots键指定槽名称列表。

如下示例表单restaurant_form将填充cuisine和num_people槽。

entities:
- cuisine
- numberslots:cuisine:type: textmappings:- type: from_entityentity: cuisinenum_people:type: anymappings:- type: from_entityentity: numberforms:restaurant_form:required_slots:- cuisine- number

可以再ignored_intents键下为整个表单定义要忽略的意图列表。在ignored_intents下列出的意图将被添加到每个槽映射的not_intent键中。

例如,如果你不希望在chitchat意图时填写表单所需槽,那么需要定义如下内容(在表单名称之后和ignored_intents意图关键字下):

entities:
- cuisine
- number
slots:cuisine:type: textmappings:- type: from_entityentity: cuisinenum_people:type: anymappings:- type: from_entityentity: number
forms:restaurant_form:ignored_intents:- chitchatrequired_slots:- cuisine- num_people

一旦表单动作第一次被调用,表单就会被激活并提示用户输入下一个所需的槽。它通过查找名为utter_ask_<form_name>_<slot_name>或utter_ask_<slot_name>(如果未找到前者)的响应来执行此动作。确保在领域文件中为每个必须的槽定义这些响应。

激活表单

要激活表单,你需要添加一个故事或规则,它描述了对话机器人应该何时运行表单。在特定意图触发表单的情况下,可以使用如下示例规则:

rules:
- rule: Activate formsteps:- intent: request_restaurant- action: restaurant_form- active_loop: restaurant_form

停用表单

填写完所有必须的槽后,表单将自动停用。

你可以使用规则或者故事来描述对话机器人在表单结束时的行为。如果不添加适用的故事或规则,对话机器人将在表单完成后自动接收下一条用户消息。

如下示例在表单your_form填满所有必须的槽后立即运行utter_submit和utter_slots_values

rules:
- rule: Submit formconditon:- active_loop: restaurant_formsteps:- action: restaurant_form- active_loop: null- slot_was_set:- requested_slot: null- action: utter_submit- action: utter_slots_values

槽映射

从3.0版本开始,槽映射在领域的slots部分中定义。此更改允许在多个表单中重复使用相同的槽映射,从而消除不必要的重复。

为非预期的表单路径编写故事/规则

用户不会总是回复要求他们提供的信息。通常,用户会提出问题、闲聊、改变主意,或者以其他方式偏离预期的路径。

当表单处于活动状态时,如果用户的输入未填充请求的槽,则表单动作的执行将被拒绝,即表单将自动引发ActionExecutionRejection。以下是表单将引发ActionExecutionRejection的特定场景:

        请求一个槽,但用户没有用他们的最后一条信息填充槽,并且没有定义用于验证槽或提取槽的自定义动作

        请求一个槽,但用于验证槽或提取槽的自定义动作未返回任何SlotSet事件

要有意拒绝表单执行,还可以返回ActionExecutionRejected事件作为自定义验证或槽映射的一部分。

要处理可能导致表单执行被拒绝的情况,你可以编写包含预期中断的规则或故事。例如,如果你希望用户与对话机器人闲聊,可以添加一个规则来处理这个问题:

rules:
- rule: Example of an unhappy pathcondition:- active_loop: restaurant_formsteps:- intent: chitchat- action: utter_chitchat- action: restaurant_form- active_loop: restaurant_form

在某些情况下,用户可能会在表单动作的中间改变主意并决定不继续它们的初识请求。在这种情况下,对话机器人应该获取要求的槽。

使用action_deactivate_loop默认动作可以优雅地处理此类情况。该动作将停用表单并重置请求的槽。此类对话示例故事如下所示:

stories:
- story: User interrupts the form and doesn't want to continuesteps:- intent: request_restaurant- action: restaurant_form- active_loop: restaurant_form- intent: stop- action: utter_ask_continue- intent: stop- action: action_deactivate_loop- active_loop: null

进阶用法

使用自定义动作可完全自定义表单。

校验表单输入

从用户输入中提取槽值后,可以验证提取的槽。默认情况下,Rasa仅在请求槽后验证是否填充了任何槽。

可以通过自定义动作validate_<form_name>来验证任何提取的槽。确保将此动作添加到领域的actions部分:

actions:
- validate_restaurant_form

执行表单时,它将在每个用户轮流验证最新填充的槽后运行自定义动作。

此自定义动作可以扩展FormValidationAction类来简化验证提取槽的过程。在这种情况下,你需要为每个提取的槽编写名为validate_<slot_name>函数。

如下示例显示了一个自定义动作的视线,该动作验证名为cuisine的槽是否有效。

from typing import Text, List, Any, Dictfrom rasa_sdk import Tracker, FormValidationAction
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk.types import DomainDictclass ValidateRestaurantForm(FormValidationAction):def name(self) -> Text:return "validate_restaurant_form"@staticmethoddef cuisine_db() -> List[Text]:"""Database of supported cuisines"""return ["caribbean", "chinese", "french"]def validate_cuisine(self,slot_value: Any,dispatcher: CollectingDispatcher,tracker: Tracker,domain: DomainDict,) -> Dict[Text, Any]:"""Validate cuisine value."""if slot_value.lower() in self.cuisine_db():# validation succeeded, set the value of the "cuisine" slot to valuereturn {"cuisine": slot_value}else:# validation failed, set this slot to None so that the# user will be asked for the slot againreturn {"cuisine": None}

你还可以扩展Action类并使用tracker.slots_to_validate检索提取的槽,以完全自定义验证过程。

自定义槽映射

如果预定义的槽映射都不适用你的用例,可以使用自定义动作 validate_<form_name> 编写自己的提取代码。开源 Rasa 将在表单运行时触发此动作。

如果使用的是 Rasa SDK,我们建议你扩展提供的 FormValidationAction。使用 FormValidationAction 时,需要三个步骤提取自定义槽:

  1. 为应该以自定义方式映射的每个槽定义一个方法 extract_<slot_name>

  2. 在领域文件中,对于表单的 required_slots,列出所有必须的槽,包括预定义和自定义映射。

此外,可以重写 required_slots 方法来添加动态请求的槽,可以在动态表单行为部分获取更多信息。

如下示例显示了一个表单的实现,该表单以自定义方式提取槽 outdoor_seating,以及使用预定义映射的槽。extract_outdoor_seating 方法根据关键字 outdoor 是否出现在最后一个用户消息中来设置槽 outdoor_seating

from typing import Dict, Text, List, Optional, Anyfrom rasa_sdk import Tracker
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk.forms import FormValidationActionclass ValidateRestaurantForm(FormValidationAction):def name(self) -> Text:return "validate_restaurant_form"async def extract_outdoor_seating(self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict) -> Dict[Text, Any]:text_of_last_user_message = tracker.latest_message.get("text")sit_outside = "outdoor" in text_of_last_user_messagereturn {"outdoor_seating": sit_outside}

默认情况下,FormValidationAction会自动将requested_slot设置为required_slots中指定的第一个未填充的槽。

动态表单行为

默认情况下,开源 Rasa 将在领域文件中为表单列出的槽中请求下一个空槽。如果使用自定义槽映射和 FormValidationAction,它将要求 required_slots 方法返回第一个空槽。如果 required_slots 中的所有槽都已经填满,则表单将被停用。

如果需要,可以动态更新表单的所需槽。例如,当你需要根据前一个槽的填充方式获得更多详细信息或想要更改请求槽的顺序时,这很有用。

如果你使用 Rasa SDK,我们建议使用 FormValidationAction 并覆盖 required_slots 以适应动态行为。你应该为每个不使预定义映射的槽实现一个方法 extract_<slot name>,如自定义槽映射中所述。如下示例将询问用户是否想坐在阴凉处或阳光下,以防他们想说坐在外面。

from typing import Text, List, Optionalfrom rasa_sdk.forms import FormValidationActionclass ValidateRestaurantForm(FormValidationAction):def name(self) -> Text:return "validate_restaurant_form"async def required_slots(self,domain_slots: List[Text],dispatcher: "CollectingDispatcher",tracker: "Tracker",domain: "DomainDict",) -> List[Text]:additional_slots = ["outdoor_seating"]if tracker.slots.get("outdoor_seating") is True:# If the user wants to sit outside, ask# if they want to sit in the shade or in the sun.additional_slots.append("shade_or_sun")return additional_slots + domain_slots


相反,如果想在特定条件下从领域文件中定义表单的required_slots中删除一个槽,应该将domain_slots复制到一个新变量并将更改应用于该新变量,而不是直接修改domain_slots。直接修改domain_slots可能会导致意外行为。例如:

from typing import Text, List, Optionalfrom rasa_sdk.forms import FormValidationActionclass ValidateBookingForm(FormValidationAction):def name(self) -> Text:return "validate_booking_form"async def required_slots(self,domain_slots: List[Text],dispatcher: "CollectingDispatcher",tracker: "Tracker",domain: "DomainDict",) -> List[Text]:updated_slots = domain_slots.copy()if tracker.slots.get("existing_customer") is True:# If the user is an existing customer,# do not request the `email_address` slotupdated_slots.remove("email_address")return updated_slots



requested_slot槽

stories:
- story: explain cuisine slotsteps:- intent: request_restaurant- action: restaurant_form- active_loop: restaurant- slot_was_set:- requested_slot: cuisine- intent: explain- action: utter_explain_cuisine- action: restaurant_form- active_loop: null- story: explain num_people slotsteps:- intent: request_restaurant- action: restaurant_form- active_loop: restaurant- slot_was_set:- requested_slot: cuisine- slot_was_set:- requested_slot: num_people- intent: explain- action: utter_explain_num_people- action: restaurant_form- active_loop: null

使用自定义动作请求下一个槽

一旦表单确定用户接下来必须填写哪个槽,它将执行 utter_ask_<form_name>_<slot_name>utter_ask_<slot_name> 动作来要求用户提供必要的信息。如果常规话术不够,可以使用自定义动作 action_ask_<form_name>_<slot_name>action_ask_<slot_name> 来请求下一个槽。

from typing import Dict, Text, Listfrom rasa_sdk import Tracker
from rasa_sdk.events import EventType
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk import Actionclass AskForSlotAction(Action):def name(self) -> Text:return "action_ask_cuisine"def run(self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict) -> List[EventType]:dispatcher.utter_message(text="What cuisine?")return []

如果槽有多个询问选项,Rasa 将按照如下顺序排列优先级:

  1. action_ask_<form_name>_<slot_name>
  2. utter_ask_<form_name>_<slot_name>
  3. action_ask_<slot_name>
  4. utter_ask_<slot_name>

规则

规则描述了对话中应该始终遵循的相同路径,无论在之前的对话中说过什么。

我们希望对话机器人能够始终以特定动作来响应一个特定意图,因此我们需要使用规则将动作映射到意图。

在代码块中,我们添加了一条规则,该规则在用户表达“订阅”意图时触发 newsletter_form。我们还添加了一条规则用于一旦提供了所有必需的信息就触发 utter_subscribed 动作。第二条规则仅在 newsletter_form 开始激活时适用,一单它不再处于激活状态(active_loop: null)后,表单就完成了。

rules:- rule: activate subscribe formsteps:- intent: subscribe- action: newsletter_form- active_loop: newsletter_form- rule: submit formcondition:- active_loop: newsletter_formsteps:- action: newsletter_form- active_loop: null- action: utter_subscribed

规则简介

规则是一种用于训练对话机器人的对话管理模型的训练数据。规则描述了应该始终遵循的相同路径的简短对话。

不要过度使用规则。规则非常适合处理小型的特定对话模式,但与故事不同,规则没有能力泛化至未见过的对话路径。结合规则和故事,可以使对话机器人变得更加鲁棒并能够处理真实的用户行为。

编写规则

在开始编写规则之前,你必须确保将规则策略添加到模型配置中:

policies:
- name: RulePolicy

可以将规则添加到训练数据的rules部分。

要表明规则可以在对话中的任何点使用,请从启动会话的意图开始,然后添加对话机器人应执行的动作来响应意图。

rules:
- rule: Say `hello` whenever the user sends a message with intent `greet`steps:- intent: greet- action: utter_greet

此示例规则适用于对话开始以及用户决定在正在进行的对话中发送带有greet意图的消息时。

仅作为规则出现在训练数据中而不出现在故事中的对话轮次将在预测时被 TEDPolicy 等仅机器学习策略忽略。

rules:
- rule: Say `hello` whenever the user sends a message with intent `greet`steps:- intent: greet- action: utter_greetstories:
- story: story to find a restaurantsteps:- intent: find_restaurant- action: restaurant_form- action: utter_restaurant_found

例如,如果如上所述定义了问候规则并且不将其添加到任何故事中,则在RulePolicy预测utter_greet之后,TEDPolicy将进行预测,就像没有发生greet和utter_greet轮次一样。

用于对话开始的规则

要编写仅适用于对话开始的规则,请在规则中添加一个conversation_start: true

rules:
- rule: Say hello when the user starts a conversation with intent greetconversation_start: truesteps:- intent: greet- action: utter_greet

如果用户稍后在对话中发送带有greet的意图的消息,规则将不匹配。

有条件的规则

条件描述了为适用规则而必须满足的要求。为此,请在condition键下添加有关先前对话的任何信息:

rules:
- rule: Only say hello if the user provided a namecondition:- slot_was_set:- user_provided_name: truesteps:- intent: greet- action: utter_greet

你可以在条件下包含的可能信息包括slot_was_set事件和active_loop事件。

在规则结束跳过等待用户输入

默认情况下,规则将在完成最后一步后等待下一条用户信息:

rules:
- rule: Rule which will wait for user message when it was appliedsteps:- intent: greet- action: utter_greet# - action: action_listen# Every rule implicitly includes a prediction for `action_listen` as last step.# This means that Rasa Open Source will wait for the next user message.

如果你想将下一个动作预测交给另一个故事或规则,请将wait_for_user_input:false添加到你的规则中:

rules:
- rule: Rule which will not wait for user message once it was appliedsteps:- intent: greet- action: utter_greetwait_for_user_input: false

这表明对话机器人应该在等待更多用户输入之前执行另一个动作。

规则和表格

当表单处于活动状态时,对话机器人将根据表单的定义方式进行预测,而忽略规则。如果出现以下情况,规则将再次可用:

        表单填充了所有必须的槽

        表单拒绝执行

运行

第一步: rasa train

用于训练NLU数据和故事成为一个模型,保存至./models

第二步:rasa shell

加载训练好的模型并让你可以通过命令行与机器人交谈

 


Rasa入门案例到此为止~

相关文章:

【Rasa】入门案例学习

Rasa初体验--构建对话机器人 NLU数据 version: "3.1"nlu:- intent: greetexamples: |- Hi- Hey!- Hello- Good day- Good morning- intent: subscribeexamples: |- I want to get the newsletter- Can you send me the newsletter?- Can you sign me up for the ne…...

基于java的坦克大战游戏的设计与实现--开题报告--【毕业论文】

文章目录 本系列校训毕设的技术铺垫文章主体层次选题目的和意义&#xff1a;与本课题相关的技术和方法综述&#xff1a;主要设计内容&#xff1a;设计的环境、方法及措施&#xff1a;参考文献 配套资源 本系列校训 互相伤害互相卷&#xff0c;玩命学习要你管&#xff0c;天生我…...

学习笔记|百度文心千帆大模型平台测试及页面交互简易代码

目前百度文心一言的内测资格申请相当拉胯&#xff0c;提交申请快3个月&#xff0c;无任何音讯。不知道要等到什么时候。 百度适时开放了百度文心千帆大模型平台&#xff0c;目前可以提交申请测试&#xff0c;貌似通过的很快&#xff0c;已取得测试申请资格&#xff0c;可以用起…...

Python中的数据科学实验库有哪些?

Python中有许多数据科学实验库可供使用。以下是一些常用的库&#xff1a; NumPy&#xff1a;用于处理大型多维数组和矩阵的基础数学库。Pandas&#xff1a;用于数据处理和分析的库&#xff0c;提供了灵活的数据结构和数据操作工具。Matplotlib&#xff1a;用于创建静态、动态和…...

区间预测 | MATLAB实现QRLSTM长短期记忆神经网络分位数回归多输入单输出区间预测

区间预测 | MATLAB实现QRLSTM长短期记忆神经网络分位数回归多输入单输出区间预测 目录 区间预测 | MATLAB实现QRLSTM长短期记忆神经网络分位数回归多输入单输出区间预测效果一览基本介绍模型描述程序设计参考资料 效果一览 基本介绍 MATLAB实现QRLSTM长短期记忆神经网络分位数回…...

Pytorch nn.Linear的基本用法与原理详解

1. 参考 Pytorch nn.Linear的基本用法与原理详解_iioSnail的博客-CSDN博客 [机器学习]深度学习初学者大疑问之nn.Linear(a,b)到底代表什么?_五阿哥爱跳舞的博客-CSDN博客...

数据结构:栈和队列的实现和图解二者相互实现

文章目录 写在前面栈什么是栈栈的实现 队列什么是队列队列的实现 用队列实现栈用栈模拟队列 写在前面 栈和队列的实现依托的是顺序表和链表&#xff0c;如果对顺序表和链表不清楚是很难真正理解栈和队列的 下面为顺序表和链表的实现和图解讲解 手撕图解顺序表 手撕图解单链表 …...

深入理解C++命名空间

文章目录 1. 命名空间的概念2. 解决命名冲突3. 嵌套命名空间4. 使用命名空间别名总结 在C编程中&#xff0c;命名空间&#xff08;Namespace&#xff09;是一种非常有用的工具&#xff0c;它可以帮助我们组织和管理代码&#xff0c;避免命名冲突。本文将深入介绍C命名空间的概念…...

<MySQL>建表SQ和CRUD SQ脚本案例二

1. MySQL 建表SQ脚本案例&#xff1a; 地域表 CREATE TABLE xxx_region_list_dic (seqId INT(11) NOT NULL AUTO_INCREMENT,sortId INT(11) DEFAULT NULL,name VARCHAR(255) NOT NULL COMMENT 地域,code VARCHAR(25) NOT NULL COMMENT 编码,isEnable VARCHAR(25) DEFAULT NULL…...

webpack基础配置

webpack基础 webpack 处理css兼容问题webpack 处理css闪屏问题webpack 优化压缩css代码总结webpack 两种开发模式webpack 基本的功能webpack配置 5概念devServer 生产环境webpack配置实例开发环境webpack配置实例webpack优化 webpack 处理css兼容问题 下载loader 引入 package…...

宝塔面板Django项目部署(无数据库版)

近日在学习使用宝塔面板部署Django开发的web项目&#xff0c;走了不少弯路花了3天的时间才完成下面的文字&#xff0c;希望这篇文字能给正在摸索中的人带去点帮助。 一、安装宝塔面板 打开宝塔面板的官方网站(https://www.bt.cn/new/index.html).点击" " 会看到: 当…...

windows默认编码格式修改

1.命令提示符界面输入 chcp 936 对应 GBK 65001 对应 UTF-8 2.临时更改编码格式 chcp 936(或65001) 3.永久更改编码格式 依次开控制面板->时钟和区域->区域->管理->更改系统区域设置&#xff0c;然后按下图所示&#xff0c;勾选使用UTF-8语言支持。然后重启电脑。此…...

原生js vue react通用的递归函数

&#x1f642;博主&#xff1a;锅盖哒 &#x1f642;文章核心&#xff1a;原生js vue react通用的递归函数 目录大纲 1.递归函数的由来 2.代码逻辑 1.递归函数的由来 递归函数的由来可以追溯到数学中的递归概念和数学归纳法。 在数学中&#xff0c;递归是指通过定义基本情况和…...

vue指令-v-text和v-html

vue指令-v-text和v-html 1、目标2、语法 1、目标 更新DOM对象的innerText/innerHTML 2、语法 v-text“Vue数据变量" v-html“Vue数据变量"注意&#xff1a;会覆盖插值表达式 示例&#xff1a; <template><div id"app"><div><p v…...

quartus工具篇——PLL IP核的使用

quartus工具篇——PLL IP核的使用 1、PLL简介 PLL(Phase-Locked Loop,相位锁环)是FPGA中非常重要的时钟管理单元,其主要功能包括: 频率合成 - PLL可以生成比输入时钟频率高的时钟信号。频率分频 - PLL也可以输出分频后的较低频率时钟。减小时钟抖动 - PLL可以过滤输入时钟中…...

[Angular] Import TranslateModule in Angular 16

1.Background Angular 更新至V16版后&#xff0c;支援 standalone&#xff0c;故移除了 NgModule&#xff0c;而TranslateModule 又要在AppModule中 import&#xff0c;那该如何做呢&#xff1f; 2.NPM packages installation npm install ngx-translate/core npm install n…...

Web自动化测试高级定位xpath

高级定位-xpath 目录 xpath 基本概念xpath 使用场景xpath 语法与实战 xpath基本概念 XPath 是一门在 XML 文档中查找信息的语言XPath 使用路径表达式在 XML 文档中进行导航XPath 的应用非常广泛XPath 可以应用在UI自动化测试 xpath 定位场景 web自动化测试app自动化测试 …...

2023河南萌新联赛第(二)场:河南工业大学 F - 最短距离

2023河南萌新联赛第&#xff08;二&#xff09;场&#xff1a;河南工业大学 F - 最短距离 时间限制&#xff1a;C/C 1秒&#xff0c;其他语言2秒 空间限制&#xff1a;C/C 262144K&#xff0c;其他语言524288K 64bit IO Format: %lld 题目描述 给定一棵包含 n n n 个顶点的树…...

前端文件上传实践与后端处理——文件分块上传

文件上传是现代Web应用程序中常见的功能之一。在这篇博客中&#xff0c;我们将探讨一个简单但完整的前端文件上传实践&#xff0c;同时提供一个后端示例&#xff0c;演示如何处理上传的文件。我们将使用JavaScript作为前端语言&#xff0c;并结合Node.js作为后端环境。让我们开…...

SFP6012A-ASEMI代理海矽美快恢复二极管参数、尺寸、规格

编辑&#xff1a;ll SFP6012A-ASEMI代理海矽美快恢复二极管参数、尺寸、规格 型号&#xff1a;SFP6012A 品牌&#xff1a;ASEMI 封装&#xff1a;TO-247AC 恢复时间&#xff1a;100ns 正向电流&#xff1a;60A 反向耐压&#xff1a;1200V 芯片大小&#xff1a;102MIL*2…...

githack的安装步骤+一次错误体验

一.githack的安装步骤 1.要在Kali Linux上安装GitHack工具&#xff0c;您可以按照以下步骤操作&#xff1a; 打开终端并使用以下命令克隆GitHack存储库&#xff1a; git clone https://github.com/lijiejie/GitHack.git2.进入GitHack目录&#xff1a; cd GitHack3.安装依赖项…...

【Spring框架】SpringBoot创建和使用

目录 什么是SpringBoot&#xff1f;SpringBoot优点创建SpringBootSpringBoot使用 什么是SpringBoot&#xff1f; Spring 的诞⽣是为了简化 Java 程序的开发的&#xff0c;⽽ Spring Boot 的诞⽣是为了简化 Spring 程序开发的。 SpringBoot优点 1.起步依赖(创建的时候就可以方…...

【C语言项目】多臂井径电子测井成像项目(一)

目录 1、目的和意义2、本章概述3、串口R2324、OpenGL5、开发环境6、环境配置6.1、VS安装OpenGL6.2、虚拟串口生成工具 7、成品速览参考文献 1、目的和意义 本项目为获取矿藏地层的油气当量和及时精确地测量含油、含气层的压力及温度值的需求&#xff0c;辅助生产管理人员完成对…...

力扣 56. 合并区间

题目来源&#xff1a;https://leetcode.cn/problems/merge-intervals/description/ C题解&#xff1a;根据左区间排序&#xff0c;更新每一段的右区间最大值&#xff0c;直到间断。 class Solution { public:static bool cmp(vector<int> & a, vector<int> &a…...

前端开发Vue3.0 标签setup语法『UI组件库』之『模态框』【业务提升必备】

封装模态框需要定义的参数 title //弹窗标题 show // 是否显示弹窗 width // 弹窗宽度 height // 弹窗高度 borderRadius // 弹窗圆角 headerColor // 弹窗顶部颜色 contentText // 内容文本 contentTextCorder //内容文本颜色 position // 标题的位置 …...

在CSDN学Golang云原生(Kubernetes二开)

一&#xff0c;通过client-go管理集群资源 Kubernetes提供了client-go库&#xff0c;该库可以让开发人员使用Golang编写的应用程序与Kubernetes API进行交互。通过client-go&#xff0c;你可以创建、更新和删除Kubernetes资源&#xff0c;并查询集群状态等信息。 以下是一个示…...

chatglm-6b量化推理指标记录

chatglm量化推理指标对比&#xff0c;单卡显存32G, 保持batchsize为64不变。通过不同的量化可以节省显存进而提升提升batch size&#xff0c;加快全量数据的推理速度。当然通过量化可以降低大模型的显存使用门槛。...

Android kotlin系列讲解之最佳的UI体验 - Material Design 实战

目录 一、什么是Material Design二、Toolbar三、滑动菜单1、DrawerLayout2、NavigationView 四、悬浮按钮和可交互提示1、FloatingActionButton2、Snackbar3、CoordinatorLayout 五、卡片式布局1、MaterialCardView2、AppBarLayout 六、可折叠式标题栏1、CollapsingToolbarLayo…...

链表基础知识

一、什么是链表 链表是一种物理存储结构上非连续&#xff0c;非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的。 链表的结构是多式多样的&#xff0c;当时通常用的也就是两种&#xff1a; &#xff08;1&#xff09;第一种是无头非循环单向…...

process.env.npm_config_argv的值3个参数remain、cooked、original什么含义

在使用Webpack进行打包时&#xff0c;判断process.env.npm_config_argv的值通常是为了根据命令行参数来决定打包的行为。process.env.npm_config_argv是一个环境变量&#xff0c;保存了当前运行的npm命令和其参数。 具体而言&#xff0c;process.env.npm_config_argv的值是一个…...