智能客服是大规模知识处理技术、自然语言理解技术、知识管理技术、自动问答系统、推理技术等结合在一起的面向行业的应用,通常构建在IM如微信、钉钉上,以机器人的形式存在。集团在2020年发布了内部IM知音楼,并逐步提供了Yach机器人、造物神等相关能力,为知音楼智能机器人建设提供了技术基础。
1. 小思简介
小思是网校QA推出的课堂智能客服机器人,主要在客服、主讲、辅导等知音楼群帮助产研老师记录/诊断/拦截问题,提升值班效率,经过一年的发展,晒晒成绩单:
- 覆盖了全部网校产研重点值班群,活跃群数量300+,人机交互次数突破95万(含新K9)
- 根据运营提供的数据, 自动诊断准确率>90%,无效问题(技术类)拦截率 >90%,技术类问题解决效率提高50%
- 小思已经成为网校日常业务保障和寒暑假保障的重要一环,2021全年为网校节省人力超590.59人/天(不含K9),其中课堂保障部分占比约85%

1.1 项目背景
QA是网校产研值班中问题的第一负责人,任务重且存在很多重复的工作,主要有以下问题:
- 专项群中无效问题占比高达70%以上
- 咨询类问题需要QA老师重复解答,普适性问题的临时解决方法需要不断沟通
- 研发和测试老师需要处理大量重复性的技术类投诉,难以深入排查定位疑难问题

为了提高QA老师值班时的效率,释放由于以上特点带来的多余人力耗损,提升反馈群中问题解答、记录、统计等环节的体验,设计和开发基于Yach机器人的智能客服小思。
1.2 项目目标
(1)问题排查效率提升
- 降低问题排查成本,常见问题可100%自主排查
- 常见问题的解决方案获取缩短到 1min 内
(2)研发值班人力节省
- 释放QA老师们在值班中除技术问题排查外的人力
- 拦截无效问题和重复问题
- 打通自助排查-客诉-人工-jira(TB)的反馈闭环

2. 方案剖析
小思既要支持业务咨询,还要识别反馈中的有效信息并做出诊断,提升问题流转效率的同时也要解决问题,这就要求在设计中深度切合业务需要,设计出自我特色的架构和功能。
2.1 核心挑战
- 需求方众多,如何满足多种角色的定制化使用需求
- 群内反馈的问题多种多样,格式千奇百怪,如何精确识别老师们的问题
- 请求量越来越大,如何保证系统稳定

2.2 应对措施
- 和需求方多加沟通,确定真实的痛点需求,按照 紧急程度+收益 由高到低排优先级
- 做好技术调研工作,学习先进的智能客服设计理念,结合网校基础服务现状引入 adapter机制 做出适合我们自己的设计
- 配合AI中台分词能力, 自研语义识别算法、ID识别算法 等,配合华佗专家知识库、华佗综合诊断和关键词识别能力对老师们的信息进行识别并处理
- 为保障服务稳定性,使用了 uwsgi+nginx+django 的后端组合,可实现快速迭代的同时实现高并发,在各环节进行服务自检埋点,一旦出现问题会第一时间通知到我进行处理。

image.png
高可用、可拓展的服务架构设计:

消息处理流程设计:

3. 关键技术
3.1 自定义机器人和聊天机器人的区别
小思是基于知音楼的聊天机器人,可以接收并处理用户信息。
自定义
主要工作是发送通知
接入成本低
webhook接入
主动推送
聊天
可以聊天交互
接入成本高
依赖在线服务(有服务接口)
可接收消息和回复
3.2 获取用户消息和回复
接收消息示例:
{
"msgtype": "text",
"content": " @小思(小思) 值班 ",
"msgId": "0TLkY4RUHshwN9vdFQlAithFlvCzOsw0Op8lF2he4fM=",
"createAt": "1647415743014",
"conversationType": "2",
"conversationId": "WJYldYC5HHbZkz0m2IH+6A==",
"senderId": "+bRZTumCOMDyfFgu3jj9bTLZT7PxMvYbuoNoXOALG\/Y=",
"senderNick": "刘振",
"senderCorpId": "1",
"chatbotMid": "314060107107447193",
"atUsers": "[]",
"extra": "",
"remark": "",
"originName": "",
"conversationTitle": "自动化任务测试群",
"userJson": "{\"yachId\":\"132905995100\",\"workCode\":\"224659\",\"name\":\"\刘\振\",\"deptName\":\"\学\习\测\试\组\"}",
"chatbotUserId": "cy1XKWuZjqS5fStZZNKwIw==",
"chatbotUserName": "小思(小思)",
"appID": "1617944680"
}
回复空消息示例:
{
"msgtype": "empty"
}
回复文本消息示例:
{
"msgtype": "text",
"text": {
"content": "你就是你, @150XXXXXXXX 璀璨的@XXXXXXXX 烟火"
},
"at": {
"atMobiles": [
"150XXXXXXXX"
],
"atWorkCodes": [
"224659"
],
"isAtAll": false
}
}
3.3 adapter机制解析
adapter是一个目录,里面放着各种功能的转发器,当群里有人@小思发来请求时,会根据该群关联的adapter转发到这些转发器处理。
def get_result(params={}):
"""机器人消息的分发和结果获取 通过接收到的知音楼消息,处理后返回结果给群内 Args: params: 知音楼消息内容的二次包装,有发送人、内容、群信息等 Returns: 知音楼消息协议格式,详见https://doc-openapi.zhiyinlou.com/doc#/robot/develop?id=http%e5%93%8d%e5%ba%94%e6%a0%bc%e5%bc%8f%ef%bc%88json%e6%a0%bc%e5%bc%8f%ef%bc%89 """
# 私聊逻辑
if '1' == params['conversationType']:
return call_model('gundam_single', params)
adapter = params['conversationConfig']['adapter']
return call_model(adapter, params)
def call_model(adapter, params):
callMod = __import__('adapter', fromlist=(
adapter,))
callMethod = getattr(callMod, adapter)
adapterClass = callMethod.MyAdapter(params)
return adapterClass.get_result()
3.4 关键字处理逻辑的实现
Python没有switch-case语句,可以使用lambda方法实现类似转发
switch = {
'值班': lambda x: duty.return_today_duty(x),
'看课': lambda x: get_zkjump_result(),
'get': lambda x: get_mixed_result(x, 3),
'咨询': lambda x: self.ai_adapter.get_huatuo_msg(),
'课件': lambda x: get_kejian(x),
}
for key in switch.keys():
# 1. 判断关键字是否在这个群配置的功能列表里
# 2. 判断关键字是否是在用户消息头部
if key in self.functions and key in self.params['content'].strip()[:3]:
return switch[key](self.params)
break
# Do something else
3.5 点击式交互的实现
官方文档里并没有给出类似知音姐姐的这种点击交互的方法,我咨询了知音楼开发后得知,这种消息叫做评价,对应的 msgtype为appraise ,不确定群内能否使用。

