在执行代码中使用启用测试功能和 API 选项和 agent.setFollowupEvent() 时聊天机器人中断

Chatbot breaks when using Enable beta features and APIs option and agent.setFollowupEvent() in the fulfillment code

情况:我正在开发聊天机器人。今天我注意到履行代码没有按预期工作。实现代码非常基本,主要是触发自定义后续事件(例如 agent.setFollowupEvent('someCustomName')),然后触发特定的意图。

我正在使用 Google 云的内联编辑器实现,因此 webhook 服务器在 Google 云中。

我还在使用 2 个集成(DF Messenger 和 FB Messenger)。

一切正常,但今天我经常看到错误(详情如下)。

我今天做的导致问题的步骤:

  1. 因为我需要进一步开发机器人并且 DF Messenger 集成已经发布,我在项目设置中创建了 2 个不同的环境:“生产”和“开发”。
  2. 我在集成设置中为每个集成设置了适当的环境——DF Messenger 集成的“生产”和 FB Messenger 集成的“开发”(FB 集成尚未 public)。
  3. 测试了这两个集成,发现它们忽略了环境选择,并且它们实际上与草案版本一起工作(无论草案中的当前意图、实体等是什么)。
  4. 我读到在项目设置中启用选项 'Enable beta features and APIs' 可能会成功(为特定集成提供正确的环境)。所以我启用了这个选项,集成开始按预期工作(每个集成都有自己的环境)。
  5. 所以,一切似乎都很好,直到我发现如果我启用 'Enable beta features and APIs' 选项,这会导致另一个问题 - 见下文。

'The real' 问题:在执行代码

中使用启用 beta 功能和 API 选项和 agent.setFollowupEvent() 时,机器人会中断

我的机器人使用的是非常简单的事件触发。我认为下面的代码部分是不言自明的,所以这里是:

  // Dummies
  function D_99_01_01(agent) {
    agent.add(`...`);
    agent.setFollowupEvent('custom_990101');
  }
  
  let intentMap = new Map();
  
  // Dummies
  intentMap.set('02.01 > some intent to trigger the event (D99.01.01)', D_99_01_01);
  
  agent.handleRequest(intentMap);

最简单的解释问题的方法是:如果我不启用 'Enable beta features and APIs' 选项,此代码可以正常工作。如果我确实启用了 'Enable beta features and APIs' 选项,它就不起作用 - 在这种情况下我会收到错误响应:

Webhook call failed. Error: UNAVAILABLE, State: URL_UNREACHABLE, Reason: UNREACHABLE_5xx, HTTP status code: 500.

