客服团队超过 5 个人,管理就会遇到一个盲区:客户消息多久被回复的?有没有人被漏回?客服有没有乱承诺?传统做法是主管每天翻聊天记录抽检,覆盖率不到 5%,而且只能事后发现——客户已经被怠慢完了。

其实质检需要的数据,微信回调里全都有。本教程用微信机器人开发 API 搭一套客服质检系统:全量消息入库 → 首响时长计算 → 漏回检测 → 敏感词合规扫描 → 每日质检日报自动推送。基于标准 HTTP + Webhook 接口实现(本文以 WTAPI 为例,Python 代码),接口均对照官方开发文档核实,可直接作为搭建文档。

一、关键认知:质检的数据从哪来

前面几篇教程都强调一个过滤技巧:回调报文里 FromUserName.string == Wxid 是本号发出的消息,做机器人时要过滤掉,避免回复自己。

做质检恰恰相反——本号发出的消息正是被检对象。

官方回调是全量推送的:客户发来的消息进回调,客服用这个微信号发出的消息同样进回调。两条数据流一配对,"客户几点问的、客服几点回的、回了什么"就全齐了。这就是整套系统的数据基础,不需要在客服手机上装任何东西。

二、接入层:全量消息入库

回调规范不变:3 秒内响应、去重键 Appid + Data.NewMsgId。区别是不再过滤任何方向的消息,按方向打标后全部入库:

import json, time
import requests
from flask import Flask, request

API_BASE = "https://wx.chuapi.com"
APP_ID = "YOUR_APPID"
HEADERS = {
    "X-finder-TOKEN": "YOUR_TOKEN",
    "Authorization": "Bearer YOUR_JWT",
    "Content-Type": "application/json",
}

_seen = set()
app = Flask(__name__)

@app.route("/wtapi/callback", methods=["POST"])
def callback():
    msg = request.get_json(silent=True) or {}
    if msg.get("TypeName") != "AddMsg":
        return "", 200
    d = msg.get("Data", {})
    key = f"{msg.get('Appid')}:{d.get('NewMsgId')}"
    if key in _seen:
        return "", 200
    _seen.add(key)

    from_user = d.get("FromUserName", {}).get("string", "")
    # 质检场景:不按方向过滤,两端都存
    db.save_message({
        "msg_id": d.get("NewMsgId"),
        # 本号发出 = 客服回复;客户发出 = 客户咨询
        "direction": "out" if from_user == msg.get("Wxid") else "in",
        "peer": d.get("ToUserName", {}).get("string", "") if from_user == msg.get("Wxid") else from_user,
        "msg_type": d.get("MsgType"),
        "content": d.get("Content", {}).get("string", ""),
        "create_time": d.get("CreateTime"),   # 官方字段:消息时间戳
    })
    return "", 200

注意 Content.string 的判定路径以官方回调速览页为准;群消息(FromUserName 以 @chatroom 结尾)里客服的发言同样可检,适合做社群运营的响应质检。

三、指标层:三个可落地的质检指标

① 首响时长——客户提问到客服第一条回复的时间差。按"客户 wxid + 会话窗口"配对:

def first_response_seconds(peer_wxid, day):
    msgs = db.get_messages(peer_wxid, day)  # 按 create_time 升序
    waiting_since, gaps = None, []
    for m in msgs:
        if m["direction"] == "in" and waiting_since is None:
            waiting_since = m["create_time"]          # 客户提问
        elif m["direction"] == "out" and waiting_since:
            gaps.append(m["create_time"] - waiting_since)
            waiting_since = None                       # 客服已回应
    if waiting_since:
        db.mark_unanswered(peer_wxid, waiting_since)   # ② 漏回:至统计时无回复
    return sum(gaps) / len(gaps) if gaps else None

② 漏回检测:客户消息发出后 N 小时(建议设 4 小时)无任何"out"方向消息,进漏回名单,质检日报里置顶——这是比"回复慢"严重一个量级的事故。

③ 敏感词扫描:客服发出的每条消息过黑名单,命中即告警:

BANNED = ["保证收益", "稳赚", "百分百", "内部渠道", "放心不会亏"]

def scan_outbound(m):
    hits = [w for w in BANNED if w in m["content"]]
    if hits:
        db.save_violation(m["msg_id"], m["peer"], hits)

黑名单按行业配:教培禁"保过提分"、保险禁"保本稳赔"、房产禁"稳涨学区房"。图片、语音(MsgType=3/34)算"有响应"计入首响,但内容合规只能抽检,这是当前方案的边界,写日报时如实标注。

四、输出层:日报自动推给主管

质检系统的价值在"每天自动出现在主管面前"。跑完统计,直接用官方发消息接口 postText(参数仅 appId/toWxid/content)把日报推到主管微信:

def push_daily_report(boss_wxid):
    r = db.build_daily_report()
    post_text(boss_wxid,
        f"【客服质检日报 {r['day']}】\n"
        f"平均首响:{r['avg_first_response']}秒(红线 120 秒)\n"
        f"超时可溯会话:{r['slow_convos']} 个\n"
        f"漏回客户:{r['unanswered']} 个 ← 需今日补救\n"
        f"敏感词命中:{r['violations']} 条")

def post_text(to_wxid, content):
    requests.post(
        f"{API_BASE}/finder/v2/api/message/postText",
        headers=HEADERS,
        data=json.dumps({"appId": APP_ID, "toWxid": to_wxid, "content": content}),
        timeout=10,
    )

五、调试与上线

调试环境:WTAPI 开发文档站 weiti.apifox.cn 提供 7 天接口调用权限,后台附带 Demo 示例可供本地调试,本文所有接口路径与字段以文档实时内容为准。建议先在控制台「微信实例」扫码拿 appId,用 toWxid=filehelper(文件传输助手)模拟收发,验证首响配对逻辑后再接真实客服号。

上线前三个提醒:

  1. 员工知情权:对客服账号做质检必须先告知员工并写入制度,只用于工作号、不碰私人号——这是法律红线,也是团队信任的基础;
  2. 先跑基线再定红线:首响红线别拍脑袋,先采集两周数据看分布,再定考核阈值;
  3. 质检数据就是客服培训素材库:漏回案例、违规话术脱敏后就是最好的周会教材,别只用于处罚。

合规声明:本文方案仅限企业对自有工作微信号的客服质量管理场景,须提前告知员工并遵守劳动与个人信息相关法规、微信平台运营规范,不使用任何非官方破解协议。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