文档

企业微信智能质检

更新时间:

背景分析

企业可能已经在使用第三方产品,如企业微信,来管理客户关系和内部沟通。智能质检在支持电话语音坐席、工单服务、IM服务的行业等主流行业的质检需求外,同样支持对第三方产品的会话内容进行智能分析和质检。

基本业务流程

图1所示为企业微信进行实时文本质检或离线文本质检的对接流程。通过集成企业微信消息传递SDK,拉取企微会话文本,支持实时或离线拉取,形成待检数据集,为企业微信会话提供全面的对话内容分析。

在该流程中,待检数据首先与业务人员设定的质检规则相结合,利用智能算法进行匹配分析。分析结果将实时通知至质检结果处理人员,确保每一环节的准确性和及时性。同时,服务支持处理人员在线进行人工校验,以进一步提升分析的精确度,并允许保存复核结果,确保信息的可追溯性。

image

图一 企业微信支持智能质检的业务流程图

获取第三方会话记录

下文将以企业微信为例,介绍获取聊天记录的基本业务流程:

  1. 开启接收消息模式:

  2. 配置接收消息参数:

    • 设置接收消息的URL、Token、EncodingAESKey参数。

    • 企业微信会向设置的URL发送一条验证消息(GET请求)验证URL请求。

    • 配置方案参考接收消息与事件

  3. 使用接收消息

    • 一旦URL验证成功,接收消息模式将被开启。

    • 企业微信将把用户发送的消息以POST请求的形式推送到设置的URL。

  4. 消息传输:

    • 企业微信在推送消息给企业时,会对消息内容做AES加密,以XML格式POST到企业应用的URL上。企业在被动响应时,也需要对数据加密,以XML格式返回给企业微信。下文的消息格式以解密后的明文举例,加解密方案参考企业微信加解密方案

    • 企业微信不同语言的加解密库可参考加解密库下载与返回码

以Java为例:

Maven依赖:引入所需依赖。

        <dependency>
            <groupId>org.json</groupId>
            <artifactId>json</artifactId>
            <version>20231013</version>
        </dependency>
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.15</version>
        </dependency>

完整调用demo(入口为main方法):

import org.json.JSONObject;
import com.qq.weixin.mp.aes.WXBizJsonMsgCrypt;

public class Sample {

