如何从 webhook 触发 actions.intent.INTENT_NAME
结论
问题不在 Python 或 ngrok,而是 webhook 的返回格式和测试方式不对:
- Dialogflow v2 的
WebhookResponse不支持顶层data。Google Assistant 专用响应必须放在顶层payload.google中。由于当前响应无法解析,actions.intent.TRANSACTION_REQUIREMENTS_CHECK并未发送给 Assistant。 Int2也必须启用 webhook fulfillment。否则,即使事件成功匹配,Dialogflow 也不会再次调用后端。- 交易流程不能通过 Actions Simulator 验证,需要在登录了测试账号的 Assistant Android 或 iOS 真机上测试。
- webhook 不能像发送普通 HTTP 请求那样直接“调用”某个
actions.intent.*。它需要在当前响应中返回systemIntent,由 Assistant 执行系统操作。操作完成后,Assistant 会通过 Dialogflow event 进入对应的 intent。 - 如果是现在新建的项目,还要注意旧版 Conversational Actions 已经停止服务。下面的方案只适用于当时仍支持该 API 的既有项目,或用于排查历史代码,无法让已经下线的平台恢复使用。
为什么没有收到检查结果
Dialogflow 已经给出了明确的错误信息:
Cannot find field: data in message google.cloud.dialogflow.v2.WebhookResponse
当前代码返回的是 Dialogflow v1 风格的结构:
{
"data": {
"google": {}
}
}
Dialogflow v2 要求使用下面的结构:
{
"payload": {
"google": {}
}
}
Dialogflow 无法解析原来的响应,因此请求在 Assistant 开始交易检查之前就失败了。Simulator 中显示的:
Webhook error (206)
只是 Assistant 对 webhook 解析错误的反馈,不代表交易检查已经执行。
修正后的 webhook
from flask import Flask, request, jsonify
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
@app.route("/", methods=["POST"])
def index():
data = request.get_json(silent=True) or {}
query_result = data.get("queryResult", {})
intent = query_result.get("intent", {}).get("displayName")
if intent == "Int1":
return jsonify({
"payload": {
"google": {
"expectUserResponse": True,
"isSsml": False,
"noInputPrompts": [],
"systemIntent": {
"intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK",
"data": {
"@type": (
"type.googleapis.com/"
"google.actions.v2.TransactionRequirementsCheckSpec"
),
"paymentOptions": {
"actionProvidedOptions": {
"displayName": "VISA-1234",
"paymentType": "PAYMENT_CARD"
}
}
}
}
}
}
})
if intent == "Int2":
payload = (
data.get("originalDetectIntentRequest", {})
.get("payload", {})
)
# 实际结果通常位于 payload.inputs[*].arguments[*] 中。
# 建议先记录完整 payload,再按收到的结构提取 resultType。
result_type = find_transaction_result(payload)
if result_type == "CAN_TRANSACT":
message = "Transaction requirements check passed."
else:
message = (
"Transaction requirements check result: "
f"{result_type or 'UNKNOWN'}"
)
return jsonify({
"fulfillmentText": message
})
return jsonify({
"fulfillmentText": "Unsupported intent."
})
def find_transaction_result(payload):
for input_item in payload.get("inputs", []):
for argument in input_item.get("arguments", []):
if argument.get("name") == "TRANSACTION_REQUIREMENTS_CHECK_RESULT":
extension = argument.get("extension", {})
return extension.get("resultType")
return None
if __name__ == "__main__":
app.run(debug=True)
需要改成:
"payload": {
"google": {
"systemIntent": {}
}
}
不能继续使用:
"data": {
"google": {
"systemIntent": {}
}
}
Dialogflow 配置步骤
1. 配置 Int1
保留用户训练语句,例如:
Yes, I want
然后启用:
Enable webhook call for this intent
Int1 的 webhook 响应用于返回 systemIntent。
2. 配置 Int2
将 event 设置为:
actions_intent_TRANSACTION_REQUIREMENTS_CHECK
同时为 Int2 启用:
Enable webhook call for this intent
如果没有启用,Assistant 返回检查结果后,Dialogflow 即使匹配到了 Int2,也不会把请求转发给 Python 后端。
3. 从原始请求读取结果
交易检查结果不一定会通过普通的 queryResult.parameters 传入。在这个版本的 Google Assistant 集成中,结果通常位于:
originalDetectIntentRequest.payload.inputs[].arguments[]
参数名通常是:
TRANSACTION_REQUIREMENTS_CHECK_RESULT
可以在结果对象中检查:
extension.resultType
常见的成功状态是:
CAN_TRANSACT
字段的实际位置和结果值仍要以真机发送给 webhook 的请求为准。调试时可以记录经过脱敏的完整 originalDetectIntentRequest.payload,但不要记录支付凭据或其他敏感信息。
如何从 webhook 触发 actions.intent.INTENT_NAME
actions.intent.* 是 Assistant 平台的系统 intent,不是后端可以随意调用的 Dialogflow intent。完整流程如下:
用户输入
→ Dialogflow 匹配 Int1
→ Dialogflow 调用 webhook
→ webhook 返回 systemIntent
→ Assistant 执行系统操作
→ Assistant 把结果作为 actions.intent.* 返回 Dialogflow
→ 对应 event 匹配 Int2
→ Dialogflow 调用 Int2 的 webhook
因此,这里的“触发”系统 intent,是指返回下面的响应:
{
"payload": {
"google": {
"expectUserResponse": true,
"systemIntent": {
"intent": "actions.intent.INTENT_NAME",
"data": {
"@type": "对应的 protobuf 类型"
}
}
}
}
}
返回 followupEventInput、修改 queryResult,或者直接向自己的 webhook 发送请求,都不能代替 Assistant 的系统交易流程。
ngrok 和 Simulator 的影响
ngrok 通常不是问题,但需要满足这些条件:
- Dialogflow fulfillment URL 使用有效的 HTTPS 地址;
- ngrok 隧道保持在线,URL 没有变化;
- 请求能在平台规定的时间内返回;
- 响应的
Content-Type是application/json; - webhook 没有发生重定向,也没有被认证页面或本机防火墙阻断;
- Flask 路由与 Dialogflow 中配置的 URL 完全一致。
Actions Simulator 不适合验证交易能力。交易检查可能依赖真实设备、测试账号、地区、账号设置和支付配置。测试时应使用支持 Google Assistant 的 Android 或 iOS 设备,并确认设备登录的是项目配置中的测试账号。
先修正 data 和 payload 的格式问题。确认 Dialogflow 能正确解析 webhook 响应后,再用真机验证交易检查以及 Int2 的回调。
备注:内容仅供参考。
