Google Assistant 中 Intent 间传递 Context 为 null
结论
agent.setContext() 和 agent.getContext() 的写法没有明显问题。Google Assistant 中的 Context 变成 null,通常不是名称格式的问题,而是因为 payBill 请求与创建 Context 时的请求不属于同一个 Dialogflow 会话。
Dialogflow Context 只在当前 session 中有效。请确认:
getBillingInfo没有结束 Assistant 会话。payBill在同一次对话中触发。payBillIntent 已将billing-context配置为 Input Context。- 设置和读取 Context 时使用的名称完全相同。
- 异步请求完成后,Webhook 返回的
outputContexts确实包含该 Context。
推荐修正
统一定义 Context 名称,并通过 agent.parameters 获取当前 Intent 的参数:
const BILLING_CONTEXT = 'billing-context';
function getBillingInfoHandler(agent) {
const phoneNumber = agent.parameters['phone-number'];
const url = 'https://testapi.io/api/shwej//getBillingInfo';
return new Promise((resolve, reject) => {
https.get(url, (res) => {
let body = '';
res.on('data', (chunk) => {
body += chunk;
});
res.on('end', () => {
try {
const apiResponse = JSON.parse(body);
const billAmount = apiResponse.billing_amount;
agent.setContext({
name: BILLING_CONTEXT,
lifespan: 5,
parameters: {
phoneNumber,
billAmount
}
});
agent.add(
`Your bill for ${phoneNumber} is ${billAmount} ₹`
);
agent.add(new Suggestion('Click to Pay'));
resolve();
} catch (error) {
console.error('Invalid API response:', error);
agent.add('Unable to read billing information.');
reject(error);
}
});
res.on('error', (error) => {
console.error('Error calling the API:', error);
agent.add('Error occurred while calling API.');
reject(error);
});
}).on('error', (error) => {
console.error('HTTPS request failed:', error);
agent.add('Error occurred while calling API.');
reject(error);
});
});
}
function payBillHandler(agent) {
const billingContext = agent.getContext(BILLING_CONTEXT);
if (!billingContext) {
agent.add(
'Billing information is no longer available. Please retrieve the bill again.'
);
return;
}
const { phoneNumber, billAmount } = billingContext.parameters || {};
if (!phoneNumber || billAmount === undefined) {
agent.add('Billing information is incomplete. Please retrieve the bill again.');
return;
}
agent.add('Your payment is successful!');
agent.add(`Phone Number: ${phoneNumber}`);
agent.add(`Amount paid: ${billAmount} ₹`);
}
lifespan: 50 可以延长 Context 的生命周期,但通常没有必要。它表示 Context 可以持续匹配 Intent 的轮数,并不代表 Context 能跨会话永久保存。无论这个值多大,只要会话结束,Context 就会消失。
检查 Dialogflow Intent 配置
请在 Dialogflow ES 控制台中检查以下设置:
getBillingInfo
- 不要启用结束对话的选项,例如
Set this intent as end of conversation。 - 确认 Webhook 已启用。
- Webhook 返回后,应生成名为
billing-context的 Output Context。
payBill
- 将
billing-context添加为 Input Context。 - 添加能够匹配建议按钮文本的训练短语,例如:
Click to Pay
点击建议按钮后,Assistant 会发送一条新的用户文本消息,而不是直接调用 payBillHandler()。只有这条文本匹配到 payBill Intent,处理函数才会执行。
如果按钮文本无法稳定匹配训练短语,可以换成更自然、明确的表达:
agent.add(new Suggestion('Pay bill'));
然后在 payBill Intent 中加入:
Pay bill
确认是否发生了会话切换
记录两个请求中的 session:
console.log('Current session:', request.body.session);
console.log(
'Output contexts:',
JSON.stringify(request.body.queryResult.outputContexts || [])
);
正常情况下,getBillingInfo 和随后触发的 payBill 应该具有相同的 request.body.session。如果两者不同,说明 Assistant 已开启新会话,之前的 Context 也就无法读取。
常见原因包括:
getBillingInfo被配置为结束对话。- 第一个响应使 Assistant 关闭了会话。
- 用户退出后重新调用 Action。
- 测试时重新启动了模拟器会话。
payBill通过其他入口或新的调用触发。
注意事项
Context 适合保存同一次对话中的临时状态,不适合保存真实的支付数据。实际支付流程应当:
- 在服务端生成交易或账单标识。
- 将账单状态保存在数据库中。
- 根据经过验证的用户身份和交易标识重新查询金额。
- 不要只根据 Context 中的
phoneNumber和billAmount执行扣款。
如果两个请求的 session 完全相同,但 billing-context 仍然不存在,请重点检查 getBillingInfo 的 Webhook 响应日志。只有响应中的 outputContexts 实际包含 .../contexts/billing-context,才能确认 Context 已成功写入。
备注:内容仅供参考。