	public static void main(String[] args) throws Exception {
		String sToken = "QDG6eK";
		String sCorpID = "wx5823bf96d3bd56c7";
		String sEncodingAESKey = "jWmYm7qr5nMoAUwZRjGtBxmz3KA1tkAj3ykkR6q2B2C";

		WXBizJsonMsgCrypt wxcpt = new WXBizJsonMsgCrypt(sToken, sEncodingAESKey, sCorpID);
		/*
		------------使用示例一:验证回调URL---------------
		*企业开启回调模式时,企业微信会向验证url发送一个get请求 
		假设点击验证时,企业收到类似请求:
		* GET /cgi-bin/wxpush?msg_signature=5c45ff5e21c57e6ad56bac8758b79b1d9ac89fd3&timestamp=1409659589&nonce=263014780&echostr=P9nAzCzyDtyTWESHep1vC5X9xho%2FqYX3Zpb4yKa9SKld1DsH3Iyt3tP3zNdtp%2B4RPcs8TgAE7OaBO%2BFZXvnaqQ%3D%3D 
		* HTTP/1.1 Host: qy.weixin.qq.com

		接收到该请求时,企业应
		1.解析出Get请求的参数,包括消息体签名(msg_signature),时间戳(timestamp),随机数字串(nonce)以及企业微信推送过来的随机加密字符串(echostr),这一步注意作URL解码。
		2.验证消息体签名的正确性 
		3. 解密出echostr原文,将原文当作Get请求的response,返回给企业微信
		第2,3步可以用企业微信提供的库函数VerifyURL来实现。

		*/
		// 解析出url上的参数值如下:
		// String sVerifyMsgSig = HttpUtils.ParseUrl("msg_signature");
		String sVerifyMsgSig = "5c45ff5e21c57e6ad56bac8758b79b1d9ac89fd3";
		// String sVerifyTimeStamp = HttpUtils.ParseUrl("timestamp");
		String sVerifyTimeStamp = "1409659589";
		// String sVerifyNonce = HttpUtils.ParseUrl("nonce");
		String sVerifyNonce = "263014780";
		// String sVerifyEchoStr = HttpUtils.ParseUrl("echostr");
		String sVerifyEchoStr = "P9nAzCzyDtyTWESHep1vC5X9xho/qYX3Zpb4yKa9SKld1DsH3Iyt3tP3zNdtp+4RPcs8TgAE7OaBO+FZXvnaqQ==";
		String sEchoStr; //需要返回的明文
		try {
			sEchoStr = wxcpt.VerifyURL(sVerifyMsgSig, sVerifyTimeStamp,
					sVerifyNonce, sVerifyEchoStr);
			System.out.println("verifyurl echostr: " + sEchoStr);
			// 验证URL成功,将sEchoStr返回
			// HttpUtils.SetResponse(sEchoStr);
		} catch (Exception e) {
			//验证URL失败,错误原因请查看异常
			e.printStackTrace();
		}

		/*
		------------使用示例二:对用户回复的消息解密---------------
		用户回复消息或者点击事件响应时,企业会收到回调消息,此消息是经过企业微信加密之后的密文以post形式发送给企业,密文格式请参考官方文档
		假设企业收到企业微信的回调消息如下:
		POST /cgi-bin/wxpush? msg_signature=477715d11cdb4164915debcba66cb864d751f3e6&timestamp=1409659813&nonce=1372623149 HTTP/1.1
		Host: qy.weixin.qq.com
		Content-Length: 
		Content-Type:text/json
		
		{
			"tousername":"wx5823bf96d3bd56c7",
			"encrypt":"RypEvHKD8QQKFhvQ6QleEB4J58tiPdvo+rtK1I9qca6aM/wvqnLSV5zEPeusUiX5L5X/0lWfrf0QADHHhGd3QczcdCUpj911L3vg3W/sYYvuJTs3TUUkSUXxaccAS0qhxchrRYt66wiSpGLYL42aM6A8dTT+6k4aSknmPj48kzJs8qLjvd4Xgpue06DOdnLxAUHzM6+kDZ+HMZfJYuR+LtwGc2hgf5gsijff0ekUNXZiqATP7PF5mZxZ3Izoun1s4zG4LUMnvw2r+KqCKIw+3IQH03v+BCA9nMELNqbSf6tiWSrXJB3LAVGUcallcrw8V2t9EL4EhzJWrQUax5wLVMNS0+rUPA3k22Ncx4XXZS9o0MBH27Bo6BpNelZpS+/uh9KsNlY6bHCmJU9p8g7m3fVKn28H3KDYA5Pl/T8Z1ptDAVe0lXdQ2YoyyH2uyPIGHBZZIs2pDBS8R07+qN+E7Q==",
			"agentid":"218"
		}

		企业收到post请求之后应该		1.解析出url上的参数,包括消息体签名(msg_signature),时间戳(timestamp)以及随机数字串(nonce)
		2.验证消息体签名的正确性。
		3.将post请求的数据进行json解析,并将"encrypt"标签的内容进行解密,解密出来的明文即是用户回复消息的明文,明文格式请参考官方文档
		第2,3步可以用企业微信提供的库函数DecryptMsg来实现。
		*/
		// String sReqMsgSig = HttpUtils.ParseUrl("msg_signature");
		String sReqMsgSig = "0623cbc5a8cbee5bcc137c70de99575366fc2af3";
		// String sReqTimeStamp = HttpUtils.ParseUrl("timestamp");
		String sReqTimeStamp = "1409659813";
		// String sReqNonce = HttpUtils.ParseUrl("nonce");
		String sReqNonce = "1372623149";
		// post请求的密文数据
		// sReqData = HttpUtils.PostData();
		String sReqData = "{\"tousername\":\"wx5823bf96d3bd56c7\",\"encrypt\":\"CZWs4CWRpI4VolQlvn4dlEC1alN2MUEY2VklGehgBVLBrlVF7SyT+SV+Toj43l4ayJ9UMGKphktKKmP7B2j/P1ey67XB8PBgS7Wr5/8+w/yWriZv3Vmoo/MH3/1HsIWZrPQ3N2mJrelStIfI2Y8kLKXA7EhfZgZX4o+ffdkZDM76SEl79Ib9mw7TGjZ9Aw/x/A2VjNbV1E8BtEbRxYYcQippYNw7hr8sFfa3nW1xLdxokt8QkRX83vK3DFP2F6TQFPL2Tu98UwhcUpPvdJBuu1/yiOQIScppV3eOuLWEsko=\",\"agentid\":\"218\"}";

		try {
			String sMsg = wxcpt.DecryptMsg(sReqMsgSig, sReqTimeStamp, sReqNonce, sReqData);
			System.out.println("after decrypt msg: " + sMsg);
			// TODO: 解析出明文json标签的内容进行处理
			// For example:
			JSONObject json = new JSONObject(sMsg);    
        	String Content = json.getString("Content");
			String CreateTime = json.getString("CreateTime");
			String customerOrAgent = json.getString("FromUserName");
			
			System.out.println("Content:" + Content);
			System.out.println("CreateTime:" + CreateTime);
			System.out.println("Character:" + customerOrAgent);
			//System.out.println("");
			
		} catch (Exception e) {
			// TODO
			// 解密失败,失败原因请查看异常
			e.printStackTrace();
		}

	/*
		------------使用示例三:企业回复用户消息的加密---------------
		企业被动回复用户的消息也需要进行加密,并且拼接成密文格式的json串。
		假设企业需要回复用户的明文如下:
		{ 
			"ToUserName": "mycreate",
			"FromUserName":"wx5823bf96d3bd56c7",
			"CreateTime": 1348831860,
			"MsgType": "text",
			"Content": "this is a test",
			"MsgId": 1234567890123456,
			"AgentID": 128
    	}

		为了将此段明文回复给用户,企业应:			1.自己生成时间戳(timestamp),随机数字串(nonce)以便生成消息体签名,也可以直接用从企业微信的post url上解析出的对应值。
		2.将明文加密得到密文。	3.用密文,步骤1生成的timestamp,nonce和企业在企业微信设定的token生成消息体签名。			4.将密文,消息体签名,时间戳,随机数字串拼接成json格式的字符串,发送给企业。
		以上2,3,4步可以用企业微信提供的库函数EncryptMsg来实现。
		*/
		String sRespData = "{\"ToUserName\":\"wx5823bf96d3bd56c7\",\"FromUserName\":\"mycreate\",\"CreateTime\": 1409659813,\"MsgType\":\"text\",\"Content\":\"hello\",\"MsgId\":4561255354251345929,\"AgentID\": 218}";
		try{
			String sEncryptMsg = wxcpt.EncryptMsg(sRespData, sReqTimeStamp, sReqNonce);
			System.out.println("after encrypt sEncrytMsg: " + sEncryptMsg);
			// 加密成功
			// TODO:
			// HttpUtils.SetResponse(sEncryptMsg);
		}
		catch(Exception e)
		{
			e.printStackTrace();
			// 加密失败
		}

	}
}
  1. 消息格式:

  • 文本消息明文示例及参数说明参考消息格式

