官网友情链接 wechatapi.net
微信二次开发系统刚开始运行时,开发人员通常最关注的是“消息能不能收到”。
客户发一条微信消息,系统能够通过个人微信API 接收,然后触发自动回复、AI 分析、CRM 记录或者工单流程,只要整条链路跑通,就算完成了第一阶段。
但真正进入生产环境以后,很快会遇到一个比“收不到消息”更隐蔽的问题:
同一条消息可能被处理不止一次。
消息重复进入系统以后,最直观的结果就是机器人重复回复。
客户发一句:
“把资料发我一下。”
机器人正常回复:
“好的,这是资料入口。”
几秒钟后,同一条消息因为重复消费再次被处理,机器人又发了一遍完全相同的内容。
如果只是偶尔重复一次,看起来只是体验问题。
但一旦消息后面还关联:
工单创建;
CRM 写入;
客户标签;
任务提醒;
Webhook;
AI 调用;
重复消息就可能产生一连串重复业务动作。
所以微信机器人真正进入生产环境以后,消息去重必须成为基础能力。
WechatApi 可以作为微信API 和个人微信API 接入层,把微信私聊、微信群、文件、图片和消息事件接入业务系统。但消息进入以后是否重复、是否已经处理过、是否允许再次执行,需要本地系统建立完整的幂等机制。
一、消息为什么会重复
很多人会问:
微信消息不是客户只发了一次吗,为什么系统会收到多次?
原因很多。
第一,网络重试。
某个消息事件已经成功到达服务端,但响应因为网络原因没有及时返回,消息源可能再次尝试推送。
第二,任务重试。
消息已经成功入库,但后续处理任务执行失败,任务系统重新执行时,如果没有步骤状态,就可能重复处理前面的动作。
第三,程序重启。
系统消费了一条消息,但业务状态还没完全提交,服务突然重启,恢复后可能重新消费。
第四,多通道同步。
某些系统既有实时事件,又有历史同步任务。如果缺少统一去重机制,同一条消息可能从不同入口进入。
所以生产系统不能假设:
“一条消息永远只来一次。”
更安全的假设应该是:
“任何消息都有可能被重复处理。”
二、消息入库就应该做第一层去重
第一层是消息级幂等。
每条微信消息最好都有稳定消息标识。
消息进入系统以后,先检查:
这条消息是否已经存在。
如果已经存在,则不重复创建业务消息记录。
如果消息源没有直接提供一个足够稳定的唯一标识,也可以结合:
所属账号;
会话;
消息时间;
发送人;
消息类型;
原始消息标识
构造业务唯一键。
但需要注意:
不要仅仅使用“消息内容”去重。
因为客户可能真的连续发送两次“好的”。
内容一样,不代表是同一条消息。
三、只做数据库唯一约束还不够
很多系统认为:
消息表加一个唯一索引,就已经解决重复问题。
其实这只是第一层。
假设同一条消息只入库一次,但它生成了一个自动回复任务。
自动回复任务第一次执行时:
消息已经发出。
但执行到“写成功日志”这一步时服务异常。
任务系统认为任务失败,于是重试。
第二次执行时,如果只检查消息表,没有检查“这条回复是不是已经发过”,仍然会再次发送。
所以还需要任务幂等和业务结果幂等。
四、一个完整消息处理链路应该分步骤
例如客户发送:
“文件上传失败。”
系统处理流程可能是:
第一步:保存消息。
第二步:识别客户。
第三步:加载上下文。
第四步:匹配规则。
第五步:判断是否自动回复。
第六步:创建回复候选。
第七步:真正发送。
第八步:生成工单候选。
第九步:更新 CRM。
这些步骤应该有自己的执行状态。
如果第八步失败,重试时应该从第八步继续。
而不是从第一步重新跑。
否则:
回复可能重复;
AI 可能重复调用;
CRM 可能重复写入;
工单可能重复创建。
五、自动回复怎么做结果幂等
自动回复属于客户可见动作,必须格外谨慎。
可以为每次自动回复生成业务唯一标识。
例如:
原消息 ID + 规则版本 ID。
如果这组组合已经产生过成功发送记录,就不能再次发送。
AI 回复也可以使用:
会话 ID + 原消息 ID + AI任务 ID。
这样即使后台任务重试,也不会再次向客户发送相同内容。
六、一个具体例子
客户 A 在 10:00:00 发送:
“你们几点下班?”
消息 ID 为 M1001。
WechatApi 将消息接入业务系统。
系统创建消息记录 M1001。
随后规则 R12 命中。
生成自动回复任务 T5001。
10:00:01,机器人成功发送:
“服务时间为 9:00-18:00。”
但在写入“任务成功”状态时数据库连接异常。
任务系统看到 T5001 仍然失败,于是 10 秒后重试。
如果系统没有结果幂等,第二次执行会再次发送。
如果有发送记录:
M1001 + R12 = 已成功发送。
第二次执行时直接跳过发送步骤,继续补写任务状态。
最终客户只收到一次回复。
这就是结果幂等的价值。
七、微信群机器人更容易出现重复影响
私聊里重复回复影响一个客户。
微信群里重复回复会影响整个群。
客户在群里问:
“活动几点开始?”
机器人连续回复两次。
整个群里所有成员都会看到。
如果群消息比较密集,重复机器人内容很容易让群体验迅速下降。
所以微信群自动回复必须严格做消息去重和发送去重。
八、工单也必须防重复
同一条售后消息如果被处理两次,可能生成两个工单。
例如:
“登录一直失败。”
第一次生成工单 W1001。
任务重试以后又生成 W1002。
客服会以为客户有两个问题。
所以工单候选可以使用:
客户 + 原始消息 + 问题类型
作为重复判断的一部分。
如果已经存在候选,则新处理过程应该补充到原候选,而不是重复创建。
九、CRM 写入也要考虑幂等
客户在微信里说:
“明天下午联系我。”
系统识别到跟进任务。
如果消息重复处理两次,就可能在 CRM 里创建两个完全一样的待办。
所以 CRM 写入最好带有来源业务 ID。
例如:
source_type = wechat_message
source_id = M1001
CRM 侧或者中间层都能据此去重。
十、文件消息也会重复
图片、文件、语音消息重复进入以后,如果不去重,会产生:
重复下载;
重复存储;
重复 OCR;
重复语音转写。
这会增加存储和计算成本。
文件资源同样可以根据消息 ID 和资源标识建立唯一关系。
十一、重复消息不要直接完全丢弃
虽然重复消息不需要重新执行业务动作,但“重复出现”本身仍然有分析价值。
系统可以记录:
首次收到时间;
重复次数;
最后重复时间;
重复来源。
如果某段时间重复率突然升高,可能意味着:
消息回调响应异常;
任务消费异常;
系统重试策略过于激进。
这可以作为系统健康监控指标。
十二、补偿任务也要幂等
管理员在异常中心点击:
“重新处理。”
同时定时补偿任务也正好执行。
如果两条路径同时处理同一消息,就可能产生并发重复。
所以补偿任务开始前也要检查:
当前业务结果是否已经完成。
如果已完成,就直接关闭补偿任务。
十三、并发情况下还要防止竞态
假设同一条消息几乎同时被两个 Worker 消费。
两个 Worker 都查询:
“有没有处理记录?”
此时都查不到。
然后同时执行发送。
这就是典型竞态。
所以幂等不能只靠“先查再写”。
最好结合:
数据库唯一约束;
分布式锁;
原子状态更新。
确保只有一个执行者能够获得发送权。
十四、WechatApi 和业务系统的边界
WechatApi 负责:
微信消息接入;
私聊;
微信群;
文件;
语音;
相关事件。
本地系统负责:
消息唯一性;
任务幂等;
业务结果幂等;
重试;
补偿;
并发控制;
日志。
WechatApi 解决“消息怎么进来”。
业务系统解决“同一件事只能真正做一次”。
十五、日志如何设计
出现重复问题时,系统应该能够回答:
这条消息第一次什么时候收到;
一共收到几次;
生成过几个任务;
哪次真正执行了发送;
后续重试为什么没有再次发送;
有没有生成工单;
有没有写 CRM。
只有链路完整,问题才能快速定位。
十六、数据看板可以看重复率
除了消息量、回复量以外,还可以统计:
消息重复率;
任务重试率;
幂等拦截次数;
重复工单拦截数。
这些指标非常适合判断系统运行质量。
如果某天消息重复率从 0.1% 升到 5%,就需要重点排查。
十七、总结
微信机器人真正进入生产环境以后,最危险的问题不一定是“消息没收到”。
有时候是:
消息收到了两次,而系统把它当成两件事做了两遍。
WechatApi 可以作为个人微信API 接入层,让微信消息、微信群、文件和事件进入业务系统。
但本地系统必须进一步建立:
消息去重;
任务幂等;
结果幂等;
并发控制;
补偿幂等;
重复日志。
微信二次开发做得越深入,越应该默认每一个外部事件都有可能重复。
只有系统能够保证:
消息可以重复进来,但客户可见动作只执行一次;
微信自动回复、AI 微信机器人、CRM、工单和 Webhook 才能真正稳定运行。