ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

企业微信外部群机器人开发:如何让不同群使用不同业务流程?

企业微信外部群机器人开发:如何让不同群使用不同业务流程? 在企业微信自动化开发的早期阶段我们通常关注的是“一问一答”式的单点规则分发例如不同群命中不同关键词回复不同内容。然而当你的私域系统真正深入到企业的核心价值链时单点的规则已经无法满足需求你需要处理的是复杂的多节点业务流程Business Workflows。例如群 A售后群执行【报修流程】第一步识别报修意图 - 第二步让客户提供设备 SN 码 - 第三步让客户上传故障照片 - 第四步生成内部工单并回复进度查询链接。群 B内购群执行【下单流程】第一步输入商品编号 - 第二步系统校验库存 - 第三步让客户输入地址 - 第四步下发支付卡片。要让不同的外部群平稳运行完全独立且多步交互的业务流程系统就必须具备“记忆”。基于 星云API官网 稳如磐石的底层通道我们将引入“有限状态机FSM与分布式上下文追踪Context Tracking”的架构教你如何打造一个真正具备业务编排能力的企业级中台。一、 核心架构为什么“流程”比“规则”难做处理“业务流程”的核心难点在于状态State的持续跟踪。HTTP 请求和 Webhook 推送本身是无状态Stateless的。当客户发来一句“北京市朝阳区XXX”网关根本不知道这是一句闲聊还是下单流程中要求填写的收货地址。因此我们的中台架构必须增加以下三个引擎流程绑定引擎Workflow Binder记录RoomId绑定了哪一套业务流程。上下文记忆引擎Context Store利用 Redis Hash 记录某个客户FromUserName在某个群RoomId的当前流程节点Step。状态机调度器State Machine Dispatcher收到消息后先查客户当前处于流程的第几步再执行对应的代码逻辑。二、 数据库/缓存设计Redis 的双重映射为了保证在极高并发下状态不混乱我们需要在 Redis 中维护两类 Key群流程配置 Key:group_workflow:{RoomId}Value 示例workflow_support(售后流程) 或workflow_order(下单流程)用户状态上下文 Key:user_context:{RoomId}:{FromUserName}Value 示例 (JSON){current_step: 2, temp_data: {sn_code: MAC123}}注意必须加上过期时间TTL如 30 分钟防止客户中途退出流程导致状态永久死锁。三、 核心代码实战带状态机的多群业务流转引擎下面是一段生产级可用的 Python (Flask) 实战代码。它展示了如何在同一个网关下让两个不同的群完美运行两个截然不同的多步业务流互不干扰。Pythonfrom flask import Flask, request, jsonify import requests import threading import json import redis app Flask(__name__) # --- 通道全局配置 --- API_KEY 你的专属_X-Nebula-Key SEND_TEXT_URL https://api.xingyapi.com/api/message/sendText BOT_USER_ID 当前机器人的企微UserID # 初始化 Redis 客户端用于存储群流程配置和客户上下文 redis_client redis.StrictRedis(hostlocalhost, port6379, db0, decode_responsesTrue) # # 1. 业务流程定义 (Workflows with State Machines) # def workflow_support_flow(room_id, sender_id, content, context): 售后报修多步流程 step context.get(current_step, 0) if step 0 and 报修 in content: # 推进到第 1 步 update_context(room_id, sender_id, {current_step: 1}) return 您好已为您开启报修流程。请发送您的【设备SN码】 elif step 1: # 记录 SN 码推进到第 2 步 sn_code content.strip() update_context(room_id, sender_id, {current_step: 2, sn_code: sn_code}) return f已记录设备SN码({sn_code})。请用一句话描述故障现象 elif step 2: # 完成流程清理状态调用内部工单系统 sn_code context.get(sn_code) fault_desc content.strip() # 模拟内部 RPC 调用 print(f [内部系统] 创建工单: SN{sn_code}, 故障{fault_desc}) clear_context(room_id, sender_id) return ✅ 您的报修工单已提交成功技术专家将很快联系您 return None # 非流程内消息返回 None 交给兜底逻辑 def workflow_order_flow(room_id, sender_id, content, context): 内购下单多步流程 step context.get(current_step, 0) if step 0 and 下单 in content: update_context(room_id, sender_id, {current_step: 1}) return 欢迎使用内购系统请输入您要购买的【商品编号】 elif step 1: item_code content.strip() update_context(room_id, sender_id, {current_step: 2, item_code: item_code}) return f您选择了商品({item_code})请输入【收货地址】 elif step 2: item_code context.get(item_code) address content.strip() # 模拟请求订单中台 print(f [内部系统] 创建订单: 商品{item_code}, 地址{address}) clear_context(room_id, sender_id) return f✅ 下单成功系统正在为您发货至{address} return None # 流程路由器注册表 WORKFLOW_ROUTER { workflow_support: workflow_support_flow, workflow_order: workflow_order_flow } # # 2. 上下文操作辅助函数 # def get_context(room_id, sender_id): ctx_str redis_client.get(fuser_context:{room_id}:{sender_id}) return json.loads(ctx_str) if ctx_str else {current_step: 0} def update_context(room_id, sender_id, context_data): # 更新上下文并设置 10 分钟闲置超时防死锁 redis_client.setex(fuser_context:{room_id}:{sender_id}, 600, json.dumps(context_data)) def clear_context(room_id, sender_id): redis_client.delete(fuser_context:{room_id}:{sender_id}) # # 3. 统一网关与状态机调度层 # app.route(/group_webhook, methods[POST]) def workflow_gateway(): data request.json instance_guid data.get(instance_guid) room_id data.get(RoomId) msg_type data.get(MsgType) if not instance_guid or not room_id or msg_type ! text: return jsonify({status: success}) content data.get(Content, ) sender_id data.get(FromUserName) mentioned_list data.get(mentioned_list, []) # 过滤未 机器人的消息但如果用户正在流程中不强制要求 context get_context(room_id, sender_id) is_in_workflow context.get(current_step, 0) 0 if BOT_USER_ID not in mentioned_list and not is_in_workflow: return jsonify({status: success}) # 剥离耗时任务进入异步状态机调度 threading.Thread(targetdispatch_workflow, args(instance_guid, room_id, sender_id, content, context)).start() return jsonify({status: success}) def dispatch_workflow(instance_guid, room_id, sender_id, content, context): 根据群绑定获取业务流程并驱动状态机 # 1. 查询该群绑定的主流程 (运营人员可提前将映射写入 Redis) # 此处假设群默认绑定了支持流程实际应查 Redis: redis_client.get(fgroup_workflow:{room_id}) bound_workflow_name redis_client.get(fgroup_workflow:{room_id}) or workflow_support workflow_func WORKFLOW_ROUTER.get(bound_workflow_name) # 2. 执行多步流转逻辑 reply_text None if workflow_func: # 清洗掉可能存在的 机器人 文本 clean_content content.replace(f{BOT_USER_ID}, ).strip() # 退出机制允许客户随时终止流程 if clean_content in [退出, 取消, 终止]: clear_context(room_id, sender_id) reply_text 已为您安全终止当前业务流程。 else: # 将上下文塞入对应的业务引擎进行计算 reply_text workflow_func(room_id, sender_id, clean_content, context) # 3. 兜底与回传 if not reply_text and not (context.get(current_step, 0) 0): reply_text f您好本群当前运行【{bound_workflow_name}】系统。请输入指令发起任务。 if reply_text: headers {Content-Type: application/json, X-Nebula-Key: API_KEY} payload { instance_guid: instance_guid, touser: room_id, text: {content: f{sender_id} {reply_text}} } requests.post(SEND_TEXT_URL, jsonpayload, headersheaders) if __name__ __main__: app.run(port5000)四、 架构进阶与防坑指南会话超时机制防死锁状态机最怕的就是“客户走到一半消失了”。例如客户走到“输入收货地址”这一步就去开会了。上面的代码中利用了redis_client.setex(..., 600, ...)强制赋予 10 分钟 TTL一旦超时流程自动重置避免下一次客户正常闲聊时被误判为输入地址。多模态流程节点在某些业务流程中特定节点可能要求客户发一张凭证图片如报修流程的第三步。这时网关层就需要放行image类型的数据包。建议仔细研读 星云API开放文档 中对于图片和文件类消息结构体的描述以便在流程中顺畅地提取PicUrl或MediaId。分布式锁防连击如果客户网络卡顿连续点了两下“下单”可能会导致业务引擎同时推进两步引发报错。此时我们前面章节讲过的“基于 MsgId 的 Redis 去重锁”就显得尤为关键了。引入了“上下文记忆”和“状态机”后你的企业微信机器人就不再是单脑的传话筒而是一个可以挂载无数微服务的全能型中台助理。想要搭建如此高可用、不丢消息的基础收发环境请前往 星云API官网 注册企业级实例保障你的长连接服务永不掉线
返回列表