基于RASA的task-orient对话系统解析(二)——对话管理核心模块

2019 年 9 月 2 日 AINLP

作者:邱震宇(华泰证券股份有限公司 算法工程师)

知乎专栏:我的ai之路

本文为授权转载,原文链接,点击"阅读原文"直达:

https://zhuanlan.zhihu.com/p/78665885




本文是rasa对话系统解析系列的第二篇。在上一篇文章中,我对rasa的整体架构进行了解析,包括代码结构,模块组成等,同时也对NLU模块进行了详细的解析。本文聚焦于rasa的核心模块——对话管理,通过阅读本文,可以清晰得了解rasa是如何根据用户的不同问话,按照某些策略执行不同的动作,并给出回应,最终通过多轮对话,完成用户的某个任务型服务需求

本文将首先对对话管理模块rasa_core做代码结构上的解析,然后以对话管理模块为主视角解析单轮对话的完整流程,最后将分别解析rasa_core中的重要模块以及重要的术语。

rasa_core代码结构

首先,看一下rasa_core的代码结构:



除去core根路径下的一些公共资源和入口方法外,可以看出rasa_core根据包名大概分成以下几个部分:

  • actions,该包下面主要存放的是action具体的实现类。关于action的具体定义和描述在后面会有详细讲解,简单说就是chatbot执行的一些动作。

  • channels,该包下面主要存放的是rasa与前端平台进行对接的接口。因为rasa本身只提供对话系统的功能服务,具体还需要与用户在前端界面进行交互,这个包里定义了不同的接口和不同平台进行对接。例如,console.py,定义了最简单的直接在shell命令行中进行对话交互的接口。

  • events,这个是rasa中定义的chatbot能执行的最小粒度的动作。与action有一些关系,我们可以通过action调用不同的events来实现不同的操作。events的实例有“SlotSet”(槽位填充),"Restarted"(重启对话,将所有状态重置)等等。

  • nlg,rasa的response生成模块,即生产chatbot返回给用户的消息。目前,rasa支持通过模板生成话术,也支持通过machine learning的方式做NLG。nlg模块中定义了方法读取domain.yml中的预定义的话术模板,然后生成具体的消息。

  • policies,此模块是rasa_core最上层的对话管理控制模块。该包中,定义了不同类型的对话管理策略,rasa将依据这些策略,执行不同actions,完成多轮对话任务。这些策略包括人工规则策略如form_policy,memoization等,也包括通过机器学习、深度学习进行训练得到策略模型,如sklearn_policy,keras_policy等。

  • schemas,这里主要放置rasa_core的配置文件domian.yml,这个配置文件主要配置槽位定义,实体定义,话术模板,使用的actions的名称定义以及其他系统配置。开发者在开发自己的对话系统时,需要自定义这个配置文件来覆盖源码中预定义的配置。

  • training,这里主要存放的是如何将准备的数据转化为对话系统可训练的转化方法以及可视化方法。

根路径上也有很多重要的类文件,这里就不全部拿出来说了,挑几个重点的说一下。

  • agent,这是rasa_core专门设计的一个接口,可以将其视作bot主体,主要作用是封装和调用rasa中最重要的一些功能方法,包括上述提到的几个包里的功能模块。

  • featurizers: 这个文件主要是定义了一些方法将对话数据特征化,目的是为了将对话数据用于机器学习的训练。

  • interpreter: 这个方法是rasa_core与rasa_nlu的一个纽带,rasa管理模块通过定义interpreter类方法,调用rasa_nlu中的parser方法来对用户的发送到bot的消息文本进行实体抽取、意图识别等操作。

  • processor:定义了MessageProcess类,供agent调用,功能是有序得调用不同对话功能组件,例如调用interpreter解析用户文本、调用本轮对话的action完成一些操作、根据policy得到下一步的action、记录对话状态等。

  • trackers:这个也是rasa中比较重要的一个对象,它的作用是rasa对话系统中的状态记录器,每一轮对话中,对话的状态信息都会进行更新并保存在这个对象中。例如当前已填充的槽位、用户最后一次发送的文本、当前用户的意图等等。

rasa对话管理模块流程(以rasa_core为主视角)

上一篇文章中,已经给出了rasa的整体流程图,如图:


rasa整体流程


这次,我们以rasa_core为主视角,将这个图重新解析一遍,着重描述rasa_core在对话系统中的功能与作用。



根据上图,可以看出,rasa_core整体的对话管理流程还是非常清晰有逻辑的,下面分别对其中比较重要的模块术语进行解析。

InputChannel和OutputChannel

OutputChannel封装了chatbot需要返回给用户的信息,需要注意,chatbot返回的消息不一定是纯文本,还可能是html,json,文件附件等等,因此需要OutputChannel这个统一接口进行封装处理,因此chatbot可以支持让用户进行点选功能(当然,前提是前端界面支持点选的适配),关于如何实现用户点选功能后续会单独开一个功能小讲。

