构建 fulfillment (Dialogflow)

执行方式定义了用于获取用户输入的对话界面,以及用于处理输入并最终执行 Action 的逻辑。

定义对话

现在,您已定义 Action,可以为这些 Action 构建相应的对话。为此,您可以创建 Dialogflow intent,用于定义语法或用户在触发 intent 时需要说的内容,以及相应的执行方式以在 intent 被触发时对其进行处理。

您可以创建任意数量的意图来定义整个对话的语法。

创建意图

点击 Dialogflow 左侧导航菜单中意图菜单项旁边的 + 号。系统会显示 Intent Editor,您可以在其中输入以下信息:

  • intent 名称是 IDE 中显示的 intent 的名称。
  • 借助上下文,您可以将 intent 的触发范围限定为特定情况。如需了解详情,请参阅关于上下文的 Dialogflow 文档。
  • 事件会触发 intent,无需用户说出任何内容。GOOGLE_ASSISTANT_WELCOME 事件就是一个示例事件,它允许 Google 助理调用您的 Action。此事件用于您的 Action 的默认 Action。如需详细了解内置帮助程序 intent,请参阅我们的文档。
  • 训练短语定义用户需要说出什么内容(语法)才能触发 intent。请在此处输入几个短语(5-10 个),说明用户可以说什么来触发 intent。Dialogflow 会自动处理您提供的示例短语的自然变体。
  • 操作和参数定义了要传递给 fulfillment 的数据(如果为此 intent 启用了 fulfillment)。这包括从用户输入解析的数据,以及您可以在执行方式中使用的用于检测触发了哪个 intent 的名称。稍后您将使用此名称将 intent 映射到其对应的执行方式逻辑。如需详细了解如何定义操作,请参阅 Dialogflow 文档中的操作和参数

  • Responses 是 Dialogflow Response Builder。利用以下构建器,您可以直接在 Dialogflow 中定义对此意图的响应,而无需调用 fulfillment。此功能对于不需要执行方式的静态响应非常有用。您可以使用它来提供简单的欢迎或道别消息。不过,您可能需要使用执行方式来响应用户的大多数 intent。

  • Fulfillment 指定是否要在此 intent 触发时调用您的执行方式。您很可能会在 Dialogflow 代理中为大多数意图启用此功能。如需在 intent 中查看此项,您必须在 Fulfillment 菜单中为代理启用 fulfillment。

在 Dialogflow 中构建响应

对于某些 intent,您可能不需要让执行方式返回响应。在这些情况下,您可以使用 Dialogflow 中的响应构建器来创建响应。

响应区域中,提供要返回给用户的文本回复。默认文本响应是简单的 TTS 文本响应,可以跨多个 Dialogflow 集成工作。响应页面上介绍了 Google 助理的响应。

构建执行方式响应

您的执行方式代码托管在 Action 的网络钩子执行方式逻辑中。例如,在 Silly Name Maker 示例中,可在 Cloud Functions for Firebase 的 index.js 中找到此逻辑。

当使用 fulfillment 的意图被触发时,您会收到来自 Dialogflow 的请求,其中包含有关该意图的信息。然后,您可以通过处理 intent 并返回响应来响应请求。此请求和响应由 Dialogflow 网络钩子定义。

强烈建议您使用 Node.js 客户端库来处理请求并返回响应。以下是使用客户端库的一般流程:

  1. 初始化 Dialogflow 对象。此对象会自动处理请求并解析请求,以便您可以在执行方式中处理这些请求。
  2. 创建用于处理请求的函数。这些函数会处理用户输入以及 intent 的其他组件,并构建要返回给 Dialogflow 的响应。

初始化 Dialogflow 对象

以下代码会实例化 Dialogflow 并为 Google Cloud Functions 函数对 Node.js 进行一些样板设置:

Node.js
'use strict';

const {dialogflow} = require('actions-on-google');
const functions = require('firebase-functions');

const app = dialogflow({debug: true});

app.intent('Default Welcome Intent', (conv) => {
  // Do things
});
exports.yourAction = functions.https.onRequest(app);
Java
public class DfFulfillment extends DialogflowApp {
  private static final Logger LOGGER = LoggerFactory.getLogger(DfFulfillment.class);

