如何在Dialogflow对话中仅向用户询问一次电话号码?
解决Dialogflow仅询问一次电话号码的问题
你遇到的核心问题是没有持久化存储用户已提供的电话号码,之前的代码只是检查当前意图的槽位参数,一旦会话流程切换,这个参数不会自动保留,导致每次进入意图都会重新索要号码。下面是具体的解决方案,结合Dialogflow上下文(Context)和Webhook实现一次性收集:
核心思路
利用Dialogflow的会话上下文来存储已收集的电话号码,上下文会在会话期间持续存在。之后所有需要用到号码的意图,先检查上下文里是否已有号码:
- 如果有,直接跳过询问逻辑
- 如果没有,才触发号码收集
具体实现步骤
1. 在Dialogflow控制台配置上下文
首先创建一个会话级别的上下文(比如命名为phone_collected),用来标记用户已提供电话号码。你可以在意图的"输出上下文"里设置,或者通过Webhook代码动态添加。
2. 修改Webhook代码
下面是更新后的代码,包含号码收集、上下文存储和后续意图的检查逻辑:
const functions = require('firebase-functions'); const { WebhookClient } = require('dialogflow-fulfillment'); exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => { const agent = new WebhookClient({ request, response }); // 处理电话号码收集的意图(比如你原来的fees_intent) function handlePhoneCollection(agent) { // 先检查上下文是否已经保存了号码 const existingPhone = agent.contexts.get('phone_collected')?.parameters?.phone; if (existingPhone) { // 已有号码,直接使用,不需要再问 agent.add(`我已经有你的电话号码:${existingPhone},接下来可以继续处理你的需求了`); return; } // 没有号码,检查当前槽位是否有输入 const phoneNumber = agent.parameters.phone; if (!phoneNumber) { agent.add('请提供你的电话号码'); } else { // 保存号码到上下文,设置生命周期为会话结束前有效(比如设置为999,代表长期有效) agent.context.set({ name: 'phone_collected', lifespan: 999, parameters: { phone: phoneNumber } }); agent.add(`好的,我已经记下你的电话号码:${phoneNumber}`); } } // 示例:其他需要用到号码的意图 function anotherIntentHandler(agent) { const savedPhone = agent.contexts.get('phone_collected')?.parameters?.phone; if (!savedPhone) { // 如果没有号码,触发号码收集意图(可以用agent.setFollowupEvent跳转到收集意图) agent.setFollowupEvent('collect_phone_event'); } else { // 已有号码,直接处理业务逻辑 agent.add(`使用你的电话号码 ${savedPhone} 处理请求`); } } // 意图映射 let intentMap = new Map(); intentMap.set('fees_intent', handlePhoneCollection); intentMap.set('another_intent', anotherIntentHandler); // 替换成你的其他意图名称 agent.handleRequest(intentMap); });
3. 补充说明
- 上下文生命周期:设置
lifespan:999可以让上下文在整个会话期间保持有效,除非手动清除或者会话超时。 - 跨会话保存:如果需要在用户下次会话时仍然保留号码,就需要把号码存储到Firebase数据库(Realtime Database或Firestore),而不是仅依赖上下文。示例代码如下:
// 保存号码到Firestore(需要先初始化Firebase Admin) const admin = require('firebase-admin'); admin.initializeApp(); const db = admin.firestore(); // 在收集到号码时保存 await db.collection('users').doc(agent.userId).set({ phone: phoneNumber }); // 在其他意图中读取 const userDoc = await db.collection('users').doc(agent.userId).get(); const savedPhone = userDoc.data()?.phone; - 触发收集的时机:如果其他意图需要号码但用户还没提供,可以通过
agent.setFollowupEvent跳转到号码收集意图,确保流程连贯。
关键修正点
你之前的代码只检查了当前意图的phone参数,没有将号码持久化到上下文或数据库,导致每次进入意图都会重新检查,而参数不会在意图间自动保留。通过上下文存储后,后续意图可以直接读取已保存的号码,避免重复询问。
内容的提问来源于stack exchange,提问作者Bhrat Brij




