本文继续围绕工业级业务对话平台和框架Rasa对如何处理业务对话系统中来自用户的unexpected intent的场景从核心组件UnexpecTEDIntentPolicy的源码层面进行解析。
一、关于UnexpecTEDIntentPolicy
在Rasa3.0的框架中,UnexpecTEDIntentPolicy的功能是很重要的一个部分,在业务对话机器人中,基于当前的对话上下文,可以使用UnexpecTEDIntentPolicy来判断用户是否是按照当前的对话上下文的逻辑来进行对话的,如果不是这样,那对话机器人应该如何处理,这显然是你在做对话机器人时必须要考虑的场景。从另外一方面来说,用户不按照当前上下文的逻辑来提供不符合预期的对话输入的场景可以视作是一种“异常”,从这个角度可以更好地理解对话机器人实际工作的过程。在业务对话系统中,通常是由用户意图(intent),用户意图触发的action,以及对话状态(state)三部分进行相互作用。在做对话机器人时,应该是基于用户的行为进行思考,UnexpecTEDIntentPolicy就是基于用户的输入信息和对话上下文来构建并能快速有效地解决前面提到的所谓“异常”的问题。从人工智能的角度看,往往是基于行为和数据来推断出具体的模式或者规律,对应的是模型的参数,然后基于测试数据或者新的数据来不断地优化模型的质量。
- 关于UnexpecTEDIntentPolicy导入包和类分析
导入MessageContainerForCoreFeaturization:
MessageContainerForCoreFeaturization是从precomputation导入,Rasa会对预计算的内容进行缓存,MessageContainerForCoreFeaturization是一个基于”key-value”的数据结构来存储从用户输入信息提取的attributes的容器,具体的attributes包括:`ACTION_NAME`, `ACTION_TEXT`, `TEXT`, or `INTENT`。
使用背景:
1)UnexpecTEDIntentPolicy只需要通过NLU graph components对这些attributes进行分词处理和特征提取
2)分词器和特征提取器针对每一项attribute是独立工作的,所以可以完全将每项attribute分开使用
3)分词器添加attributes(e.g. token sequences),而不仅是Features
4)由于使用这样的数据结构,它不会包括policies所需要的所有features(cf. `rasa.core.featurizers.SingleStateFeaturizer`),有时候用户输入信息根本不包括任何features
5) 不同的attributes的值可能是一致的,譬如”greet”可以作为用户输入信息,也可以作为用户意图的名称,但并不是所有的attributes都是以这样的方式来进行分词处理和特征提取,所以需要使用key attribute和value的组合来识别一条信息
具体用法:
-在进行特征提取的pipeline(如上面DAG图所示,Rasa3.x框架使用的是一种流式的计算)的开始部分,Rasa使用这个容器来对给定的训练语料的数据进行去重处理,以及对对话状态tracker里的数据去重(譬如一个text在对话中重复出现,只会对它做一次特征提取)
-在进行特征提取的pipeline的结束部分,Rasa把处理后的所有信息再次封装到这个容器里
导入tensorflow,建议使用2.6的版本:
导入数据类型:
导入ExecutionContext,如上面DAG图所示,每一个graph component在图中都有上下文的依赖关系:
导入DefaultV1Recipe,它相当于程序运行时的配置,譬如在开发时需要使用哪些机器学习组件会配置在一个yml文件里:
导入Resource,它用于表示图中一个持久化的graph component,通过Resource的name从ModelStorage中定位到这个graph component的数据:
导入ModelStorage,它用于为需要进行持久化操作的graph component提供存储服务,对于Rasa以图的框架来进行流式计算来说,状态的管理是非常重要的,无论对于训练还是推理,通过这种持久化机制,可以极大地加速训练:
导入LABEL_RANKING_LENGTH,这跟分类相关:
导入DialogueStateTracker,这用于对话状态的跟踪:
导入SLOTS, ACTIVE_LOOP, ACTION_UNLIKELY_INTENT_NAME等配置常量信息:
导入UserUttered, ActionExecuted等事件,你可以把Rasa的DAG架构看做是由事件驱动的,无论是在训练还是推理,在Rasa3.x的架构中,实际上会有多个policies并行处理,根据最后处理结果选取confidence最高的:
UnexpecTEDIntentPolicy是基于TEDPolicy的:
导入RasaModel,这是一个基于tensorflow的通用的模型接口:
导入RasaModelData,这是一个模型数据封装类:
2. UnexpecTEDIntentPolicy和TEDPolicy关系分析
UnexpecTEDIntentPolicy继承自TEDPolicy,它具有和TEDPolicy同样的模型架构。对于TEDPolicy来说,针对每一个对话turn,TED policy使用这三部分信息作为输入:用户输入信息,历史对话信息,保存对话状态信息的slots。每一部分内容都进行特征提取然后连接在一起后传给Transformer进行处理。UnexpecTEDIntentPolicy与TEDPolicy不同之处在于执行的任务级别,TEDPolicy是用于预测next action,而UnexpecTEDIntentPolicy会根据训练语料和对话上下文来预测最后一次预测使用的intent是否与对话上下文匹配。
3. UnexpecTEDIntentPolicy源码剖析
使用Python的decorator “DefaultV1Recipe.register”对graph component进行注册,从而能在DAG图中使用它:
在这里注册的component类型为” POLICY_WITH_END_TO_END_SUPPORT”,这是因为UnexpecTEDIntentPolicy需要直接使用对用户输入信息进行特征提取获得的features,以下是类型定义:
通过方法get_default_config获取配置信息,如hidden layer size,用于sparse features的dense dimension等,通常intent和action是对应的关系:
关于Transformer的一些配置:
训练使用的一些参数配置,例如负样本数量NUM_NEG等:
进行初始化赋值操作:
Rasa 3.x基于DAG图的架构实现了系统基础架构和模型架构的分离,这样就可以使开发者只考虑在graph中使用什么样的模型,譬如通过下面的方法来指定UnexpecTEDIntentPolicy组件所使用的模型:
通过方法_assemble_label_data把所有的训练数据进行整合:
方法_prepare_data_for_prediction用于把训练数据转换为可以用于模型预测的数据:
方法compute_label_quantiles_post_training用于计算是否触发” action_unlikely_intent”的分数,在推理时每一个label都会计算多个分数,再根据” tolerance”设定的值来决定触发” action_unlikely_intent”的 threshold。
方法_get_trackers_for_training用于过滤掉不能用于训练的tracker list,譬如:
-没有用户意图的UserUttered事件
-没有action_name的ActionExecuted事件