如何使用Twilio WhatsApp API为聊天机器人保留会话状态
解决Twilio机器人的会话状态保留问题
你遇到的问题非常典型——因为HTTP是无状态协议,Twilio每次推送用户消息都是一个全新的POST请求,默认情况下机器人根本没法记住之前的对话上下文。要搞定这个问题,核心思路就是把每个用户的会话状态单独存储起来,下面给你几个适配当前技术栈的落地方案:
方案1:内存存储(快速开发测试用)
如果只是处于开发调试阶段,可以用一个简单的JS对象临时存储用户状态,用用户的From号码作为唯一标识(每个用户的WhatsApp号码都是独一无二的,刚好能对应会话)。
修改你的whatsapp/main.js:
const accountSid = "accountSid"; const authToken = "authToken"; const client = require("twilio")(accountSid, authToken); const MessagingResponse = require("twilio").twiml.MessagingResponse; // 内存存储会话状态,仅用于开发测试!生产环境绝对不能用 const userSessions = {}; function sendResponse(req, res, next) { const userNumber = req.body.From; const userMessage = req.body.Body.trim().toLowerCase(); const twiml = new MessagingResponse(); // 获取用户当前会话状态,默认是"空闲" const currentState = userSessions[userNumber] || "idle"; if (currentState === "idle") { if (userMessage === "show me movies") { twiml.message("in what language?"); // 更新状态:等待用户输入电影语言 userSessions[userNumber] = "awaiting_movie_language"; } else { twiml.message("Hi there! Type 'show me movies' to get started."); } } else if (currentState === "awaiting_movie_language") { // 这里可以扩展逻辑,比如调用电影API获取对应语言的影片列表 twiml.message(`Got it! Showing you *${userMessage}* movies right away.`); // 重置会话状态为空闲 userSessions[userNumber] = "idle"; } res.writeHead(200, { "Content-Type": "text/xml" }); res.end(twiml.toString()); } module.exports = { sendResponse };
⚠️ 注意:内存存储的致命缺点是服务器重启后所有状态都会丢失,而且没法支持多服务器部署(状态不共享),所以只适合开发调试用。
方案2:Redis存储(生产环境推荐)
生产环境下,首推用Redis这种内存数据库存储会话状态——它速度快,支持设置过期时间(自动清理闲置会话),还能在多服务器之间共享状态,完美适配生产场景。
步骤1:安装Redis依赖
npm install redis
步骤2:修改whatsapp/main.js集成Redis
const accountSid = "accountSid"; const authToken = "authToken"; const client = require("twilio")(accountSid, authToken); const MessagingResponse = require("twilio").twiml.MessagingResponse; const redis = require("redis"); // 创建Redis客户端,替换成你的Redis实际地址 const redisClient = redis.createClient({ url: "redis://localhost:6379" }); redisClient.connect().catch(console.error); async function sendResponse(req, res, next) { const userNumber = req.body.From; const userMessage = req.body.Body.trim().toLowerCase(); const twiml = new MessagingResponse(); // 从Redis获取用户当前状态,默认是"idle" const currentState = await redisClient.get(`session:${userNumber}`) || "idle"; if (currentState === "idle") { if (userMessage === "show me movies") { twiml.message("in what language?"); // 存储状态并设置2小时过期,避免闲置会话占用资源 await redisClient.setEx(`session:${userNumber}`, 7200, "awaiting_movie_language"); } else { twiml.message("Hi there! Type 'show me movies' to get started."); } } else if (currentState === "awaiting_movie_language") { twiml.message(`Got it! Showing you *${userMessage}* movies right away.`); // 清理当前会话状态 await redisClient.del(`session:${userNumber}`); } res.writeHead(200, { "Content-Type": "text/xml" }); res.end(twiml.toString()); } module.exports = { sendResponse };
关键注意点
- 始终用
From号码作为会话的唯一标识,确保不同用户的上下文不会混淆 - 生产环境绝对不能用内存存储,必须用Redis、MongoDB这类持久化/分布式存储方案
- 给会话状态设置合理的过期时间,自动清理长期闲置的会话,节省服务器资源
这样改造后,你的机器人就能完美记住用户的上下文了——比如用户回复"english"时,机器人会立刻明白这是针对「电影语言」的回复,而不是一个全新的独立请求。
内容的提问来源于stack exchange,提问作者obiwankenoobi
相关产品推荐
相关产品推荐