无论我如何 testing/using 机器人(在 Dialgoflow 内部测试时,在 https://console.actions.google.com/ 上测试时,在生产网站上使用聊天机器人时(与 DF Messenger 集成),都会发生错误或在测试 FB Messenger 集成时(FB 页面上的应用程序))。

我的部分解决方案和问题:

  1. 首先,如果我想为不同的集成使用不同的环境,并且如果我想能够进一步开发机器人,我肯定需要启用 'Enable beta features and APIs' 选项,对吗?但是接下来我需要解决问题的第二部分...
  2. 我怀疑履行代码可能是个问题?如果是真的,我需要 有人通过一些重写为我指明了正确的方向 代码或一些如何以适当的方式触发事件的示例 方式。
  3. 代码本身是否正常,问题实际上在于 Dialogflow 本身(它的工作方式)?在这种情况下我能做什么?

编辑:添加整个代码

Package.json(默认,没碰):

{
  "name": "dialogflowFirebaseFulfillment",
  "description": "This is the default fulfillment for a Dialogflow agents using Cloud Functions for Firebase",
  "version": "0.0.1",
  "private": true,
  "license": "Apache Version 2.0",
  "author": "Google Inc.",
  "engines": {
    "node": "10"
  },
  "scripts": {
    "start": "firebase serve --only functions:dialogflowFirebaseFulfillment",
    "deploy": "firebase deploy --only functions:dialogflowFirebaseFulfillment"
  },
  "dependencies": {
    "actions-on-google": "^2.2.0",
    "firebase-admin": "^5.13.1",
    "firebase-functions": "^2.0.2",
    "dialogflow": "^0.6.0",
    "dialogflow-fulfillment": "^0.5.0"
  }
}

index.js:

// See https://github.com/dialogflow/dialogflow-fulfillment-nodejs
// for Dialogflow fulfillment library docs, samples, and to report issues
'use strict';

const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
const {Card, Suggestion} = require('dialogflow-fulfillment');

process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements

exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
  const agent = new WebhookClient({ request, response });
  console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
  console.log('Dialogflow Request body: ' + JSON.stringify(request.body));

  /*
  function welcome(agent) {
    agent.add(`Pozdravljeni!`);
  }

  function fallback(agent) {
    agent.add(`Oprostite, nisem razumela.`);
    agent.add(`Lahko ponovite, prosim?`);
  }
  */

  // Dummies
  function D_99_01_01(agent) {
    //agent.add(`Text reponse`);
    //console.log('Dummy custom_990101 triggered');
    //agent.setContext({ name: 'outputCOntext', lifespan: 1, parameters: {}});
    agent.add(`...`);
    agent.setFollowupEvent('custom_990101');
  }
  function D_99_01_02(agent) {
    agent.add(`...`);
    agent.setFollowupEvent('custom_990102');
  }
  function D_99_01_03(agent) {
    agent.add(`...`);
    agent.setFollowupEvent('custom_990103');
  }
  function D_99_02_01(agent) {
    agent.add(`...`);
    agent.setFollowupEvent('custom_990201');
  }
  function D_99_03_01(agent) {
    agent.add(`...`);
    agent.setFollowupEvent('custom_990301');
  }

  function D_01(agent) {
    agent.add(`...`);
    agent.setContext({ name: 'Nov_narocnik', lifespan: 0, parameters: {}});
    agent.setContext({ name: 'Obstojec_narocnik', lifespan: 0, parameters: {}});
    agent.setFollowupEvent('custom_01');
  }
  function D_02_02(agent) {
    agent.add(`...`);
    agent.setContext({ name: '01Uvod-followup', lifespan: 2, parameters: {}});
    agent.setFollowupEvent('custom_0202');
  }
  function D_02_02_01(agent) {
    agent.add(`...`);
    agent.setContext({ name: 'Obstojec_narocnik', lifespan: 999, parameters: {}});
    agent.setContext({ name: '0202Obstojenaronik-followup', lifespan: 2, parameters: {}});
    agent.setFollowupEvent('custom_020201');
  }
  function D_02_02_02(agent) {
    agent.add(`...`);
    agent.setContext({ name: 'Obstojec_narocnik', lifespan: 999, parameters: {}});
    agent.setContext({ name: '0202Obstojenaronik-followup', lifespan: 2, parameters: {}});
    agent.setFollowupEvent('custom_020202');
  }
  function D_02_02_02_SERVICE_NO(agent) {
    agent.add(`...`);
    agent.setFollowupEvent('custom_020202_SERVICE_NO');
  }
  function D_02_02_02_SERVICE_NO_CLIENT(agent) {
    agent.add(`...`);
    agent.setContext({ name: '020202Podpora-STORITEV-ne-followup', lifespan: 2, parameters: {}});
    agent.setFollowupEvent('custom_020202_SERVICE_NO_CLIENT');
  }
  function D_02_02_02_SERVICE_NO_FINISH(agent) {
    agent.add(`...`);
    agent.setContext({ name: '020202Podpora-STORITEV-ne-followup', lifespan: 2, parameters: {}});
    agent.setFollowupEvent('custom_020202_SERVICE_NO_FINISH');
  }
  function D_02_02_02_SERVICE_NO_SUPPORT(agent) {
    agent.add(`...`);
    agent.setContext({ name: '020202Podpora-STORITEV-ne-followup', lifespan: 2, parameters: {}});
    agent.setFollowupEvent('custom_020202_SERVICE_NO_SUPPORT');
  }
  function D_02_02_03(agent) {
    agent.add(`...`);
    agent.setContext({ name: 'Obstojec_narocnik', lifespan: 999, parameters: {}});
    agent.setContext({ name: '0202Obstojenaronik-followup', lifespan: 2, parameters: {}});
    agent.setFollowupEvent('custom_020203');
  }
  function D_02_02_03_NO(agent) {
    agent.add(`...`);
    agent.setContext({ name: '020203Obstojenaronik-klub-followup', lifespan: 2, parameters: {}});
    agent.setFollowupEvent('custom_020203_NO');
  }


  // // Uncomment and edit to make your own intent handler
  // // uncomment `intentMap.set('your intent name here', yourFunctionHandler);`
  // // below to get this function to be run when a Dialogflow intent is matched
  // function yourFunctionHandler(agent) {
  //   agent.add(`This message is from Dialogflow's Cloud Functions for Firebase editor!`);
  //   agent.add(new Card({
  //       title: `Title: this is a card title`,
  //       imageUrl: 'https://developers.google.com/actions/images/badges/XPM_BADGING_GoogleAssistant_VER.png',
  //       text: `This is the body text of a card.  You can even use line\n  breaks and emoji! `,
  //       buttonText: 'This is a button',
  //       buttonUrl: 'https://assistant.google.com/'
  //     })
  //   );
  //   agent.add(new Suggestion(`Quick Reply`));
  //   agent.add(new Suggestion(`Suggestion`));
  //   agent.setContext({ name: 'weather', lifespan: 2, parameters: { city: 'Rome' }});
  // }

  // // Uncomment and edit to make your own Google Assistant intent handler
  // // uncomment `intentMap.set('your intent name here', googleAssistantHandler);`
  // // below to get this function to be run when a Dialogflow intent is matched
  // function googleAssistantHandler(agent) {
  //   let conv = agent.conv(); // Get Actions on Google library conv instance
  //   conv.ask('Hello from the Actions on Google client library!') // Use Actions on Google library
  //   agent.add(conv); // Add Actions on Google library responses to your agent's response
  // }
  // // See https://github.com/dialogflow/fulfillment-actions-library-nodejs
  // // for a complete Dialogflow fulfillment library Actions on Google client library v2 integration sample

  // Run the proper function handler based on the matched Dialogflow intent name
  let intentMap = new Map();
  //intentMap.set('Default Welcome Intent', welcome);
  //intentMap.set('Default Fallback Intent', fallback);
  // intentMap.set('your intent name here', yourFunctionHandler);
  // intentMap.set('your intent name here', googleAssistantHandler);

  // Dummies
  intentMap.set('02.01 > fizična oseba - no - telefon (D99.01.01)', D_99_01_01);
  intentMap.set('02.01 > fizična oseba - no - email (D99.01.02)', D_99_01_02);
  intentMap.set('02.01 > fizična oseba - no - klepet (D99.01.03)', D_99_01_03);
  intentMap.set('02.01 > fizična oseba - omrežje - posvet - telefon (D99.01.01)', D_99_01_01);
  intentMap.set('02.01 > fizična oseba - omrežje - posvet - email (D99.01.02)', D_99_01_02);
  intentMap.set('02.01 > fizična oseba - omrežje - posvet - klepet (D99.01.03)', D_99_01_03);
  intentMap.set('02.01 > ne zdaj - telefon (D99.01.01)', D_99_01_01);
  intentMap.set('02.01 > ne zdaj - email (D99.01.02)', D_99_01_02);
  intentMap.set('02.01 > ne zdaj - klepet (D99.01.03)', D_99_01_03);
  intentMap.set('02.02.01 > no - yes - klub (D02.02.03)', D_02_02_03);
  intentMap.set('02.02.01 > no - yes - razmerje (D02.02.01)', D_02_02_01);
  intentMap.set('02.02.01 > no - yes - podporne storitve (D02.02.02)', D_02_02_02);
  intentMap.set('02.02.01 > no - no (D99.02.01)', D_99_02_01);
  intentMap.set('02.02.01 > yes - klepet (D99.01.03)', D_99_01_03);
  intentMap.set('02.02.01 > yes - email (D99.01.02)', D_99_01_02);
  intentMap.set('02.02.01 > yes - telefon (D99.01.01)', D_99_01_01);
  intentMap.set('02.02.02 Podpora - no - splošno (D02.02)', D_02_02);
  intentMap.set('02.02.02 Podpora - no - zaključek (D99.03.01)', D_99_03_01);
  intentMap.set('02.02.02 Podpora - tv2go - no (D02.02.02_SERVICE_NO)', D_02_02_02_SERVICE_NO);
  intentMap.set('02.02.02 Podpora - tv2go - yes - email (D99.01.02)', D_99_01_02);
  intentMap.set('02.02.02 Podpora - tv2go - yes - klepet (D99.01.03)', D_99_01_03);
  intentMap.set('02.02.02 Podpora - tv2go - yes - other - obstoječ naročnik (D02.02.02_SERVICE_NO_CLIENT)', D_02_02_02_SERVICE_NO_CLIENT);
  intentMap.set('02.02.02 Podpora - tv2go - yes - other - podpora (D02.02.02_SERVICE_NO_SUPPORT)', D_02_02_02_SERVICE_NO_SUPPORT);
  intentMap.set('02.02.02 Podpora - tv2go - yes - other - zaključek (D02.02.02_SERVICE_NO_FINISH)', D_02_02_02_SERVICE_NO_FINISH);
  intentMap.set('02.02.02 Podpora - tv2go - yes - telefon (D99.01.01)', D_99_01_01);
  intentMap.set('02.02.02 Podpora - eračun - no (D02.02.02_SERVICE_NO)', D_02_02_02_SERVICE_NO);
  intentMap.set('02.02.02 Podpora - eposlovanje - no (D02.02.02_SERVICE_NO)', D_02_02_02_SERVICE_NO);
  intentMap.set('02.02.02 Podpora - trajnik - yes - telefon (D99.01.01)', D_99_01_01);
  intentMap.set('02.02.02 Podpora - trajnik - yes - no service - obstoječ naročnik (D02.02.02_SERVICE_NO_CLIENT)', D_02_02_02_SERVICE_NO_CLIENT);
  intentMap.set('02.02.02 Podpora - trajnik - yes - no service - zaključek (D02.02.02_SERVICE_NO_FINISH)', D_02_02_02_SERVICE_NO_FINISH);
  intentMap.set('02.02.02 Podpora - trajnik - yes - no service - podpora (D02.02.02_SERVICE_NO_SUPPORT)', D_02_02_02_SERVICE_NO_SUPPORT);
  intentMap.set('02.02.02 Podpora - trajnik - yes - email (D99.01.02)', D_99_01_02);
  intentMap.set('02.02.02 Podpora - trajnik - yes - klepet (D99.01.03)', D_99_01_03);
  intentMap.set('02.02.02 Podpora - trajnik - no (D02.02.02_SERVICE_NO)', D_02_02_02_SERVICE_NO);
  intentMap.set('02.02.02 Podpora - horizont - no (D02.02.02_SERVICE_NO)', D_02_02_02_SERVICE_NO);
  intentMap.set('02.02.02 Podpora - horizont - yes - telefon (D99.01.01)', D_99_01_01);
  intentMap.set('02.02.02 Podpora - horizont - yes - other - podpora (D02.02.02_SERVICE_NO_SUPPORT)', D_02_02_02_SERVICE_NO_SUPPORT);
  intentMap.set('02.02.02 Podpora - horizont - yes - other - zaključek (D02.02.02_SERVICE_NO_FINISH)', D_02_02_02_SERVICE_NO_FINISH);
  intentMap.set('02.02.02 Podpora - horizont - yes - other - obstoječ naročnik (D02.02.02_SERVICE_NO_CLIENT)', D_02_02_02_SERVICE_NO_CLIENT);
  intentMap.set('02.02.02 Podpora - horizont - yes - email (D99.01.02)', D_99_01_02);
  intentMap.set('02.02.02 Podpora - horizont - yes - klepet (D99.01.03)', D_99_01_03);
  intentMap.set('02.02.02 Podpora - STORITEV - no - zaključek (D99.03.01)', D_99_03_01);
  intentMap.set('02.02.02 Podpora - STORITEV - no - obstoječ naročnik (D02.02)', D_02_02);
  intentMap.set('02.02.02 Podpora - STORITEV - no - podpora (D02.02.02)', D_02_02_02);
  intentMap.set('02.02.03 > yes - klepet (D99.01.03)', D_99_01_03);
  intentMap.set('02.02.03 > yes - nič - splošno (D02.02)', D_02_02);
  intentMap.set('02.02.03 > yes - nič - zaključek (D99.03.01)', D_99_03_01);
  intentMap.set('02.02.03 > yes - nič - klub (D02.02.03_NO)', D_02_02_03_NO);
  intentMap.set('02.02.03 > yes - email (D99.01.02)', D_99_01_02);
  intentMap.set('02.02.03 > yes - telefon (D99.01.01)', D_99_01_01);
  intentMap.set('02.02.03 > no - naročilo storitev - yes (D02.02)', D_02_02);
  intentMap.set('02.02.03 > no - naročilo storitev - no (D99.02.01)', D_99_02_01);
  intentMap.set('02.02.03 > no - naročilo izdelka - pomoč - nič - zaključek (D99.03.01)', D_99_03_01);
  intentMap.set('02.02.03 > no - naročilo izdelka - pomoč - nič - klub (D02.02.03_NO)', D_02_02_03_NO);
  intentMap.set('02.02.03 > no - naročilo izdelka - pomoč - nič - splošno (D02.02)', D_02_02);
  intentMap.set('02.02.03 > no - naročilo izdelka - pomoč - email (D99.01.02)', D_99_01_02);
  intentMap.set('02.02.03 > no - naročilo izdelka - pomoč - telefon (D99.01.01)', D_99_01_01);
  intentMap.set('02.02.03 > no - naročilo izdelka - pomoč - klepet (D99.01.03)', D_99_01_03);
  intentMap.set('02.02.03 > no - naročilo izdelka - brez naročila - klub (D02.02.03_NO)', D_02_02_03_NO);
  intentMap.set('02.02.03 > no - naročilo izdelka - brez naročila - zaključek (D99.03.01)', D_99_03_01);
  intentMap.set('02.02.03 > no - naročilo izdelka - brez naročila - splošno (D02.02)', D_02_02);
  intentMap.set('02.02.03 > no - splošno - yes (D02.02)', D_02_02);
  intentMap.set('02.02.03 > no - splošno - no (D99.02.01)', D_99_02_01);
  intentMap.set('DFI - telefon (D99.01.01)', D_99_01_01);
  intentMap.set('DFI - email (D99.01.02)', D_99_01_02);
  intentMap.set('DFI - klepet (D99.01.03)', D_99_01_03);
  intentMap.set('DFI - osnovni meni (D01)', D_01);
  intentMap.set('DFI - zaključek (D99.03.01)', D_99_03_01);

  agent.handleRequest(intentMap);
});

根据 documentation, the Dialogflow fulfillment does not supports agent versioning:

The Dialogflow fulfillment library does not support versioning. If you need to use versioning, choose one of the following options:

此外,建议在部署到生产环境时将您的代码从内联编辑器移动到 Webhook 服务(例如,在 Cloud Functions 中创建您自己的自定义处理程序)。

The inline editor is intended for simple fulfillment testing and prototyping. Once you are ready to build a production application, you should create a webhook service.


另一方面,Dialogflow 实现库 is not longer maintained by Google, and since you've enabled beta features and API, this might be running into compatibility issues, as the first library is not up to date. I would recommend you to disable it, unless you have a real good reason to do use it, such as using Knowledge connectors,这是一个测试版功能(2021 年 11 月)。