InputChannel主要负责将用户输入连同用户的身份信息封装成UserMessage对象,方便后面的Processor处理。对应的,如果在上一轮对话中,OutputChannel是点选或者其他非单纯文本输出,那么本轮对话中的InputChannel也需要接受用户点选或者其他非单纯文本的输入,封装成最终的UserMessage。

UserMessage

关于UserMessage对象,上一篇文章中已经有过介绍,这里给出其具体的成员变量封装情况:



可以看到作为贯穿整个rasa_core处理流程的用户消息对象,它的成员结构还是比较清晰的,包括了用户发送的文本,定义的OutputChannel类型,用户的id,parse_data(主要存放用户自己定义的实体键值对,开发调试用),inputChannel类型,以及message的id。

policy

对话管理策略是多轮对话系统的核心功能,相当于对话系统的大脑,它负责根据当前用户的反馈,告诉Processor当前轮对话中需要采取的后续action,以及如何更新对话状态信息等。rasa支持人工规则的策略,也支持机器学习、深度学习得到的数据驱动策略。

以Form_policy为例,这个策略是一种表单策略,对应的rasa预置了一种类型的action,叫form的action。这种action会将所有槽位作为表单的属性column,每一轮对话,都会去主动询问用户,引导用户将这些表单的属性填充,直到所有属性填充完成。而form_policy的核心就是检索当前是否配置了form类型的action,如果是,则将下一步的action置为form。有关action的描述将在后面详细给出。可以看出这是一个典型的人工规则策略。

在一次对话任务中,可以使用多个policy的组合来帮助bot完成既定的任务。比如策略A是一个使用深度学习训练得到的一个策略模型,但是一般使用data-driven得到的模型不会达到100%的准确率,总会有bad case的情况,此时如果只是用该策略,那么会话极有可能会陷入到bad case中,因此需要一个兜底的策略在策略A的bad case发生时,让对话能够平稳进行下去。rasa就预置了这样一个策略,叫fall_back,将fall_back与策略A进行组合,就能得到一个更加鲁棒的一个对话策略。

在实际项目生产中,如果在项目初期,领域数据比较少的情况下,通常会选择form policy或者其他规则型策略。当产品上线,在积累到一定的数据后,可以使用一些data-driven的模型来做策略。

domain

这个对象的数据来自于前述章节提到的配置文件domain.yml。该对象定义不同的方法,从配置文件domain.yml读取槽位模板,话术模板,定义的action名称,自定义的policy名称等信息,并封装到domain对象中。domain对象可以在action执行时为其提供槽位信息以及话术模板等字段。

设计domain的好处在哪儿呢?

个人认为主要是方便管理对话系统需要使用的模板信息。这里的模板信息包含定义的槽位,意图、实体、话术模板、自定义action、自定义policy。如果需要添加或者修改这些信息,只需要修改domain.yml里面的信息就可以了,不需要去修改任何代码,让配置和代码解耦。

列举一个本人在做项目时的一个domain使用实例。做对话系统的对话记录保存时,需要保存每一轮对话中chatbot发送给用户的信息。但是因为很多bot message都是读取的domain.yml中的话术模板再配置参数动态生成的。因此可以直接使用Domain的load方法读取yml中的键值对,生成一个字典。然后可以从字典中读取相应的话术模板得到bot message。

CollectionDispatcher

这个对象的主要作用是设计了各种魔法函数,处理不同类型的bot输出,并将其输出到OutputChannel中。看一下它的成员方法就能知道它的作用:



根据方法名就能知道不同方法的作用,例如utter_message,接受text字符串参数,可以直接输出我们定义的文本。utter_template则是从domain中的话术模板读取相应的template,**kwargs表示如果话术模板中预留了参数槽位,则使用该参数进行填充,生成最终的bot message。

Processor

这个对象是对话系统的核心处理模块。它通过execute_action完成bot处理对话的流程。

这里需要注意一点,在processor执行action之前,agent将会调用processor的log_message方法,使用nlu_interpreter来对用户发送的文本做实体识别和意图识别,然后将信息保存在tracker中,这个逻辑比较简单,nlu模块也在前一篇文章中详细解析过了,因此这里就不详细展开了。

execute_action方法核心内容如下:



可以看到,该模块涉及的核心对象有两个,action和tracker(当然还有其他对象如OutputChannel,policy等)。下面分别解析这两个对象。

DialogueStateTracker

从名字上就可以看到这个对象的功能:在多轮对话过程中全程记录对话状态信息。这个对象在开发自己的对话系统时,作用可是非常大的。很多对话状态信息,都可以从它这里得到。当然, 我们并不能直接去读写其定义的成员变量信息,需要通过其成员方法来操作成员变量,例如current_sate(),其核心内容如下:



注意该方法的返回对象是一个字典,其包含了丰富的对话信息,例如用户的id、当前所有的槽位键值对(包括已填充和未被填充的)、用户最近一次发送的消息等等。

有关于tracker的用法,将在以后的系列文章中结合实例详细给出。

Action

