WhatsApp Cloud API订单机器人如何关联历史提问与用户回复
问题根因
WhatsApp Cloud API的webhook本身只负责推送用户新发送的消息,不会主动回传机器人历史发送内容、对话流程进度这类上下文信息。你当前的代码是无状态实现,没有存储每个用户的对话进度和已收集信息,自然无法把用户当前回复和之前的提问关联起来。
多轮下单流程实现方案
核心要补的是服务端会话状态管理逻辑,所有上下文、流程节点都需要你自己在服务端存储维护,具体实现分4步:
- 搭建会话存储层
初期调试可以直接用内存Map做临时存储,正式上线替换成Redis、MySQL这类持久化存储即可。存储以用户的WhatsApp账号(即webhook payload里的from字段)作为唯一主键,每个用户的会话数据至少存三类信息:- 当前流程节点:标记用户现在走到下单流程的哪一步,比如「初始欢迎、选商品、选数量、填地址、确认订单」
- 已收集的订单信息:比如用户选的商品ID、购买数量、收货地址、联系电话等
- 会话更新时间:用来做过期判断,比如超过30分钟无回复就重置会话,避免脏数据干扰
- 预定义流程状态流转规则
把完整下单流程拆成固定的顺序节点,每个节点明确三个规则:合法的用户输入格式、校验通过后要跳转的下一个节点、当前节点要发送给用户的引导内容。基础流程示例:- 用户首次发消息:处于初始节点,返回可购商品列表,节点更新为「等待用户选商品」
- 收到用户商品选择回复:校验商品是否存在,存下选中的商品,发送数量填写提示,节点更新为「等待用户填数量」
- 收到用户数量回复:校验是否为合法正整数,存下数量,发送地址填写提示,节点更新为「等待用户填地址」
- 按这个逻辑走完所有信息收集步骤,最终生成订单,重置会话状态,发送下单成功通知
- 改造webhook消息处理逻辑
每次收到用户消息,先拿用户手机号查询对应的会话记录:- 查不到会话/会话已过期:按初始流程处理,创建新的会话记录,返回商品列表
- 查到有效会话:根据当前存储的流程节点,判断用户当前回复对应哪个待回答问题,先做输入合法性校验:校验通过就把用户输入存到订单信息里,更新流程节点,发送下一段引导;校验不通过就发送错误提示,让用户重新输入当前节点要求的内容,不跳转节点
- 发消息后同步更新会话状态
每次调用接口给用户发完引导消息,立刻同步更新存储里的用户会话节点和更新时间,不要等下一次收到用户消息再更新,避免状态错乱
最小改造代码示例
先加会话存储和流程节点定义:
// 临时内存存储,正式环境替换为Redis/MySQL const userSessions = new Map() // 会话过期时间:30分钟 const SESSION_TIMEOUT = 30 * 60 * 1000 // 下单流程节点枚举 const OrderStep = { INIT: 'init', SELECT_GOODS: 'select_goods', SELECT_NUM: 'select_num', FILL_ADDRESS: 'fill_address', CONFIRM: 'confirm' }
然后修改webhook里的消息处理部分,替换原来固定返回Ack的逻辑:
// 提取到from、msg_body、phone_number_id之后,先查询用户会话 const currentTime = Date.now() let userSession = userSessions.get(from) // 会话不存在或过期,初始化新会话 if (!userSession || currentTime - userSession.updateAt > SESSION_TIMEOUT) { userSession = { currentStep: OrderStep.INIT, orderInfo: {}, updateAt: currentTime } } let replyText = '' // 根据当前节点处理用户回复 switch (userSession.currentStep) { case OrderStep.INIT: replyText = '欢迎下单,在售商品如下:\n1. 商品A 售价99元\n2. 商品B 售价199元\n请回复对应数字选择要购买的商品' userSession.currentStep = OrderStep.SELECT_GOODS break case OrderStep.SELECT_GOODS: const goodsId = msg_body.trim() if (!['1', '2'].includes(goodsId)) { replyText = '输入无效,请回复1或2选择对应商品' break } userSession.orderInfo.goodsId = goodsId replyText = '请输入要购买的数量(需为大于0的正整数)' userSession.currentStep = OrderStep.SELECT_NUM break case OrderStep.SELECT_NUM: const num = Number(msg_body.trim()) if (!Number.isInteger(num) || num <= 0) { replyText = '数量输入无效,请输入大于0的正整数' break } userSession.orderInfo.buyNum = num replyText = '请输入您的详细收货地址和联系电话' userSession.currentStep = OrderStep.FILL_ADDRESS break // 剩余节点按相同逻辑扩展即可 } // 更新会话最后修改时间,存回存储 userSession.updateAt = currentTime userSessions.set(from, userSession) // 调用WhatsApp接口发送回复 axios({ method: "POST", url: "https://graph.facebook.com/v12.0/" + phone_number_id + "/messages?access_token=" + token, data: { messaging_product: "whatsapp", to: from, text: { body: replyText }, }, headers: { "Content-Type": "application/json" }, });
实操提示:不用尝试依赖消息ID(payload里的wamid字段)做上下文关联,WhatsApp不会自动将机器人发送的消息和用户的回复做绑定回传,自行维护会话状态是最稳定的方案。如果要降低用户输入错误率,可以用WhatsApp官方的交互式消息(列表选择、快捷回复按钮),用户点击后会回传你预先设置的选项ID,比纯文本输入的容错性高很多。
内容的提问来源于stack exchange,提问作者Manspof
相关产品推荐
相关产品推荐

