随着公司业务的发展,客服的业务量不断增加,为了解放人力,提升质检业务的覆盖率,及时有效的发现客服日常工作中的问题,需要建设智能质检系统,满足日益增长的话务质检系统需求。
质检系统主要针对的是电话(二线外呼,400内呼)和文本会话(IM会话)内容,以及客服的后续操作进行质检,以解决用户需求为核心,检验客服的服务。由于客服日常对接的用户诉求“千奇百怪”,质检系统需要对接的数据来源也是多方面的,这就要求质检系统需要对接各个系统,将多方数据进行串联,以算子为基础,使用配置化的规则计算脚本进行最终结果的计算。
质检的各项指标,按照数据的来源划分大致可以分为以下几种:
IM文本会话的内容,会话的时间等
二线外呼,400内呼电话通话内容,通话信息等
工单操作,比如创建工单,重启工单,催单等
商品类型,订单价格等
赔付记录,用户标签等
按照数据类型可以分为以下几种:
会话内容的语义,意图等
通话语速,情绪等
订单金额,商品标签,工单类型等
客服各类操作,创建工单,创建赔付单等
同时,在不同的场景下,“标准”的判定会有一定的差别,这就要求系统的质检,具有可以灵活调整的能力,规则的制定需要随着业务发展进行调整。
基于质检系统的业务特征,为了保证系统上线功能的正常使用,同时保证系统的稳定运行,在系统的设计时需要面临一些挑战:
按照一通会话对应一次质检,每天需要生成对应数量的质检单。针对每条质检单还需要有对应的质检项,最终质检系统需要对这些质检项,按照配置好的质检规则进行质检。
以上这4点就是整个质检系统在设计过程中着重需要注意的点,为系统设计指明了方向。
基于前面提到的这些挑战,整体的质检系统围绕如何采配置质检项,如何采集数据并完成质检开展。
质检系统整体数据采集的流程如下:
为了减少对下游系统服务的压力,解决大量质检单所需质检数据的采集问题,基于现有质检系统T+1生成质检单的模式,数据大宽表采用离线采集是比较优选的方案。
质检系统执行“质检”行为,主要基于在质检项上配置的质检规则进行,而质检规则的执行就依赖于规则引擎。
规则引擎的选择,最初考虑JDK自带的Java Script Engine,但该引擎只支持JavaScript,后期选择了扩展性更加强大的QLExpress。
质检系统根据话务类型将质检分为3大类,分别是一线,二线和400。不同类型的质检单通过离线采集数据生成对应的大宽表用于查询计算。以一线在线为例,数据的采集,清洗主要分为以下几个步骤:
基础数据采集生成离线表后,质检系统根据质检单中对应的会话id查询信息,并通过关联工单号,解析会话内容中的订单号,查询对应关联的离线数据表,最终组装成上下文信息并提交给规则引擎计算最终结果。
规则执行主要依赖于规则脚本的配置和规则引擎执行脚本,系统选用了QLExpress作为脚本引擎,QLExpress是一门动态脚本引擎解析工具,具有以下的一些优点:
支持 +,-,*,/,<,>,<=,>=,==,!=,<>【等同于!=】,%,mod【取模等同于%】,++,--,
/in【类似sql】,like【sql语法】,&&,||,!,等操作符
支持for,break、continue、if then else 等标准的程序控制逻辑
逻辑三元操作 a > b ? a : b;
不支持try{}catch{}
不支持java8的lambda表达式
不支持for循环集合操作for (Item item : list)
date = new Date();
System.out.println(date.getTime());
runner.addOperatorWithAlias("如果", "if", null);
runner.addOperatorWithAlias("则", "then", null);
runner.addOperatorWithAlias("否则", "else", null);
express = "如果 (A > B) 则 {return a;} 否则 {return b;}";
DefaultContextcontext = new DefaultContext ();
runner.execute(express, context, null, false, false, null);
//定义一个join方法
public class JoinOperator extends Operator {
@Override
public Object executeInner(Object[] list) throws Exception {
Object opdata1 = list[0];
Object opdata2 = list[1];
if (opdata1 instanceof List) {
((List)opdata1).add(opdata2);
return opdata1;
} else {
List result = new ArrayList();
for (Object opdata : list) {
result.add(opdata);
}
return result;
}
}
}
质检系统的主要用户为
用于自动质检的大宽表是在dataworks中,通过各数据源的基础表组装而成,最终将大宽表写入es以供自动质检时使用。查询时,大宽表数据还会经过二次组装,最终组装成规则引擎可用的上下文信息。
配置页面如下:
上次催单=距离最近时间(@I,@A,false);
承诺催单=A && !E;
催单时间=距离最近时间(@B,@C,true);
创单时间=距离最近时间(@D,@C,true);
重启时间=距离最近时间(@F,@C,true);
备注时间=距离最近时间(@G,@C,true);
if(承诺催单){
if(分钟差(上次催单,@A)>10){
return (!B || (@J < 催单时间 && 分钟差(@J,催单时间)>10)) && !D && !F;
}else{
return (!G || (@J < 备注时间 && 分钟差(@J,备注时间)>10));
}
}
return false;
脚本执行依赖于规则引擎中预先定义好的自定义函数和包含各种所需参数的上下文context执行。
自定义函数通过QLExpress的绑定java对象的method特性实现。以规则中“分钟差”为例:
首先通过java代码实现所需的自定义函数
public int timeDiff_Minute(Long t1,Long t2){
if(Objects.isNull(t1) || Objects.isNull(t2)){
throw new QlExpressException(4000,"计算分钟差失败,时间参数为空");
}
return (int)TimeUnit.MILLISECONDS.toMinutes(timeDiff(t1,t2));
}
将定义的method绑定至脚本引擎
QlExpressFunc qlExpressFunc = new QlExpressFunc();
runner.addFunctionOfServiceMethod("分钟差", qlExpressFunc, "timeDiff_Minute",
new Class[]{Long.class, Long.class}, null);
上下文context本质为Map对象,用于传递脚本执行时所需的参数。一般使用DefaultContext,也可通过实现IExpressContext接口自定义context。
public class DefaultContextextends HashMap implements IExpressContext
{ }
质检系统的目的是发现客服工作中的问题,为了提升发现问题的时效,并有效拦截外诉风险,未来质检的模式将从现有的基于T+1的离线数据模式改为实时质检模式。修改后的质检服务将在分钟级的尺度上对客服操作进行质检并及时发出预警。同时,修改实时质检模式后,可以有效的提升现有服务器资源的利用率,对整体服务的稳定性有很大的提升。
客户服务行为的本质可以简单的归纳为客服通过会话与用户交流并满足用户诉求,而质检则是对客服这一服务行为的检查。那么质检的结果就是由“语义”——客服与用户交流的内容和“行为”——客服满足用户诉求的操作来决定。其中语义的解析是现在影响质检结果的最大的瓶颈。对于质检系统来说,提高质检的准确率,当务之急就是提升语义解析的准确率。现在的系统通过文本,正则匹配和算法意图解析来进行语义的解析,这其中大部分语义解析都是基于单句话来执行,未来的目标是通过整通会话的上下文,进行更加精细的语义解析,以此来提升质检的准确率。
质检结果的第二个影响因素“行为”,在客服域内,客服可以应答用户诉求的操作应该遵循SOP。同样,质检系统在进行质检时,也应该根据SOP来制定质检规则。质检系统和SOP系统应该是相辅相成,质检系统发现问题并不是目标,而通过发现问题反馈建立SOP,杜绝相似问题的发生才是目的。
文章名称:自研智能质检系统探索之路
转载注明:http://www.shufengxianlan.com/qtweb/news34/325084.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联