控制台发起质检分析

将多句文本整理为数据集后,可上传至智能对话分析控制台创建数据集任务发起质检分析。

文本数据集中要求提供的角色、开始时间、内容与文本消息XML中的FromUserName、CreateTime、Content一一对应。

创建质检规则、质检任务配置、执行质检任务和质检结果复核相关内容请参考创建质检规则

接入SDK发起质检分析

离线文本对话具体说明参考UploadDataV4 - 上传文本质检V4

调用智能对话分析的UploadDataV4接口,发起离线文本质检分析。

实时文本检测具体说明参考UploadDataSync - 文本实时质检

调用智能对话分析的UploadDataSync接口,发起实时文本质检分析。

以Java代码为例:

maven依赖,引入质检SDK。

        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-qualitycheck</artifactId>
            <version>3.0.7</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-core</artifactId>
            <version>4.0.6</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.83_noneautotype</version>
        </dependency>

完整调用demo(入口为main方法):

说明

调用接口前,需配置环境变量,通过环境变量读取访问凭证。关于配置环境变量的操作,请参见使用说明

智能对话分析的AccessKey ID和AccessKey Secret的环境变量名:SCA_AK_ENVSCA_SK_ENV

package com.aliyun.sample;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;

import com.aliyuncs.qualitycheck.model.v20190115.UploadDataRequest;
import com.aliyuncs.qualitycheck.model.v20190115.UploadDataResponse;
import com.aliyuncs.qualitycheck.model.v20190115.UploadDataSyncRequest;
import com.aliyuncs.qualitycheck.model.v20190115.UploadDataSyncResponse;

