客户发"查订单",机器人要去订单系统查订单号;发"退款",要建退款工单。这些业务处理不是一个 if-else 能搞定的,是一条管道:接收消息 → 提取意图 → 调用业务接口 → 回发结果。这篇讲这条管道怎么搭,重点在业务处理层,不是消息接收本身。
底层用的是Eyun 平台开放的企微 API,凭证在Eyun 平台首页开通,Webhook 收消息,message/sendText 发回复。
接收层:只做落库和投递
回调进来先落库,推队列,立即返回 200。队列里存的是消息 ID,处理线程取 ID 查消息体再处理。
@app.route("/wx-api/webhook/", methods=["POST"]) def webhook(): delivery_id = request.headers.get("X-Eyun-Delivery") if redis.setnx(f"dedup:{delivery_id}", 1): redis.expire(f"dedup:{delivery_id}", 86400) msg_id = save_message(request.json) redis.lpush("process_queue", msg_id) return "ok"消息体字段(fromUin、content、conversationId、msgType)在Eyun 开发文档里有完整说明。落库后处理逻辑和接收层解耦,处理慢了不会堵回调。
意图提取:关键词优先,模型兜底
业务处理的第一步是判断客户要干什么。先用关键词规则匹配——"订单"对应查询订单、"退款"对应退款流程、"发票"对应发票申请。规则匹配成本低、响应快,覆盖 70% 场景。
规则没命中的,塞给轻量模型做意图分类。模型输出预定义的意图标签和置信度,置信度低于 0.7 的转人工,不硬答。
业务处理:按意图调接口
意图确定后,按意图调对应业务接口。每个意图对应一个处理函数,输入是消息上下文,输出是回复内容。
def handle_query_order(appid, from_uin, content): order_no = extract_order_no(content) if not order_no: return "请提供订单号" order = order_api.query(order_no) if order["status"] == "shipped": return f"订单 {order_no} 已发货,快递单号 {order['tracking']}" return f"订单 {order_no} 状态:{order['status']}" INTENT_HANDLERS = { "query_order": handle_query_order, "refund": handle_refund, "invoice": handle_invoice, }处理函数里调业务系统的接口,不直接调企微接口。需要查客户档案时,调 contact/getUserProfileDetail;需要打标签时调 label/updateLabel。
回发:结果格式化后发消息
处理结果回发时,简单文本用 sendText,带链接或详情用 sendRichText 发卡片。
def reply(appid, to_uin, text): requests.post( f"{BASE}/wx-api/api/message/sendText", headers=HEADERS, json={"appid": appid, "to": to_uin, "content": text} )处理失败要回友好提示,不能把异常信息直接发给客户。比如订单系统超时,回"正在查询,请稍候",后台异步重试后再补发结果。
处理流水线的核心是解耦
接收、意图、业务、回发四层拆开,每层只做一件事。接收层不关心业务,业务层不关心消息怎么来的,回发层不关心业务逻辑。分层之后改意图规则不用动接收层,换业务接口不用动回发层,维护成本低很多。