下面将解析对话管理中最重要的一个概念——Action。前面已经说到,event对象是rasa中定义的chatbot能执行的最小粒度的动作。而Action则是比event更高层次的对象,会根据用户发送过来的消息,执行一些操作,这些操作可以是自定义的一些逻辑,也可以是系统预置的events。rasa中,action可以分为三大类:

utterance actions:直接发送文本给用户,action文本模板是在domain.yml中进行定义。

custom actions: 自定义action,由开发者自定义功能的action。个人认为这个是功能最强大的action,因为开发自由度很大,支持使用任何开发语言进行开发。最后只需要将其打包成一个restful服务接口暴露出来即可。因此这种action是可以和对话主系统分离部署的。下面给出自定义action server与bot agent和用户的交互流程图:



rasa action支持node.js, .NET, java等开发语言,当然也支持Python。但是对于Python来说,需要安装rasa-sdk工具包。这个工具包里预置了一些有用的action模板。例如form action。前面章节已经对该action有过描述,这里就不赘述了。

当然,form action以及其他预置的action模板只能实现最简单的场景,如果要实现复杂的场景,需要根据不同场景,自定义action,可以选择继承这些模板,在上面进行功能的添加和完善。有关于form action的具体使用后续会专门在实例讲解时解析。

default action: rasa系统内置的粒度较小的action。与rasa_sdk中的action不同,这个是直接在rasa_core/actions下面的。相对于上面的form action来说,这里的action功能更单一,与events比较像,但是还是略有不同,下面举个实例ActionRestart:



可以看到它使用了一个Restarted()的event,这个event的功能是重启整个对话流程,重置对话状态。除此之外,该action需要先执行读取话术模板组装bot message,并将其发送给用户后,才去重启整个会话。

所有default action的列表如下,它们的命名都非常简单直接:



小结

本文主要解析了rasa_core的核心功能,以rasa_core为主视角,重新解析了rasa管理多轮对话的主要流程。同时,本文从代码和功能流程架构上分别对该模块进行了解析,尤其是对多轮对话系统中涉及到的重要概念术语都进行了详细的剖析。后续文章将以rasa的部署和启动为视角,讲解其如何将不同的组件整合在一起并运行起来。另外,也会以某个对话场景为实例,详细得介绍如何使用利用rasa来构建一个相对复杂的任务型对话系统。

相关文章:

基于RASA的task-orient对话系统解析(一)

Rasa介绍:对话系统、产品与技术

登录查看更多
4

相关内容

【SIGIR 2020】 基于协同注意力机制的知识增强推荐模型
专知会员服务
90+阅读 · 2020年7月23日
【论文推荐】文本摘要简述
专知会员服务
69+阅读 · 2020年7月20日
【阿里技术干货】知识结构化在阿里小蜜中的应用
专知会员服务
98+阅读 · 2019年12月14日
[综述]基于深度学习的开放领域对话系统研究综述
专知会员服务
80+阅读 · 2019年10月12日
基于RASA的task-orient对话系统解析(一)
AINLP
16+阅读 · 2019年8月27日
Rasa介绍:对话系统、产品与技术
AINLP
7+阅读 · 2019年8月20日
NLP实践:对话系统技术原理和应用
AI100
34+阅读 · 2019年3月20日
【小夕精选】多轮对话之对话管理(Dialog Management)
夕小瑶的卖萌屋
27+阅读 · 2018年10月14日
干货篇|百度UNIT对话系统核心技术解析
InfoQ
23+阅读 · 2018年9月20日
多轮对话之对话管理:Dialog Management
PaperWeekly
18+阅读 · 2018年1月15日
Arxiv
5+阅读 · 2019年10月11日
A Sketch-Based System for Semantic Parsing
Arxiv
4+阅读 · 2019年9月12日
Arxiv
11+阅读 · 2019年4月15日
Arxiv
3+阅读 · 2018年12月21日
Physical Primitive Decomposition
Arxiv
4+阅读 · 2018年9月13日
Arxiv
8+阅读 · 2018年5月1日
Arxiv
5+阅读 · 2018年5月1日
VIP会员
相关VIP内容
【SIGIR 2020】 基于协同注意力机制的知识增强推荐模型
专知会员服务
90+阅读 · 2020年7月23日
【论文推荐】文本摘要简述
专知会员服务
69+阅读 · 2020年7月20日
【阿里技术干货】知识结构化在阿里小蜜中的应用
专知会员服务
98+阅读 · 2019年12月14日
[综述]基于深度学习的开放领域对话系统研究综述
专知会员服务
80+阅读 · 2019年10月12日
相关论文
Arxiv
5+阅读 · 2019年10月11日
A Sketch-Based System for Semantic Parsing
Arxiv
4+阅读 · 2019年9月12日
Arxiv
11+阅读 · 2019年4月15日
Arxiv
3+阅读 · 2018年12月21日
Physical Primitive Decomposition
Arxiv
4+阅读 · 2018年9月13日
Arxiv
8+阅读 · 2018年5月1日
Arxiv
5+阅读 · 2018年5月1日
Top
微信扫码咨询专知VIP会员