一、Rasa简介
Rasa是一套用来构建基于上下文的AI小助手和聊天机器人框架。
分为两个主要的模块:
- NLU:自然语言理解模块,实现意图识别以及槽值的提取,将用户的输入转化为结构性数据,在训练过程中,为了提高从用户信息的实体识别能力,采用了预先训练的实体提取器Pre-trained Entity Extractors,正则表达式Regexes,同义词Synonyms等
- Rasa Core:对话管理模块,也是一个平台,用来预测决定下一步做什么,其中对话数据包括了stories以及rules
- 其中设计对话数据时分为happy and unhappy paths,前者表示用户按照预期来进行会话,但用户通常会通过提问,闲聊或其他要求来进入后者。
- RasaX:一个交互工具,帮助用户构建,改进和部署由Rasa框架搭成的聊天机器人
其中,rasa版本已经发展到了3.0,与之前的1.0,2.0都有较大的差距,在这里会直接介绍最新版本,感兴趣的可以了解其他版本。
二、Rasa的数据构成
在此处,构建小助手是使用rasa官网的交互式网页来构建的,可以直接将训练数据输入并训练,再进行测试,十分方便。也可以将你的模型下载下来,方便之后的使用与改进。以下是Rasa的数据构成
2.1NLUdata
在这里,意向(intent)及其示例(examples)用作聊天小助手的自然语言理解 (NLU) 模型的训练数据
nlu:
- intent: greetexamples: |- Hi- Hey!- Hallo- 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?
2.2Responses
现在,聊天小助手已经理解了用户可能会说的几条消息,它需要可以发回给用户的响应Responses
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 newsletter!- text: |You're all set! Check your inbox at {email} to confirm your subscription.
2.3Stories
Stories是示例对话,可根据用户之前在对话中所说的内容正确响应训练助手。格式显示用户消息的意图,后跟助手的操作或响应。
stories:- story: greet and subscribesteps:- intent: greet- action: utter_greet- intent: subscribe- action: newsletter_form- active_loop: newsletter_form
Stories的编写注意事项
2.4Forms
在许多情况下,聊天助手需要从用户那里收集信息。例如,当用户想要订阅新闻稿时,助理必须询问其电子邮件地址,您可以使用表单在Rasa中执行此操作
slots:email:type: textmappings:- type: from_textconditions:- active_loop: newsletter_formrequested_slot: email
forms:newsletter_form:required_slots:- email
2.5Rules
规则描述了对话的某些部分,无论之前在对话中说了什么,这些部分都应始终遵循相同的规则。我们希望我们的助手始终使用特定操作响应某个意图,因此我们使用Rules将该操作映射到意图
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
Rules的好处:
- 单轮交互:某些消息不需要任何上下文来回答它们。规则Rules是将意向映射到响应的简单方法,可指定这些消息的固定答案。
- 回退行为:与回退分类器结合使用时,可以编写规则来响应具有特定回退行为的低可信度用户消息。
- 表单:激活和提交表单通常遵循固定路径。您还可以编写规则来处理表单中的意外输入
举个例子,比如询问使用信用卡A支付还是信用卡B来支付,但是用户通常会询问信用卡的账户余额,而不是直接回答选择哪一个来支付。
以上数据准备完成之后就可以在官网上进行训练并测试结果,也可以下载下来。
三、Rasa的简单安装
python版本为3.7或者3.8,推荐使用Ubuntu系统,并且使用虚拟环境。
Linux环境下python虚拟环境virtualenv安装和使用——包含虚拟环境集中管理库
python3 -m venv ./venv #创建虚拟环境,
source venv/bin/activate #激活虚拟环境
pip3 install -U pip && pip3 install rasa # 安装rasa,pip的版本在21.3
rasa init #创建默认的初始项目,项目文件
此项目还需要其他的依赖包,需要什么就下载什么就可以了。
命令行界面——主要是rasa train,训练并将模型保存起来
3.1初始项目文件的组成——数据格式
├── actions
│ ├── __init__.py
│ └── actions.py
├── config.yml
├── credentials.yml
├── data
│ ├── nlu.yml
│ └── stories.yml
├── domain.yml
├── endpoints.yml
├── models
│ └── <timestamp>.tar.gz
└── tests└── test_stories.yml
主要文件的作用
__init__.py | 空文件 |
---|---|
actions.py | 可以自定义 actions 的代码文件 |
config.yml ‘*’ | Rasa NLU 和 Rasa Core 的配置文件 |
credentials.yml | 定义和其他服务连接的一些细节,例如rasa api接口 |
data/nlu.md ‘*’ | Rasa NLU 的训练数据 |
data/stories.md ‘*’ | Rasa stories 数据 |
domain.yml ‘*’ | Rasa domain 文件 |
endpoints.yml | 和外部消息服务对接的 endpoins 细则 |
models/<timestamp>.tar.gz | 初始训练的模型数据 |
- 这些文件的后缀名是yml——一个统一和可扩展的方式,可以用来管理训练数据
- 将训练数据分割到任意数量的yml文件中,每个文件可以包含NLU数据、stories和规则的任意组合
2.2.1NLU训练数据——NLU.yml
Rasa NLU是重要模块之一,负责对用户的消息内容进行语义理解,所以需要提供一份训练数据,然后Rasa会根据这些数据进行模型训练
NLU数据样例
# 默认是3.0
version: "3.0"
nlu:
- intent: greetexamples: |- Hi- Hey!- Hallo- Good day- Good morning- 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 sunny days in Berlin.- intent: check_balanceexamples: |- What's my [credit](account) balance?- What's the balance on my [credit card account]- synonym: creditexamples: |- credit card account- credit account- regex: account_numberexamples: |- \d{10,12}
- 其中以 -开头的行就是用户定义的 intents(意图),examples: |下面是一组有相同意图的消息内容,大致格式就是这样的
- 在这其中可以包括带注释的实体,同义词,正则表达式,查阅表格等,这些都是用来改进意图分类和实体识别的方法。
- 以上提到的方法需要用到组件,组件的使用一般是在domain.yml文件中
2.2.2对话管理文件——stories.yml
stories:
- story: collect restaurant booking info # name of the story steps:- intent: greet # user message with no entities- action: utter_ask_howcanhelp- intent: inform # user message with entitiesentities:- location: "rome"- price: "cheap"- action: utter_on_it # action that the bot should execute- action: utter_ask_cuisine- intent: informentities:- cuisine: "spanish"- action: utter_ask_num_people- story: story with entitiessteps:- intent: account_balance #必需的entities: #可有可无- account_type: credit- action: action_credit_account_balance# 必须的- story: story with a slotsteps:- intent: celebrate_bot# 设置槽- slot_was_set:- feedback_value: positive- action: utter_yay# 检查点的使用,在一个故事的结束,和下一个故事的开始
- 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_flightrules:
- rule: Only say `hey` when the user provided a namecondition:- slot_was_set:- user_provided_name: truesteps:- intent: greet- action: utter_greet
- 故事由以下部分组成:
story
:故事的名称。该名称是任意的,不在训练中使用metadata
:任意和可选,不用于训练,- steps:构成故事的用户消息和操作
steps
,组成——用户的消息,机器人的action,一个表单,设置槽点
- 在用户的消息中,实体虽然不是必需的,但是学习过程会根据意图和实体的组合来预测下一个操作。可以使用
use_entities
属性更改此行为 - action:有两种形式
- 一:Responses:是以utter_开头,发送特定的消息
- 二:Custom actions:是以action_开头,自定义发送任意数量的消息
- slot_was_set——设置槽值键值对的形式,设置槽值不是必须的,如果槽位的值对会话无影响或不重要则可以只插入一个槽名。
- 检查点checkpoint的使用,可以作为故事的开头,可以作为故事的结尾。
2.2.2.1Rules:一般在Stories文件中
Rules非常适合处理小的特定对话模式,但与Stories不同,Rules无法推广到看不见的对话路径,描述了应始终遵循相同路径的简短对话片段。
在开始编写规则之前,必须确保将Rules策略添加到模型配置config.yml中:
policies:
- ... # Other policies
- name: RulePolicy
对话开始的Rules只需要conversation_start: true,仅在开始时生效
rules:- rule: Say `hello` when the user starts a conversation with intent `greet`conversation_start: truesteps:- intent: greet- action: utter_greet
条件满足时才有的适用的规则
rules:- rule: Only say `hello` if the user provided a namecondition:- slot_was_set:- user_provided_name: truesteps:- intent: greet- action: utter_greet
2.2.2domain.yml文件
version: "3.0"intents:- affirm- deny- greet- thankyou- goodbye- search_concerts- search_venues- compare_reviews- bot_challenge- nlu_fallback- how_to_get_startedentities:- nameslots:concerts:type: listinfluence_conversation: falsemappings:- type: customvenues:type: listinfluence_conversation: falsemappings:- type: customlikes_music:type: boolinfluence_conversation: truemappings:- type: customresponses: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.
actions:- action_search_concerts- action_search_venues- action_show_concert_reviews- action_show_venue_reviews- action_set_music_preferencesession_config:session_expiration_time: 60 # value in minutescarry_over_slots_to_new_session: true
domain域定义了您的助手在其中操作,指定机器人应了解的意向、实体、槽位、响应、表单和操作。它还定义会话的配置。
文件内容组件的介绍
-
intents:包含了文件的所有意图,你的对话训练数据,以及nlu中的data
-
entities:实体,可以有忽略以及不用忽略。
-
#这是忽略了所有的实体 intents:- greet:use_entities: []
-
#这是忽略了一部分的实体,被排除的实体不会影响下一轮的预测 intents: - greet:use_entities:- name- first_nameignore_entities:- location- age
-
如果想要的实体不想要影响预测,则可以在slots下加入influence_conversation: false,指定其是否会影响下一轮的预测
-
-
slots:可以说是机器人的记忆,充当键值存储,存储用户提供的信息
-
插槽影响会话的方式将取决于它的插槽类型。槽值类型有text,bool,categorical,float,list,any.
-
此外还可以自定义槽值类型。自定义槽值类型示例
-
# from_entity根据实体来填充槽值entity_name entities: - entity_name slots:slot_name:type: anymappings:- type: from_entityentity: entity_namerole: role_namegroup: group nameintent: intent_namenot_intent: excluded_intent
-
-
Forms:表单——表单的工作原理是提示用户输入信息,直到用户收集了所有必需的信息。信息存储在插槽slots中。填满所有必需的槽位后,机器人将满足用户的原始请求。
-
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
-
-
Actions动作——是机器人执行的操作,可以是响应用户,调用外部的API,查询数据库等,且所有的自定义操作全在domain文件中
-
responses:utter_greet:# 用大括号来表示变量,插入槽值后,将值填入- text: "Hey, {name}. How are you?"
-
-
session_config默认会话配置——下面是默认的配置,表示如果用户在60分钟不活动后发送第一条消息,就会触发一个新的会话,而任何现有的插槽都将被转移到新的会话中。将session_expiration_time的值设置为0意味着会话不会结束。
-
session_config:session_expiration_time: 60 # value in minutes, 0 means infinitely longcarry_over_slots_to_new_session: true # set to false to forget slots between sessions
-
slots:logged_in:type: boolinfluence_conversation: Falsemappings:- type: customname:type: textinfluence_conversation: Falsemappings:- type: custom # 还可以有约束相应的变体 responses: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?"
-
响应可以直接返回给用户,也可以直接在action.py中定义,以Rasa SDK为操作的服务器
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 []
-
包含这种的文件可以有多个,但应在同一目录下,同时训练的时候的命令
rasa train --domain path_to_domain_directory
2.2.3配置文件——config.yml
language: "zh"pipeline:
# 指定语言模型
- name: "MitieNLP"
# 训练模型model: "data/total_word_feature_extractor_zh.dat"
# 分词器,此处的是jieba中文分词器
- name: "JiebaTokenizer"
# 实体的提取
- name: "MitieEntityExtractor"
- name: "EntitySynonymMapper"
# 文本特征化
- name: "RegexFeaturizer"
- name: "MitieFeaturizer"
# 意图分类
- name: "SklearnIntentClassifier"policies:- name: KerasPolicyepochs: 500max_history: 5- name: FallbackPolicyfallback_action_name: 'action_default_fallback'- name: MemoizationPolicymax_history: 5- name: FormPolicy
以上的组件都是可以自己选择的,每个组件都有自己独特的功能,具体用到哪一个组件就看需要哪种功能,都是在写在pipeline下面的
有关配置文件的所有详细的介绍以及使用
2.2.5测试对话管理文件test_stories.yml
stories:
- story: A basic end-to-end teststeps:- user: |heyintent: greet- action: utter_ask_howcanhelp- user: |show me [chinese]{"entity": "cuisine"} restaurantsintent: inform- action: utter_ask_location- user: |in [Paris]{"entity": "location"}intent: inform- action: utter_ask_price
测试文件预训练文件最大的不同就是添加了用户信息,来验证是否是用户想要的
四、对话模式
3.1闲聊以及常见问题
3.1.1更新配置
对于每次提出的相同类型的问题,都希望能以相同的方式回答,这就需要用到Rules,具体用法是在配置文件`config.yml中将下面的内容写入
policies:
# other policies
- name: RulePolicy
之后在配置文件的 NLU 管道中包含 ResponseSelector。ResponseSelector 需要特征化程序和意向分类器才能工作,因此它应该位于管道中的以下组件之后,例如
pipeline:- name: WhitespaceTokenizer- name: RegexFeaturizer- name: LexicalSyntacticFeaturizer- name: CountVectorsFeaturizer- name: CountVectorsFeaturizeranalyzer: char_wbmin_ngram: 1max_ngram: 4- name: DIETClassifierepochs: 100- name: EntitySynonymMapper- name: ResponseSelectorepochs: 100
3.1.2 定义检索意图和响应选择器
单个操作使用 ResponseSelector 的输出为用户请求的特定常见问题解答返回正确的响应。
3.1.3创建Rules
只需要为每个检索意图编写一个规则Rules。然后,将以相同的方式处理在该检索意图下分组的所有意向。操作名称以检索意图的名称开头和结尾。编写响应常见问题解答和闲聊的规则:utter_
rules:- rule: respond to FAQssteps:- intent: faq- action: utter_faq- rule: respond to chitchatsteps:- intent: chitchat- action: utter_chitchat
之后将使用响应选择器的预测来返回实际的响应消息。
3.1.4更新NLU训练数据
ResponseSelector 的 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 sunny days in Berlin.
3.1.5定义响应
响应选择器的响应遵循与检索意图相同的命名约定。
responses:utter_chitchat/ask_name:- image: "https://i.imgur.com/zTvA58i.jpeg"text: Hello, my name is Retrieval Bot.- text: I am called Retrieval Bot!utter_chitchat/ask_weather:- text: Oh, it does look sunny right now in Berlin.image: "https://i.imgur.com/vwv7aHN.png"- text: I am not sure of the whole week but I can see the sun is out today.
3.1.6总结
完成以下操作后,可以训练机器人并试用闲聊对话。
- 将规则策略RulePolicy添加到您的策略,并将响应选择器 ResponseSelector 添加到管道pipeline中
config.yml
- 添加至少一条规则rule以响应常见问题解答/闲聊
- 为您的常见问题解答/闲聊意图添加示例examples
- 为您的常见问题解答/闲聊意图添加回复 responses
- 更新域domain中的意向intents
3.2 处理业务逻辑
会话助手通常支持用户目标,这些目标涉及在为用户执行某些操作之前从用户那里收集所需的信息。例如,餐厅搜索机器人需要收集有关用户偏好的一些信息,以便为他们找到合适的餐厅
3.2.1定义表单
- Slot mappings: 插槽映射
- Responses: 机器人如何请求每条信息
可以通过在表单名称下指定所需槽位的列表来定义domain.yml中的表单,由表单填充的插槽通常不应影响对话
比如订购餐厅的菜人数以及是否想在外面
forms:restaurant_form:required_slots:- cuisine- num_people- outdoor_seating
这些插槽需要添加到domain.yml的插槽部分,以及定义如何填充插槽的插槽映射。对于填充了from_entity的任何槽位,也需要将该实体添加到域中
entities:- cuisine- number
slots:cuisine:type: textmappings:- type: from_entityentity: cuisinenum_people:type: floatmappings:- type: from_entityentity: numberoutdoor_seating:type: boolmappings:- type: from_intentintent: affirmvalue: trueconditions:- active_loop: restaurant_formrequested_slot: outdoor_seating- type: from_intentintent: denyvalue: falseconditions:- active_loop: restaurant_formrequested_slot: outdoor_seating
其中只有当用户回答“你想坐在外面吗?”这个问题时,插槽才应该设置为true或false。
请求插槽
要指定机器人应该如何请求所需的信息,你可以在你的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?"
3.2.2更新配置
表单的Happypath应定义为规则Rules,这意味着您需要将规则策略添加到策略中,与闲聊对话模式的更新配置相同
3.2.3创建规则
Forms本身负责处理要求用户提供所有必需信息的逻辑,因此只需要两个规则Rules来定义表单的Happypath一个定义Forms何时启动,另一个定义填充后会发生什么。对于餐厅搜索示例,在现实生活中,助手会根据用户的偏好查找餐厅。在这种情况下,机器人将发出响应,其中包含将用于搜索的详细信息。
rules:- rule: activate restaurant formsteps:- intent: request_restaurant # 触发激活表单的意图- action: restaurant_form # 激活表单- active_loop: restaurant_form # 表单处于活动状态- rule: submit formcondition:- active_loop: restaurant_form # 条件是表单必须是活动的steps:- action: restaurant_form # 执行表单- active_loop: null # 表单不再活动- action: utter_submit # 表单完成后要执行的操作- action: utter_slots_values # 表单完成后要执行的操作
分离表单的激活和提交好处:如果用户提供了意外的输入或通过聊天中断了表单,Rules仍然适用
3.2.4更新NLU训练数据
就是为意图添加示例,同闲聊的对话模式,nlu.yml文件
nlu:
- intent: request_restaurantexamples: |- 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)
如果用户在第一条消息中提供实体,则该槽将在表单开头填充,并且机器人就不会通过再次向他们询问美食来填充槽。根据真实的场景来添加实例数据
nlu:
- intent: affirmexamples: |- Yes- yes, please- yup
- intent: denyexamples: |- no don't- no- no I don't want that- intent: informexamples: |- [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
一定要记得在nlu.yml文件中出现的意图都要写在domain.yml文件中
以下是更新之后的domain.yml文件
intents:- request_restaurant- affirm- deny- inform
3.2.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}"
3.2.6总结
表单可以简化收集用户信息的逻辑。要定义一个最小的表单(如上面的餐厅搜索示例),以下是您需要执行的操作的摘要:
- 将规则rules策略比如RulesPolicy添加到
config.yml
- 在域domain.yml中定义具有所需槽slots的表单forms
- 为域domain.yml中所有必需的槽slots添加槽映射
- 添加用于激活和提交表单forms的规则rules
- 为激活表单的意图添加示例,examples
- 为意图添加示例以填充所需槽slots
- 定义机器人在表单填写时要执行的操作或响应action or response
- 使用您定义的新意图和操作更新您的域domain.yml
3.3其他对话模式
除以上两种对话模式外,还有以下四种对话模式,具体模式的文件配置以及要注意的地方都在下面的网址上面,四种对话模式的配置,操作都是大同小异,感兴趣的可以去了解一下。
- 处理意外输入
- 情景对话
- 联系用户
- 回退和人工交接
五、总结
- rasa训练的命令在这里