  @ForIntent("Default Welcome Intent")
  public ActionResponse welcome(ActionRequest request) {
    // Do things
    // ...
  }

创建用于处理请求的函数

当用户说出触发意图的短语时,您会收到来自 Dialogflow 的请求,您可以使用执行方式中的函数来处理该请求。在此函数中,您通常需要执行以下操作:

  1. 执行处理用户输入所需的任何逻辑。
  2. 构建响应以响应触发的 intent。请考虑用户使用的途径来构建适当的响应。如需详细了解如何满足不同 surface 的响应,请参阅surface 功能
  3. 通过您的响应调用 ask() 函数。

以下代码展示了如何构建两个 TTS 响应,用于处理一个调用 intent (input.welcome) 和一个对话框 intent (input.number),欢迎用户访问您的 Action,并回显用户针对某个 Dialogflow intent 说出的数字,并带有名称:

Node.js
const app = dialogflow();
app.intent('Default Welcome Intent', (conv) => {
conv.ask('Welcome to number echo! Say a number.');
});
app.intent('Input Number', (conv, {num}) => {
// extract the num parameter as a local string variable
conv.close(`You said ${num}`);
});
Java
@ForIntent("Default Welcome Intent")
public ActionResponse defaultWelcome(ActionRequest request) {
  ResponseBuilder rb = getResponseBuilder(request);
  rb.add("Welcome to number echo! Say a number.");
  return rb.build();
}

@ForIntent("Input Number")
public ActionResponse inputNumber(ActionRequest request) {
  ResponseBuilder rb = getResponseBuilder(request);
  Integer number = (Integer) request.getParameter("num");
  rb.add("You said " + number.toString());
  return rb.endConversation().build();
}

上述代码附带的自定义 intent“输入数字”使用 @sys.number 实体从用户话语中提取数字。然后,intent 会向执行方式中的函数发送包含用户号码的 num 参数。

您可以添加一个回退函数,而不是为每个 intent 使用单独的处理程序。在回退函数内,检查哪个 intent 触发了它,并相应地执行适当的操作。

Node.js
const WELCOME_INTENT = 'Default Welcome Intent';
const NUMBER_INTENT = 'Input Number';
const NUMBER_PARAMETER = 'num';
// you can add a fallback function instead of a function for individual intents
app.fallback((conv) => {
 // intent contains the name of the intent
 // you defined in the Intents area of Dialogflow
 const intent = conv.intent;
 switch (intent) {
   case WELCOME_INTENT:
     conv.ask('Welcome! Say a number.');
     break;
   case NUMBER_INTENT:
     const num = conv.parameters[NUMBER_PARAMETER];
     conv.close(`You said ${num}`);
     break;
 }
});
Java
// you can add a fallback function instead of a function for individual intents
@ForIntent("Default Fallback Intent")
public ActionResponse fallback(ActionRequest request) {
  final String WELCOME_INTENT = "Default Welcome Intent";
  final String NUMBER_INTENT = "Input Number";
  final String NUMBER_ARGUMENT = "num";
  // intent contains the name of the intent
  // you defined in the Intents area of Dialogflow
  ResponseBuilder rb = getResponseBuilder(request);
  String intent = request.getIntent();
  switch (intent) {
    case WELCOME_INTENT:
      rb.add("Welcome! Say a number.");
      break;
    case NUMBER_INTENT:
      Integer num = (Integer) request.getParameter(NUMBER_ARGUMENT);
      rb.add("You said " + num).endConversation();
      break;
  }
  return rb.build();
}

无匹配项重新提示

当 Dialogflow 无法匹配意图的训练短语中定义的任何输入语法时,它会触发回退 intent。回退 intent 通常会重新提示用户为您的 Action 提供必要的输入。您可以提供重新提示短语,方法是在回退 intent 的响应 (Response) 区域中指定这些短语,也可以使用网络钩子提供响应。

当用户的响应与您的 Action 的训练短语不匹配时,Google 助理会尝试处理输入。此行为有助于用户在对话过程中更改操作。例如,用户询问“这周放映哪些电影?”,然后在对话过程中改变上下文:“明天的天气怎么样?”在此示例中,由于“明天的天气怎么样?”不是对初始提示触发的对话的有效响应,因此 Google 助理会自动尝试处理匹配并将用户移至适当的对话。

如果 Google 助理找不到与用户输入匹配的适当 Action,就会将用户返回到该 Action 的上下文中。

由于 Google 助理可能会中断您的 Action 来响应有效的非匹配场景,因此请勿使用回退 intent 来执行用户查询。您应仅使用后备 intent 重新提示用户输入有效的内容。

如需创建回退 intent,请执行以下操作:

  1. 点击 Dialogflow 导航菜单中的意图 (Intents)。
  2. 点击创建 intent 旁边的 ⋮,然后选择创建后备 intent。(或者,点击 Default Fallback intent 进行修改。)
  3. 指定重新提示短语,以回复用户。这些短语应该具有对话性,并且对用户当前的上下文尽可能有用。

    在不使用 fulfillment 的情况下执行此操作:在 intent 的 Response 区域指定短语。Dialogflow 会从此列表中随机选择短语并向用户传达,直到触发更具体的意图。

    如需使用 fulfillment 执行此操作,请执行以下操作

    1. 在 intent 的 Fulfillment 部分中,切换为此 intent 启用 webhook 调用
    2. 在您的执行方式逻辑中,应像处理任何其他 intent 一样处理回退 intent,如创建用于处理请求的函数部分中所述。

    例如,以下函数使用 Node.js 客户端库中的 conv.data 对象(可用于维护状态的任意数据载荷)存储计数器,用于跟踪回退 intent 的触发次数。如果多次触发,则 Action 会退出。虽然它未在代码中显示,但当非回退 intent 被触发时,您应使其他 intent 将此计数器重置为 0。(如需详细了解如何实现,请参阅 Number Genie 示例。)

    Node.js
    app.intent('Default Fallback Intent', (conv) => {
     conv.data.fallbackCount++;
     // Provide two prompts before ending game
     if (conv.data.fallbackCount === 1) {
       conv.contexts.set(DONE_YES_NO_CONTEXT, 5);
       conv.ask('Are you done playing Number Genie?');
     } else {
       conv.close(`Since I'm still having trouble, so I'll stop here. ` +
         `Let's play again soon.`);
     }
    });
    Java
    @ForIntent("Default Fallback Intent")
    public ActionResponse defaultFallback(ActionRequest request) {
      final String DONE_YES_NO_CONTEXT = "done_yes_no_context";
      ResponseBuilder rb = getResponseBuilder(request);
    
      int fallbackCount =
          request.getConversationData().get("fallbackCount") == null
              ? 0
              : (Integer) request.getConversationData().get("fallbackCount");
      fallbackCount++;
      request.getConversationData().put("fallbackCount", fallbackCount);
    
      if (fallbackCount == 1) {
        rb.add(new ActionContext(DONE_YES_NO_CONTEXT, 5));
        rb.add("Are you done playing Number Genie?");
      } else {
        rb.add("Since I'm still having trouble, so I'll stop here. Let's play again soon")
            .endConversation();
      }
      return rb.build();
    }

使用上下文

如果您希望 Dialogflow 仅在特定情况下触发回退 intent,请使用上下文。如果您希望针对不同的非匹配场景使用不同的后备 intent,这会非常有用。

  • 如果您没有为回退 intent 设置上下文,则会被认为是 Dialogflow 在没有匹配其他意图时触发的全局回退 intent。如果您选择使用其中一个属性,则仅应定义其中一个属性。
  • 如果您为回退 intent 设置输入上下文,则 Dialogflow 会在满足以下条件时触发此回退 intent:

    • 用户的当前上下文是 intent 中定义的上下文的超集。
    • 没有其他 intent 匹配。

    这样,您就可以使用具有不同输入上下文的多个回退 intent,从而针对特定场景自定义非匹配重新提示。

  • 如果您为回退 intent 设置输出上下文,则会在触发和处理回退 intent 后使用户处于同一上下文中。

如需了解详情,请参阅 Dialogflow 上下文

无输入重新提示

请参阅重新提示页面,详细了解如何应对用户未在 Google Home 等需要持续互动的语音设备上提供进一步输入的情况。