经过尝试,发现在群聊中,我们不仅能通过聊天机器人发送自定义评价消息,还能获取评价消息点击后的交互信息。
if self.params['msgtype'] == 'reply':
# 用户回复消息时做处理,一般回复空
elif self.params['msgtype'] == 'appraise':
# 点击式交互信息处理
else:
# 文本类信息处理
3.6 获取知音楼消息后100ms内返回结果的挑战
您给小思发了一条消息,由于需要分析消息里的内容,进行链路复杂的诊断分析,可能需要花一些时间。这时小思在吐出正确结果前在群里刷屏了好多条: 第三方服务出现问题,请联系管理员。
解决方案是所有请求变为异步请求
(1)直接回复空消息给知音楼,异步处理业务逻辑
thread = threading.Thread(target=self.thread_get_msg, args=())
thread.start()
return self.reply_empty()
(2)使用p2c接口推送消息回复给用户
xiaosi = Xiaosi(self.params['conversationId'])
self.alert_user.append(self.params['userJson']['workCode'])
# 调用p2c接口发送消息到群内,并@原消息发送人
xiaosi.p2c(
msgtype='markdown',
markdown=markdown,
is_at_all=False,
workcodes=self.alert_user)
3.7 使用uWSGI+nginx为django提供高并发能力
django框架自带的服务运行在单进程中,吞吐承载力有限,我们可以搭配uWSGI/nginx的组合。
uWSGI: 是一种python web server,uWSGI是实现了uwsgi和WSGI两种协议的Web服务器,负责响应python 的web请求。
Nginx: 常用高性能代理服务器,这个是大家都比较熟悉的朋友了。
Nginx conf:
server {
listen 80;
#server_name localhost;
access_log logs/access.log;
error_log logs/error.log;
location / {
include uwsgi_params;
uwsgi_send_timeout 600;
uwsgi_connect_timeout 600;
uwsgi_read_timeout 600;
uwsgi_pass 127.0.0.1:8000;
}
location /static {
expires 30d;
autoindex on;
add_header Cache-Control private;
alias /home/www/static/;
}
}
uwsgi ini:
[uwsgi]
# 对外提供 http 服务的端口
http = :8080
# 用于和 nginx 进行数据交互的本地服务和端口
socket = 127.0.0.1:8000
# django 程序的主目录
chdir = /home/www
# Django 的 wsgi 文件位置
wsgi-file = gundam/wsgi.py
#配置启动管理主进程
master=True
log-master = true
# 最大的工作进程数
processes = 8
# 每个进程最大的工作线程数
threads = 2
# 通过该端口可以监控 uwsgi 的负载情况
#stats = 127.0.0.1:9191
# 为每个工作进程设置请求数的上限,可以使用这个选项来默默地对抗内存泄漏
max-requests=5000
#配置存放主进程的进程号文件
pidfile=logs/uwsgi.pid
# 服务退出的时候自动删除unix socket文件和pid文件。
vacuum = true
4. 使用场景和示例
4.1 值班管理和提醒


4.2 群定时通知


image.png
4.3 对接不同处理能力


灵活且准确的使用智能客服提供的能力,可以帮我们提升日常工作的效率,如果您有Python开发能力,小思开放了adapter自主接入,可以定制属于您自己业务的智能客服
出处:微信公众号:学而思网校技术团队
作者:刘振
来源:https://mp.weixin.qq.com/s?__biz=MzU4NDg2MTA4MA==&mid=2247489213&idx=1&sn=e4aaf821981db2f6cbc6f20235d53fa5