Rasa Core & Rasa X 详解
- Rasa Core
- Rasa X
Rasa Action Server
Rasa Core
https://jiangdg.blog.csdn.net/article/details/105434136
Rasa框架提供的对话管理模块,即Dialog Management(DM)
它控制着人机对话的过程,是人机对话系统的重要组成部分。DM会根据NLU模块输出的语义表示执行对话状态的更新和追踪,并根据一定策略选择相应的候选动作。在对话过程中不断根据当前状态决定下一步应该采取的最优动作(如:提供结果,询问特定限制条件,澄清或确认需求等)
DM有两个任务:
- 对话状态维护(dialog state tracking, DST)
对话状态是指记录了哪些槽位已经被填充、下一步该做什幺、填充什幺槽位,还是进行何种操作。用数学形式表达为,t+1 时刻的对话状态S(t+1),依赖于之前时刻 t 的状态St,和之前时刻 t 的系统行为At,以及当前时刻 t+1 对应的用户行为O(t+1)。可以写成S(t+1)←St+At+O(t+1)。
- 生成系统决策(dialog policy)
根据 DST 中的对话状态(DS),产生系统行为(dialog act),决定下一步做什幺 dialog act 可以表示观测到的用户输入(用户输入 -> DA,就是 NLU 的过程),以及系统的反馈行为(DA -> 系统反馈,就是 NLG 的过程)
对于1,Rasa实现很简单,就是简单地基于策略的槽状态替换。
对于2,Rasa使用基于LSTM的排序学习,大体上是将当前轮用户意图、上一轮系统行为、当前槽值状态向量化,然后与所有系统行为做相似度学习,以此决定当前轮次的一个或多个系统行为
Action
一、动机
当Rasa NLU识别到用户输入Message的意图后,Rasa Core对话管理模块将如何对其作出回应呢?
答案:action
二、action 有哪些类别?
- default actions
- utter actions
- custom actions
2.1 default actions
- 介绍:Rasa Core默认的一组actions,我们无需定义它们,直接可以story和domain中使用;
- 类别:
- action_listen:监听action,Rasa Core在会话过程中通常会自动调用该action;
- action_restart:重置状态,比初始化Slots(插槽)的值等;
- action_default_fallback:当Rasa Core得到的置信度低于设置的阈值时,默认执行该action;
2.2 utter actions
- 介绍:以utter_为开头,仅仅用于向用户发送一条消息作为反馈的一类actions;
- 定义:只需要在domain.yml文件中的actions:字段定义以utter_为开头的action即可,而具体回复内容将被定义在templates:部分;
1 |
|
2.3 custom actions
即自定义action,允许开发者执行任何操作并反馈给用户,比如简单的返回一串字符串,或者控制家电、检查银行账户余额等等;
三、自定义动作是如何工作
当您的助手预测自定义动作时,Rasa服务器将POST
使用json有效负载向动作服务器发送请求,其中包括预测动作的名称,对话ID,跟踪器的内容和域的内容。
当动作服务器完成自定义动作的运行时,它将返回响应和事件的json。然后,Rasa服务器将响应返回给用户,并将事件添加到会话跟踪器。
3.1 编写自定义Action
Action Class
为任何自定义操作的基类。要定义自定义动作,请创建Action
该类的子类并覆盖两个必需的方法name
和run
。当动作服务器name
收到运行动作的请求时,它将根据其方法的返回值调用动作。
骨架自定义操作如下所示:
1 |
|
Action.name() 定义动作的名称。该方法返回的名称是您的机器人域中使用的名称。
Action.run() 参数解释:
dispatcher –用于将消息发送回用户的调度程序。
- utter_message() 方法可用于将任何类型的响应返回给用户
1
2
3
4
5
6
7
8
9dispatcher.utter_message(text = "Hey there")
dispatcher.utter_message(image = "")
dispatcher.utter_message(json_message = {...})
dispatcher.utter_message(template = "utter_greet")
dispatcher.utter_message(template = "utter_greet_name", name = "Aimee")
dispatcher.utter_messsage(buttons = [
{"payload": "/affirm", "title": "Yes"},
{"payload": "/deny", "title": "No"},
]tracker –当前用户的状态跟踪器。可以通过
Tracker
属性和方法获取有关过去事件和会话当前状态的信息,如:访问插槽值tracker.get_slot(slot_name)
,最新的用户消息是tracker.latest_message.text
以及任何其他rasa_sdk.Tracker
属性。具体请参阅跟踪器的文档。domain–机器人的域
3.2 Running a Rasa SDK Action Server
1 |
|
FormAction
一、动机
在 Rasa Core 中,有时,我们需要执行 一个 Action 并 填充 多个 slots 时(eg:用户询问 天气时,Bot 需要知道 用户 想 查询的 是 哪一天(date-time),哪个地方(address),才能做出 正确 的 反馈),这个时候,需要怎么办么?
答案:采用 FormAction 实现。
二、为什么 可以 采用 FormAction 实现呢?
FormAction会遍历监管的所有slot,当发现相关的slot未被填充时,就会向用户主动发起询问,直到所有slot被填充完毕,才会执行接下来的业务逻辑。
三、FormAction 的 工作流程
- 用户 输入 query;
- FormAction 遍历监控所有 slots;
- while 所有 slots 都被 填充?
- 发现 相关 slot 未被 填充时,主动 向 用户 发起 询问;
- 所有 slots 填充 完毕;
- 继续执行下一步 业务逻辑;
三、FormAction 怎么构建?
3.1 构建 story
- 注意:在 story 中,不仅需要考虑用户按照我们的设计准确的提供有效信息,而且还要考虑用户在中间过程改变要执行的意图情况或称输入无效信息,因为对于FormAction来说,如果无法获得预期的信息就会报错;
- 两种情况:
- 情况一 happy path:
- 情况二 unhappy path:
- 实例:
1 |
|
注:
- “* request_weather” : 意图
- “- weather_form” :form action,可以理解为 Core 针对意图 request_weather 所执行的 动作 Action;
- “- form{“name”: “weather_form”}” : 激活 form (这个 name 对应 action.py 中 Class WeatherForm 的 函数 name() 的返回值);
- “- action_deactivate_form”:默认 的 action,作用是用户可能在表单操作过程中改变主意,决定不继续最初的请求,我们使用这个default action来禁止(取消)表单,同时重置要请求的所有slots;
3.2 在 定义域 domain.yml 中添加 form 字段
- 动机:定义域 domain.yml 类似于 配置文件,该文件中 配置 该项目 所需要 的 intents、slots、entities、actions、forms、responses;
- 目标:配置 form
1 |
|
3.3 配置 FormPolicy 策略模块
- 动机:前面 【为什么可以采用 FormAction 实现呢?】说了,FormAction 可以 持续 向用户 询问 未 填充 的 slot 的信息。那么,是什么 方法 使他具有该功能呢?
- 原因:主要 是 有 FormPolicy 方法
- 介绍:FormPolicy是MemoizationPolicy的扩展,用于处理(form)表单的填充事项;
- 思路:当一个FormAction被调用时,FormPolicy将持续预测表单动作,直到表单中的所有槽都被填满,然后再执行对应的FormAction;
- 如何 使用 FormActions ?
- 在 config.yml 配置文件中配置
1 |
|
3.4 实现 WeatherForm 动作 Action
- 动机:看完上面内容,你是否有以下疑问:
- 意图 request_weather 怎么知道要执行哪些 动作 Action 呢?
- FormPolicy 策略模块 怎么 知道 WeatherForm 需要 哪些 槽位呢?
- 答案:需要在 action.py 文件中 定义 WeatherForm 的相关 Action
- 样例代码:
1 |
|
代码解析:
- name():定义 Action 名称;
- required_slots(tracker: Tracker):定义 需要 填充 slots;
- submit():执行函数,当 所有 槽位 填充完,通过该函数 进行 responses;
流程解析:
当form action第一被调用时,form就会被激活并进入FormPolicy策略模式;
每次执行form action,required_slots会被调用,当发现某个还未被填充时,会主动去调用形式为uter_ask_{slotname}的模板(注:定义在domain.yml的templates字段中);
当所有slot被填充完毕,submit方法就会被调用,此时本次form操作完毕被取消激活;
Stories
二、动机
在对话管理(DM)中需要通过学习 获取到 必要的知识。那么,DM 的 训练数据从何而来?训练数据的格式是怎么样的?
答案: Stories
三、什么是 Stories?
- 介绍:Rasa 采用 Stories 作为一种训练 DM 模型的数据格式;
- 存放地址:该训练数据存放在 story.md 文件中。
- 说明:Stories 是用户和人工智能助手之间的对话的表示,转换为特定的格式,其中用户输入表示为相应的意图(和必要的实体),而助手的响应表示为相应的操作名称。
- 该数据的格式如下所示:
1 |
|
四、Stories 主要分哪些部分呢?
4.1 用户输入 (User Messages)
- “xx”:”yy” 对应的信息 为 用户输入消息,采用 NLU 管道输出的 intent 和 entities 来表示可能的输入,policies 根据 intent 和 entities 预测下一步 action;
- 类别:
- “* greet”:用户输入无 entity 的场景;
- “* inform{“people”: “six”}”:用户输入包含 entity 的场景,响应这一类 intent 为 普通 action;
- “* request_weather”:用户输入Message对应的intent为form action情况;
4.2 动作 (Action)
- “-”:要执行动作(Action);
- 分类:
- utterance actions:在domain.yaml中定义以utter_为前缀,比如名为greet的意图,它的回复应为utter_greet;
- custom actions:自定义动作,具体逻辑由我们自己实现,虽然在定义action名称的时候没有限制,但是还是建议以action_为前缀,比如名为inform的意图fetch_profile的意图,它的response可为action_fetch_profile;
4.3 事件(Action)
- “-”:要执行事件(Action);
- 分类:
- 槽值设置(SlotSet):
- 激活/注销表单(Form):
4.3.1 Slot Events
- 作用:当我们在自定义Action中设置了某个槽值,那么我们就需要在Story中Action执行之后显著的将这个SlotSet事件标注出来,格式为- slot{“slot_name”: “value”}。
- 举例:我们在action_fetch_profile中设置了Slot名为account_type的值,代码如下:
1 |
|
注:需要在Story中执行action_fetch_profile之后,添加- slot{“account_type” : “premium”}。
1 |
|
如果您的自定义Action中将槽值重置为None,则对应的事件为-slot{“slot_name”: null}
4.3.2 Form Events
- 三种形式的表单事件(Form Events):
- Form Action事件:
- 介绍:表单动作事件,是自定义Action的一种,用于一个表单操作
- “- restaurant_form”
- Form activation事件:
- 介绍:激活表单事件,当form action事件执行后,会立马执行该事件
- “- form{“name”: “restaurant_form”}”
- Form deactivation事件:
- 介绍:注销表单事件,作用与form activation相反
- “- form{“name”: null}”
- Form Action事件:
1 |
|
总之,我们在构建Story时,可以说是多种多样的,因为设计的故事情节是多种多样的,这就意味着上述三种内容的组合也是非常灵活的。另外,在设计Story时Rasa还提供了Checkpoints 和OR statements两种功能,来提升构建Story的灵活度,但是需要注意的是,东西虽好,但是不要太贪了,过多的使用不仅增加了复杂度,同时也会拖慢训练的速度。
Domain
Domain,描述了对话机器人应知道的所有信息
类似于“人的大脑”,存储了意图intents、实体entities、插槽slots、动作actions、响应、表单等信息。domain.yml文件组成结构如下:
intents
意图的定义是在NLU样本中实现的,并且在每个意图下面我们需要枚举尽可多的样本用于训练,以达到Bot能够准确识别出我们输入的一句话到底想要干什幺
session_config
即会话配置,这部分的作用为配置一次会话(conversation session)是否有超时限制
slots
即插槽,它就像对话机器人的内存,它通过键值对的形式可用来收集存储用户输入的信息(实体)或者查询数据库的数据
entities
即实体,类似于输入文本中的关键字,需要在NLU样本中进行标注,然后Bot进行实体识别,并将其填充到Slot槽中,便于后续进行相关的业务操作
actions
当Rasa NLU识别到用户输入Message的意图后,Rasa Core对话管理模块就会对其作出回应,而完成这个回应的模块就是action
1
2
3
4actions:
– utter_answer_affirm
– utter_answer_deny
– utter_answer_greetforms
即表单,该部分列举了在NLU样本中自定义了哪些表单动作 (Form Actions)
1
2forms:
- weather_formresponses
描述UtterActions具体的回复内容,并且每个UtterAction下可以定义多条信息,当用户发起一个意图,比如 “你好!”,就触发utter_answer_greet操作,Rasa Core会从该action的模板中自动选择其中的一条信息作为结果反馈给用户。除此之外,还可以在训练数据中存储Responses;或者自定义一个NLG服务来生成Responses。
1
2
3
4
5
6
7responses:
utter_answer_greet:
- text: "您好!请问我可以帮到您吗?"
- text: "您好!很高兴为您服务。请说出您要查询的功能?"
utter_ask_date_time:
- text: "请问您要查询哪一天的天气?"
Slots
Slots
Slots Type
- Text:文本
- Boolean:布尔型
- Categorical:多个值中的一个
- Float:浮点数
- List:
- Unfeaturized:不影响对话的数据
slots 填充方式
- 通过initial_value字段为当前slot提供一个初始值
- Slots Set from NLU
\* greet{“name”: “Ali”}
- Slots Set By Clicking Buttons
- Slots Set by Actions:在Custom Action中通过返回事件来填充Slots的值
Slots值的两种获取方式
Get Slot in responses
在domain.yaml的responses部分,可以通过{slotname}的形式获取槽值
1
2
3
4responses:
utter_greet:
– text: “Hey, {name}. How are you?”Get Slot in Custom Action
通过Tracker,能够轻松获取整个对话信息,其中就包括Slot的值
1
2
3
4
5
6
7
8
9
10
11from rasa_sdk.actions import Action
from rasa_sdk.events import SlotSet
import requests
class FetchProfileAction(Action):
def name(self):
return “fetch_profile”
def run(self, dispatcher, tracker, domain):
# 获取slot account_type的值
account_type = tracker.get_slot(‘account_type’)
return []
Policies
二、动机
在对话管理(DM)需要根据 用户输入 作出 相应的响应,该过程就需要 制定合适 的策略。
答案: Policies
三、Policies 是什么?
介绍:Policies 是 Rasa Core中的策略模块;
对应类:rasa_core.policies.Policy;
作用:使用合适的策略(Policy)来预测一次对话后要执行的行为(Actions);
预测原理:衡量命中的哪些Policies哪个置信度高,由置信度高的Policy选择合适的Action执行。假如出现不同的Policy拥有相同的置信度,那么就由它们的优先级决定,即选择优先级高的Policy;
Rasa对提供的Policies进行了优先级排序,具体如下表:
四、Policies 的 策略模块的作用?
4.1 Memoization Policy
- 作用:只记住(memorizes)训练数据中的对话。如果训练数据中存在这样的对话,那么它将以置信度为1.0预测下一个动作,否则将预测为None,此时置信度为0.0;
- 如何在策略配置文件config.yml文件中,配置MemoizationPlicy策略,其中,max_history(超参数)决定了模型查看多少个对话历史以决定下一个执行的action;
1 |
|
注:max_history值越大训练得到的模型就越大并且训练时间会变长,关于该值到底该设置多少,我们可以举这么个例子,比如有这么一个Intent:out_of_scope来描述用户输入的消息off-topic(离题),当用户连续三次触发out_of_scope意图,这时候我们就需要主动告知用户需要向其提供帮助,如果要Rasa Core能够学习这种模型,max_history应该至少为3。story.md中表现如下:
1 |
|
4.2 Keras Policy
- 作用:Keras框架中实现的神经网络来预测选择执行下一个action;
- 默认的框架:使用LSTM(Long Short-Term Memory,长短期记忆网络)算法,但是我们也可以重写KerasPolicy.model_architecture函数来实现自己的框架(architecture)。KerasPolicy的模型很简单,只是单一的LSTM+Dense+softmax,这就需要我们不断地完善自己的story来把各种情况下的story进行补充;
- 如何在策略配置文件config.yml文件中,配置KerasPolicy策略,其中,epochs表示训练的次数,max_history同上:
1 |
|
4.3 Embedding Policy
- 动机:基于机器学习的对话管理能够学习复杂的行为以完成任务,但是将其功能扩展到新领域并不简单,尤其是不同策略处理不合作用户行为的能力,以及在学习新任务(如预订酒店)时,如何将完成一项任务(如餐厅预订)重新应用于该任务时的情况;
作用:循环嵌入式对话策略(Recurrent Embedding Dialogue Policy,REDP),它通过将actions和对话状态嵌入到相同的向量空间(vector space)能够获得较好的效果,REDP包含一个基于改进的Neural Turing Machine的记忆组件和注意机制,在该任务上显著优于基线LSTM分类器;
配置EmbeddingPolicy参数:
1 |
|
4.4 Form Policy
作用:MemoizationPolicy的扩展,用于处理(form)表单的填充事项。当一个FormAction被调用时,FormPolicy将持续预测表单动作,直到表单中的所有槽都被填满,然后再执行对应的FormAction;
使用:需要实现FormAction,在
domain.yml
中指定,在stories.md
中使用当一个FormAction被调用时,FormPolicy将持续预测表单动作,直到表单中的所有槽都被填满,然后再执行对应的FormAction。
1 |
|
1 |
|
4.5 Mapping Policy
- 作用:M可用于直接将意图映射到要执行的action,从而实现被映射的action总会被执行,其中,这种映射是通过triggers属性实现的;
- 使用:无视之前对话,一旦触发意图就操作;映射是传递intent属性给
triggers
实现的,修改domain.yml
1 |
|
注:greet是意图;utter_goodbye是action。
一个意图最多只能映射到一个action,我们的机器人一旦收到映射意图的消息,它将执行对应的action。然后,继续监听下一条message。需要注意的是,对于上述映射,我们还需要要在story.md文件中添加如下样本,否则,任何机器学习策略都可能被预测的action_greet在dialouge历史中突然出现而混淆
4.6 Fallback Policy
- 作用:如果意图识别的置信度低于nlu_threshold,或者没有任何对话策略预测的action置信度高于core_threshold,FallbackPolicy将执行fallback action。通俗来说,就是我们的对话机器人意图识别和action预测的置信度没有满足对应的阈值,该策略将使机器人执行指定的默认action;
- 使用:例如用户问了让机器人理解不了的东西时需要回退
1 |
|
注:其中,action_default_fallback是Rasa Core中的一个默认操作,它将向用户发送utter_default模板消息,因此我们需要确保在domain.yml文件中指定此模板;
- 自定义使用:在fallback_action_name字段自定义默认回复的action,比如my_fallback_cation,就可以这么改:
1 |
|
Interactive Learning
虽然我们可以容易的人工构建story样本数据,但是往往会出现一些考虑不全,甚至出错等问题,基于此,Rasa Core框架为我们提供了一种交互式学习(Interactive Learning)来获得所需的样本数据。
- 开启Action Server
1 |
|
- 开启Interactive Learning
1 |
|
分别执行(1)、(2)命令后,我们可以预设一个交互场景根据终端的提示操作即可。如果一个交互场景所有流程执行完毕,按Ctrl+C结束并选择Start Fresh进入下一个场景即可。当然Rasa还提供了可视化界面,以帮助你了解每个Story样本构建的过程,网址:http://localhost:5005/visualization.html。
Rasa X
layers on top of Rasa Open Source and helps you build a better assistant
is a free, closed source tool available to all developers
- can be deployed anywhere, so your training data stays secure and proprietary
Rasa X可以以本地模式安装,也可以使用Kubernetes / Openshift或Docker Compose安装在服务器上。请考虑以下哪种描述最能描述您的情况,并相应地选择一种安装方法。
本地模式
如果以下任何一种描述您的用例,则最好的方法是:
- 您正在开发自己的Rasa助手,并希望在用户界面中与其聊天并与他人共享
- 您是第一次浏览Rasa X,只想了解它在本地的工作方式
在以下情况下,您将需要使用其他安装选项之一:
- 您已经准备好部署助手并将其提供给最终用户
服务器快速安装
这是在服务器或群集上安装Rasa X的最简单,最快的方法。如果您不确定选择哪种方法,请尝试这种方法。
如果以下任何一种描述您的用例,则最好的方法是:
- 您正在安装要在生产中使用的Rasa X,并且不需要太多自定义
- 您是第一次浏览Rasa X,并想了解它在服务器上的工作方式
在以下情况下,您将需要使用其他服务器安装选项之一:
Docker撰写
如果满足以下条件,则使用Docker Compose在服务器上安装Rasa X是一个不错的选择:
- 您不能或不想使用Kubernetes / Openshift
- 您需要比快速安装脚本提供的更多自定义设置
- 您不会期望大量的用户流量(即数百个并发用户)
安装脚本可用于满足硬件和操作系统要求的服务器 。对于其他操作系统,您可以通过Docker Compose手动安装RasaX。
注意❤❤❤
启动 rasa x
的过程中,windows下可能会遇到如下问题
1 |
|
解决:win10下需保证所有 XXX.yml 等配置文件不包含中文,或者是修改rasa\shared\utils\io.py代码:
1 |
|
遇到的坑
- 训练数据JSON格式实体entity为中文,报错
UnicodeEncodeError: 'ascii' codec can't encode characters
,entity命名应使用英文 - 根目录不要有文件
test.py
,启动API服务时会运行该文件,可能会报错 - 项目名不要带中文,启动Rasa X时可能报错
- YAML文件涉及字符串最好用
"
包围起来,特别为了调用Rasa API时。如- payload: "/inform{\"gender\": \"男\"}"
- 一个Form激活时输入了无关数据报错
Failed to extract slot xxx with action xxx_form
,可在Stories中添加action_deactivate_form
停止
参考
400 多行代码!超详细 Rasa 中文聊天机器人开发指南
https://flashgene.com/archives/110272.html
Rasa中文聊天机器人开发指南
https://jiangdg.blog.csdn.net/article/details/104328946
Rasa入门——AI助手和聊天机器人