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

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

คาดหวังรูปแบบ

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

ระบุข้อความตอบกลับที่เป็นประโยชน์และล้มเหลวอย่างแนบเนียน

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

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

จากนั้นสร้าง Intent สำรอง (ควรจะเลือก 1 ตัวเลือกสำหรับ Intent ที่นำไปใช้ได้จริงแต่ละรายการใน ตัวแทน) ในเครื่องจัดการ Intent ให้ดึงจำนวนสำรองจาก conv.data เพิ่มออบเจ็กต์ และหากน้อยกว่า 3 ให้ดึงพรอมต์จากอาร์เรย์ จาก 3 หากจำนวนอยู่ที่ 4 รายการขึ้นไป ให้ปิดการสนทนาโดยใช้การสนทนาสุดท้าย ปรากฏขึ้น ใน Intent ทั้งหมดที่ไม่ใช่วิดีโอสำรอง ให้รีเซ็ตจำนวนสำรองเป็น 0 โดยหลักการแล้ว คุณควรสร้างเทมเพลตวิดีโอสำรองสำหรับ 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();
}

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

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 ตัวอย่างเช่น ผู้ใช้ที่มีการโต้ตอบสุดท้ายเกิดขึ้นหลายครั้ง เดือนก่อนที่การโต้ตอบปัจจุบันอาจได้รับคำทักทายที่ต่างจาก ผู้ที่ใช้ Action ในวันก่อนหน้านี้

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

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