/**
 * 发起离线/实时文本质检Demo
 */
public class Sample {

    /**
     * 此处通过从环境变量中读取AccessKey,初始化智能对话分析Client
     * @return Client
     * @throws Exception
     */
    public static IAcsClient createSCAClient() throws Exception {
        // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户
        // 此处以把AccessKey 和 AccessKeySecret 保存在环境变量为例说明。您也可以根据业务需要,保存到配置文件里
        // 强烈建议不要把 AccessKey 和 AccessKeySecret 保存到代码里,会存在密钥泄漏风险
        IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", System.getenv("SCA_AK_ENV"), System.getenv("SCA_SK_ENV"));
        //指定服务接入地址,以下值为固定
        DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", "Qualitycheck", "qualitycheck.cn-hangzhou.aliyuncs.com");

        return new DefaultAcsClient(profile);
    }


    /**
     * 组装入参JsonStr,调用文本上传CDK,上传质检数据
     * @param args_
     * @throws Exception
     */
    public static void main(String[] args_) throws Exception {
        /**
         * 1. 组装调用参数
         */
        String jsonStr = null;
        /**
         * uploadData 上传音频质检, 入参jsonStr
         *
         * jsonStr示例:其中dialogue为必填项,其余为选填项,详细文档见https://help.aliyun.com/zh/sca/developer-reference/api-qualitycheck-2019-01-15-uploaddata
         * {
         *     "isSchemeData": 1,
         *     "ruleIds": [
         *
         *     ],
         *     "tickets": [
         *         {
         *             "skillGroupName": "技能组******",
         *             "callType": "3",
         *             "callee": "176********",
         *             "caller": "057**********",
         *             "business": "北京",
         *             "callStartTime": "17************",
         *             "customerServiceId": "270***********",
         *             "customerServiceName": "ServiceName",
         *             "remark1": "****",
         *
         *             "remark25": "*****",
         *             "dialogue": [
         *                 {
         *                     "beginTime": "2000-12-31 23:59:58",
         *                     "role": "客户",
         *                     "identity": "某客户",
         *                     "emotionValue": 6,
         *                     "speechRate": 111,
         *                     "words": "你好。",
         *                     "end": "2580",
         *                     "begin": "1800",
         *                     "channelId": "1"
         *                 },
         *                 {
         *                     "beginTime": "2000-12-31 23:59:59",
         *                     "role": "客服",
         *                     "identity": "某客服",
         *                     "emotionValue": 6,
         *                     "speechRate": 222,
         *                     "words": "请问有什么可以帮您。",
         *                     "end": 8540,
         *                     "begin": 6770,
         *                     "channelId": 0
         *                 }
         *             ],
         *             "fileName": "yourfilename"
         *         }
         *     ]
         * }
         *
         * uploadDataSync 实时上传音频质检, 入参jsonStr,详细文档见https://help.aliyun.com/zh/sca/developer-reference/api-qualitycheck-2019-01-15-uploaddatasync
         * {
         *     "ruleIds": [
         *         1
         *     ],
         *     "tickets": [
         *         {
         *             "tid": "本段文本的ID,可以使用对应的电话或工单数据 ID,注意不要重复",
         *             "dialogue": [
         *                 {
         *                     "role": "客服",
         *                     "words": "你好",
         *                     "end": 5000,
         *                     "begin": 1000,
         *                     "beginTime":"2000-12-31 23:59:59"
         *                 }
         *             ]
         *         }
         *     ]
         * }
         */
        uploadData(jsonStr);
        uploadDataSync(jsonStr);
    }


    // 上传离线文本质检数据
    public static void uploadData(String jsonStr) {
        UploadDataRequest req = new UploadDataRequest();
        req.setJsonStr(jsonStr);
        try {
            UploadDataResponse response = createSCAClient().getAcsResponse(req);
            System.out.println(response.getCode());
            System.out.println(response.getMessage());
            System.out.println(response.getData());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    // 上传实时文本质检数据
    public static void uploadDataSync(String jsonStr) {
        UploadDataSyncRequest req = new UploadDataSyncRequest();
        req.setJsonStr(jsonStr);
        try {
            UploadDataSyncResponse response = createSCAClient().getAcsResponse(req);
            System.out.println(response.getCode());
            System.out.println(response.getMessage());
            System.out.println(response.getData());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}