เคล็ดลับการใช้งาน (Dialogflow)

โปรดอ่านเคล็ดลับต่อไปนี้เพื่อนำแนวทางปฏิบัติที่ดีในการออกแบบการสนทนาไปใช้กับการดำเนินการของคุณ

คาดการณ์เวอร์ชันต่างๆ

จัดการปัญหานี้ในอินพุต "ผู้ใช้พูด" ใน Dialogflow นอกจากนี้ ให้ใช้ Intent มากกว่า 1 รายการที่แมปกับการดำเนินการเดียวกันได้ ซึ่งจะทริกเกอร์ Intent แต่ละรายการด้วยชุดวลี "ผู้ใช้พูด" ที่ต่างกันได้

เสนอคำเตือนที่เป็นประโยชน์และล้มเหลวอย่างมีชั้นเชิง

บางครั้งการดำเนินการของคุณไม่สามารถไปข้างหน้าได้เพราะไม่ได้รับอินพุต (เรียกว่า "ไม่ป้อนข้อมูล)" หรือไม่เข้าใจข้อมูลจากผู้ใช้ (เรียกว่า "ไม่มีการจับคู่") เมื่อเกิดกรณีนี้ขึ้น Assistant จะพยายามพิจารณาว่าผู้ใช้ต้องการทริกเกอร์การดำเนินการอื่นหรือไม่ หาก Assistant ไม่ตรงกับข้อมูลที่ผู้ใช้ป้อนกับการดำเนินการอื่น ผู้ใช้จะดำเนินการต่อในบริบทของการดำเนินการของคุณ สถานการณ์นี้สามารถเกิดขึ้นได้ทุกเมื่อ ดังนั้น แนวทางปฏิบัติแนะนำคือให้จัดการสถานการณ์ที่ไม่มีการป้อนข้อมูลและไม่ตรงกับสถานการณ์จริงในบทสนทนาที่มีตัวเลือกสำรองในแต่ละครั้ง คุณสามารถใช้ทางเลือกสำรองเพื่อช่วยให้ผู้ใช้กลับสู่เส้นทางแห่งความสำเร็จได้

โดยเริ่มต้นตัวแปร fallbackCount ในออบเจ็กต์ conv.data แล้วตั้งค่าเป็น 0 เตรียมอาร์เรย์ของข้อความแจ้งสำรอง 2 รายการ (เพิ่มความชัดเจน) และข้อความแจ้งสำรองขั้นสุดท้ายที่จบการสนทนา

จากนั้นสร้าง Intent สำรอง (โดยหลักการแล้ว 1 รายการสำหรับ Intent ที่ดำเนินการได้แต่ละรายการใน Agent) ในเครื่องจัดการ Intent ให้ดึงจำนวนวิดีโอสำรองจากออบเจ็กต์ conv.data แล้วเพิ่มค่านี้ และหากมีค่าน้อยกว่า 3 ให้ดึงข้อความแจ้งจากอาร์เรย์ของ 3 หากมีการนับที่ 4 ครั้งขึ้นไป ให้ปิดการสนทนาโดยใช้ข้อความแจ้งขั้นสุดท้าย ใน Intent ทั้งหมดที่ไม่ใช่รายการสำรอง ให้รีเซ็ตจำนวนรายการสำรองเป็น 0 โดยหลักการแล้ว ให้สร้างเทมเพลตสำรองสำหรับ Intent ที่เฉพาะเจาะจงเพื่อให้มีความเฉพาะเจาะจงสำหรับ Intent เหล่านั้น

Node.js

const GENERAL_FALLBACK = [
   'Sorry, what was that?',
   'I didn\'t quite get that. I can help you find good local restaurants, what do you want to know about?',
];

const LIST_FALLBACK = [
   'Sorry, what was that?',
   'I didn\'t catch that. Could you tell me which one you prefer?',
];

const FINAL_FALLBACK = 'I\'m sorry I\'m having trouble here. Let\'s talk again later.';

const handleFallback = (conv, promptFetch, callback) => {
 conv.data.fallbackCount = parseInt(conv.data.fallbackCount, 10);
 conv.data.fallbackCount++;
 if (conv.data.fallbackCount > 2) {
   conv.close(promptFetch.getFinalFallbackPrompt());
 } else {
   callback();
 }
}
// Intent handlers below
const generalFallback = (conv) => {
  handleFallback = (conv, promptFetch, () => {
    conv.ask(GENERAL_FALLBACK[conv.data.fallbackCount],
      getGeneralNoInputPrompts());
 });
}

const listFallback = (conv) => {
  handleFallback = (conv, promptFetch, () => {
   conv.ask(LIST_FALLBACK[conv.data.fallbackCount],
       getGeneralNoInputPrompts());
 });
}

const nonFallback = (conv) => {
  conv.data.fallbackCount = 0;
  conv.ask('A non-fallback message here');
}

Java

private static final List<String> GENERAL_FALLBACK =
    Arrays.asList(
        "Sorry, what was that?",
        "I didn\'t quite get that. I can tell you all about IO, like date or location, or about the sessions. What do you want to know about?");
private static final List<String> LIST_FALLBACK =
    Arrays.asList(
        "Sorry, what was that?",
        "I didn\'t catch that. Could you tell me which one you liked?");
private static final List<String> FINAL_FALLBACK =
    Arrays.asList("I\'m sorry I\'m having trouble here. Maybe we should try this again later.");

@ForIntent("General Fallback")
public ActionResponse generalFallback(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  int fallbackCount = (Integer) request.getConversationData().get("fallbackCount");
  fallbackCount++;
  request.getConversationData().put("fallbackCount", fallbackCount);
  if (fallbackCount > 2) {
    responseBuilder.add(getRandomPromptFromList(FINAL_FALLBACK)).endConversation();
  } else {
    responseBuilder.add(getRandomPromptFromList(GENERAL_FALLBACK));
  }
  return responseBuilder.build();
}

private String getRandomPromptFromList(List<String> prompts) {
  Random rand = new Random();
  int i = rand.nextInt(prompts.size());
  return prompts.get(i);
}

@ForIntent("List Fallback")
public ActionResponse listFallback(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  int fallbackCount = (Integer) request.getConversationData().get("fallbackCount");
  fallbackCount++;
  request.getConversationData().put("fallbackCount", fallbackCount);
  if (fallbackCount > 2) {
    responseBuilder.add(getRandomPromptFromList(FINAL_FALLBACK)).endConversation();
  } else {
    responseBuilder.add(getRandomPromptFromList(LIST_FALLBACK));
  }
  return responseBuilder.build();
}

@ForIntent("Non Fallback")
public ActionResponse nonFallback(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  request.getConversationData().put("fallbackCount", 0);
  responseBuilder.add("Non Fallback message");
  return responseBuilder.build();
}

เตรียมพร้อมที่จะช่วยเหลือทุกเมื่อ

สร้างความตั้งใจที่จะฟังวลีช่วยเหลือ เช่น "ฉันทำอะไรได้บ้าง" "เธอบอกอะไรฉันได้บ้าง" หรือ "ช่วยด้วย" ในกรณีนี้ ให้เสนอคำตอบ (แบบหมุนเวียน) เพื่อแสดงภาพรวมเกี่ยวกับสิ่งที่ตัวแทนทำได้และนำผู้ใช้ไปยังการดำเนินการที่เป็นไปได้ ตามหลักแล้ว ให้ใช้เป้าหมายในการให้ความช่วยเหลือติดตามผลใน Dialogflow เพื่อสร้างสถานการณ์ความช่วยเหลือแบบต่างๆ สำหรับความตั้งใจที่นำไปใช้ได้จริงที่แตกต่างกัน

Node.js

const HELP_PROMPTS = [
   'There\'s a lot you might want to know about the local restaurants, and I can tell you all about it, like where it is and what kind of food they have. What do you want to know?',
   'I\'m here to help, so let me know if you need any help figuring out where or what to eat. What do you want to know?',
];

// Intent handler
const help = (conv) => {
 reply(conv, promptFetch.getHelpPrompt(), // fetches random entry from HELP_PROMPTS
     promptFetch.getGeneralNoInputPrompts());
}

Java

private static final List<String> HELP_PROMPTS =
    Arrays.asList(
        "There's a lot you might want to know about IO, and I can tell you all about it, like where it is and what the sessions are. What do you want to know?",
        "IO can be a little overwhelming, so I\'m here to help. Let me know if you need any help figuring out the event, like when it is, or what the sessions are. What do you want to know?");

@ForIntent("Help")
public ActionResponse help(ActionRequest request) {
  return getResponseBuilder(request).add(getRandomPromptFromList(HELP_PROMPTS)).build();
}

อนุญาตให้ผู้ใช้แสดงข้อมูลซ้ำ

รวมเมธอด app.ask(output) ทั้งหมดด้วยฟังก์ชันพร็อกซีที่เพิ่มเอาต์พุตไปยัง conv.data.lastPrompt สร้างความตั้งใจซ้ำๆ ที่รอฟังข้อความแจ้ง จากผู้ใช้ซ้ำๆ เช่น "อะไร" "พูดอีกทีได้ไหม" หรือ "พูดซ้ำได้ไหม" สร้างอาร์เรย์ของคำนำหน้าที่ซ้ำได้ ซึ่งสามารถใช้เพื่อรับทราบว่าผู้ใช้ขอให้ดำเนินการบางอย่างซ้ำ ในเครื่องจัดการ Intent ที่ซ้ำกัน ให้เรียกใช้ ask() ด้วยสตริงต่อกันของคำนำหน้าที่ซ้ำกันและค่า conv.data.lastPrompt โปรดทราบว่าคุณจะต้องย้ายแท็กเปิด SSML หากใช้ในข้อความแจ้งล่าสุด

Node.js

const REPEAT_PREFIX = [
    'Sorry, I said ',
    'Let me repeat that. ',
];

const reply = (conv, inputPrompt, noInputPrompts) => {
  conv.data.lastPrompt = inputPrompt;
  conv.data.lastNoInputPrompts = noInputPrompts;
  conv.ask(inputPrompt, noInputPrompts);
}
// Intent handlers
const normalIntent = (conv) => {
  reply(conv, 'Hey this is a question', SOME_NO_INPUT_PROMPTS);
}

const repeat = (conv) => {
  let repeatPrefix = promptFetch.getRepeatPrefix(); // randomly chooses from REPEAT_PREFIX
  // Move SSML start tags over
  if (conv.data.lastPrompt.startsWith(promptFetch.getSSMLPrefix())) {
    conv.data.lastPrompt =
        conv.data.lastPrompt.slice(promptFetch.getSSMLPrefix().length);
    repeatPrefix = promptFetch.getSSMLPrefix() + repeatPrefix;
  }
  conv.ask(repeatPrefix + conv.data.lastPrompt,
      conv.data.lastNoInputPrompts);
}

Java

private final List<String> REPEAT_PREFIX = Arrays.asList("Sorry, I said ", "Let me repeat that.");

private final String SsmlPrefix = "<speak>";

@ForIntent("Normal Intent")
public ActionResponse normalIntent(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  responseBuilder.getConversationData().put("lastPrompt", "Hey this is a question");
  return responseBuilder.build();
}

@ForIntent("repeat")
public ActionResponse repeat(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  String repeatPrefix = getRandomPromptFromList(REPEAT_PREFIX);
  // Move SSML start tags over
  String lastPrompt = (String) responseBuilder.getConversationData().get("lastPrompt");
  if (lastPrompt.startsWith(SsmlPrefix)) {
    String newLastPrompt = lastPrompt.substring(SsmlPrefix.length());
    responseBuilder.getConversationData().put("lastPrompt", newLastPrompt);
    repeatPrefix = SsmlPrefix + repeatPrefix;
  }
  responseBuilder.add(repeatPrefix + lastPrompt);
  return responseBuilder.build();
}

ปรับเปลี่ยนการสนทนาในแบบของคุณด้วยค่ากำหนดของผู้ใช้

การดำเนินการสามารถขอค่ากำหนดของผู้ใช้และจดจำผู้ใช้ไว้ใช้ในภายหลัง เพื่อให้คุณปรับเปลี่ยนการสนทนาในอนาคตกับผู้ใช้รายนั้นในแบบของคุณได้

การดำเนินการในตัวอย่างนี้จะให้รายงานสภาพอากาศสำหรับรหัสไปรษณีย์แก่ผู้ใช้ โค้ดตัวอย่างต่อไปนี้จะถามผู้ใช้ว่าต้องการให้การดำเนินการจำรหัสไปรษณีย์ของตนสำหรับการสนทนาในภายหลังหรือไม่

Node.js

app.intent('weather_report', (conv) => {
  let zip = conv.arguments.get('zipcode');
  conv.data.zip = zip;
  conv.ask(getWeatherReport(zip));
  conv.ask(new Confirmation(`Should I remember ${zip} for next time?`));
});

app.intent('remember_zip', (conv, params, confirmation) => {
  if (confirmation) {
    conv.user.storage.zip = conv.data.zip;
    conv.close('Great! See you next time.');
  } else conv.close('Ok, no problem.');
});

Java

@ForIntent("weather_report")
public ActionResponse weatherReport(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  String zip = (String) request.getArgument("location").getStructuredValue().get("zipCode");
  responseBuilder.getConversationData().put("zip", zip);
  responseBuilder.add(getWeatherReport(zip));
  responseBuilder.add(
      new Confirmation().setConfirmationText("Should I remember " + zip + " for next time?"));
  return responseBuilder.build();
}

@ForIntent("remember_zip")
public ActionResponse rememberZip(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  if (request.getUserConfirmation()) {
    responseBuilder.getUserStorage().put("zip", responseBuilder.getConversationData().get("zip"));
    responseBuilder.add("Great! See you next time.").endConversation();
  } else {
    responseBuilder.add("Ok, no problem.").endConversation();
  }
  return responseBuilder.build();
}

หลังจากถามผู้ใช้ว่าใช้รหัสไปรษณีย์ใดในระหว่างกล่องโต้ตอบแรก คุณสามารถข้ามข้อความแจ้งในการเรียกใช้ครั้งถัดไปและใช้รหัสไปรษณีย์เดิมได้ คุณยังควรมี Escape (เช่น ชิปคำแนะนำที่ช่วยให้เขาเลือกรหัสไปรษณีย์อื่น) ได้ แต่การลดการเปิดบทสนทนาในกรณีทั่วไปจะสร้างประสบการณ์การใช้งานที่ราบรื่นขึ้นมาก

Node.js

app.intent('weather_report', (conv) => {
  let zip = conv.arguments.get('zipcode');
  if (zip) {
    conv.close(getWeatherReport(zip));
  } else if (conv.user.storage.zip) {
    conv.ask(new SimpleResponse(getWeatherReport(conv.user.storage.zip)));
    conv.ask(new Suggestions('Try another zipcode'));
  } else {
    conv.ask('What\'s your zip code?');
  }
});

app.intent('provide_zip_df', (conv) => {
  conv.user.storage.zip = conv.arguments.get('zipcode');
  conv.close(getWeatherReport(conv.user.storage.zip));
});

Java

public ActionResponse weatherReport2(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  String zip = (String) request.getArgument("location").getStructuredValue().get("zipCode");
  if (zip != null) {
    responseBuilder.add(getWeatherReport(zip)).endConversation();
  } else if ((zip = (String) responseBuilder.getUserStorage().get("zip")) != null) {
    responseBuilder.add(new SimpleResponse().setTextToSpeech(getWeatherReport(zip)));
    responseBuilder.add(new Suggestion().setTitle("Try another zipcode"));
  } else {
    responseBuilder.add("What's your zip code?");
  }
  return responseBuilder.build();
}

ปรับแต่งสำหรับผู้ใช้ที่กลับมา

การคงสถานะบางอย่างระหว่างการสนทนาไว้ช่วยให้ผู้ใช้ที่กลับมาได้รับประสบการณ์ที่เป็นธรรมชาติมากขึ้น ขั้นตอนแรกในการสร้างประสบการณ์นี้คือ การทักทายผู้ใช้ที่กลับมาในรูปแบบที่ต่างออกไป ตัวอย่างเช่น คุณสามารถแตะคำทักทายหรือ แสดงข้อมูลที่เป็นประโยชน์ตามการสนทนาที่ผ่านมา โดยใช้พร็อพเพอร์ตี้ AppRequest.User lastSeen ขาเข้าเพื่อระบุว่าผู้ใช้เคยโต้ตอบกับการดำเนินการของคุณมาก่อนหรือไม่ หากพร็อพเพอร์ตี้ lastSeen รวมอยู่ในเปย์โหลดคำขอ คุณจะใช้คำทักทายที่แตกต่างจากปกติได้

โค้ดด้านล่างใช้ไลบรารีของไคลเอ็นต์ Node.js เพื่อดึงค่าของ last.seen

Node.js

// This function is used to handle the welcome intent
// In Dialogflow, the Default Welcome Intent ('input.welcome' action)
// In Actions SDK, the 'actions.intent.MAIN' intent
const welcome = (conv) => {
  if (conv.user.last.seen) {
    conv.ask(`Hey you're back...`);
  } else {
    conv.ask('Welcome to World Cities Trivia!...');
  }
}

Java

// This function is used to handle the welcome intent
// In Dialogflow, the Default Welcome Intent ('input.welcome' action)
// In Actions SDK, the 'actions.intent.MAIN' intent
public ActionResponse welcome(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  if (request.getUser().getLastSeen() != null) {
    responseBuilder.add("Hey you're back...");
  } else {
    responseBuilder.add("Welcome to Number Genie!...");
  }
  return responseBuilder.build();
}

คุณปรับปรุงคําทักทายนี้เพิ่มเติมได้โดยปรับแต่งคำตอบตามค่าจริงของ lastSeen ตัวอย่างเช่น ผู้ใช้ที่มีการโต้ตอบล่าสุดเกิดขึ้นหลายเดือนก่อนการโต้ตอบปัจจุบันอาจได้รับคำทักทายต่างจากผู้ใช้ที่ใช้การดำเนินการในวันก่อนหน้า

การควบคุมระดับเสียงในการสนทนา

Assistant จะให้ผู้ใช้ควบคุมระดับเสียงของอุปกรณ์ในการดำเนินการสนทนาในอุปกรณ์ที่รองรับได้โดยพูดสิ่งต่างๆ อย่างเช่น "เพิ่มระดับเสียง" หรือ "ตั้งระดับเสียงเป็น 50 เปอร์เซ็นต์" หากคุณมี Intent ที่จัดการวลีการฝึกที่คล้ายกัน Intent จะมีความสำคัญเหนือกว่า เราขอแนะนำให้คุณอนุญาตให้ Assistant จัดการคำขอเหล่านี้ของผู้ใช้ เว้นแต่ว่าการดำเนินการของคุณมีเหตุผลเฉพาะ