Mẹo triển khai (Dialogflow)

Hãy xem lại các mẹo sau để triển khai các phương pháp thiết kế cuộc trò chuyện hiệu quả vào Hành động của bạn.

Dự kiến biến thể

Hãy xử lý vấn đề này trong phần "Người dùng nói" thông tin đầu vào trong Dialogflow. Ngoài ra, hãy sử dụng nhiều hơn một ý định có thể liên kết đến cùng một hành động, trong đó mỗi ý định có thể được kích hoạt bằng các nhóm khác nhau của "Người dùng nói" cụm từ.

Đưa ra các câu lệnh nhắc lại hữu ích và không khắc phục được lỗi một cách linh hoạt

Đôi khi, Hành động của bạn không thể tiến hành vì không nhận được thông tin đầu vào (được gọi là không có dữ liệu đầu vào) hoặc không hiểu dữ liệu đầu vào của người dùng (còn gọi là không khớp). Khi điều này xảy ra, trước tiên, Trợ lý sẽ cố gắng xác định xem người dùng có muốn để kích hoạt một Hành động khác. Nếu Trợ lý không khớp với thông tin đầu vào của người dùng sang Hành động khác, người dùng tiếp tục trong ngữ cảnh Hành động của bạn. Trường hợp này có thể xảy ra bất cứ lúc nào, vì vậy phương pháp hay nhất là chỉ xử lý riêng tình huống không có dữ liệu đầu vào và không khớp tại mỗi ngã rẽ trong một cuộc trò chuyện có phương án dự phòng. Khi sử dụng tính năng dự phòng, bạn có thể giúp người dùng trở lại hoạt động bình thường.

Để thực hiện việc này, hãy khởi tạo biến fallbackCount trong đối tượng conv.data. và đặt thành 0. Chuẩn bị một mảng gồm hai lời nhắc dự phòng (báo cáo rõ ràng hơn), và lời nhắc dự phòng cuối cùng giúp kết thúc cuộc trò chuyện.

Sau đó, hãy tạo một ý định dự phòng (tốt nhất là một ý định cho mỗi ý định có thể hành động trong nhân viên hỗ trợ). Trong trình xử lý ý định, hãy lấy số lượng dự phòng từ conv.data đối tượng, tăng giá trị này và nếu đối tượng nhỏ hơn 3, hãy lấy lời nhắc từ mảng trên 3. Nếu số lượng từ 4 trở lên, hãy đóng cuộc trò chuyện bằng cách sử dụng lệnh . Trong tất cả các ý định không phải là ý định dự phòng, hãy đặt lại số lượng dự phòng về 0. Tốt nhất là bạn nên tạo mẫu cho các ý định dự phòng cụ thể dành riêng cho những ý định đó.

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();
}

Sẵn sàng trợ giúp bất cứ lúc nào

Tạo một ý định lắng nghe các cụm từ trợ giúp như "Tôi có thể làm gì?", "bạn có thể cho tôi biết điều gì" hoặc "trợ giúp". Trong ý định này, hãy cung cấp một số (xoay vòng) cung cấp thông tin tổng quan về những việc nhân viên hỗ trợ có thể làm và hướng người dùng đến hành động khả thi. Tốt nhất là bạn cũng có thể sử dụng ý định trợ giúp tiếp theo trong Dialogflow để tạo ra các tình huống trợ giúp khác nhau cho các ý định hành động khác nhau.

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();
}

Cho phép người dùng phát lại thông tin

Gói tất cả phương thức app.ask(output) bằng một hàm proxy để thêm phương thức đầu ra thành conv.data.lastPrompt. Tạo một ý định lặp lại để theo dõi lặp lại từ người dùng như "cái gì?", "nói lại lần nữa" hoặc "bạn có thể lặp lại điều đó không?". Tạo một mảng tiền tố lặp lại có thể dùng để xác nhận rằng người dùng đã yêu cầu lặp lại điều gì đó. Lặp lại trình xử lý ý định, hãy gọi ask() bằng một chuỗi nối của tiền tố lặp lại và giá trị của conv.data.lastPrompt. Xin lưu ý rằng bạn sẽ phải chuyển mọi Thẻ mở SSML nếu được dùng trong câu lệnh gần đây nhất.

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();
}

Cá nhân hoá cuộc trò chuyện bằng các lựa chọn ưu tiên của người dùng

Hành động của bạn có thể hỏi người dùng về các lựa chọn ưu tiên và ghi nhớ các lựa chọn đó để sử dụng sau, cho phép bạn cá nhân hoá các cuộc trò chuyện trong tương lai với người dùng đó.

Hành động trong ví dụ này cung cấp cho người dùng một báo cáo thời tiết có mã bưu chính. Nội dung sau đây mã ví dụ hỏi người dùng xem họ có muốn Hành động ghi nhớ mã zip của mình hay không cho các cuộc trò chuyện sau này.

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();
}

Sau khi hỏi người dùng xem họ đang ở mã bưu chính nào trong hộp thoại đầu tiên, bạn có thể bỏ qua lời nhắc đó trong lần gọi tiếp theo và sử dụng cùng một mã bưu chính. Bạn vẫn nên cung cấp một lối thoát (chẳng hạn như khối đề xuất cho phép họ chọn một mã bưu chính khác) nhưng bằng cách giảm số lượt trò chuyện trong trường hợp phổ biến, bạn sẽ tạo ra một trải nghiệm liền mạch hơn nhiều.

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();
}

Tuỳ chỉnh cho người dùng cũ

Việc duy trì trạng thái nào đó giữa các cuộc trò chuyện đảm bảo cuộc trò chuyện tự nhiên hơn cho người dùng cũ. Bước đầu tiên trong quá trình tạo trải nghiệm này là chào người dùng quay lại theo cách khác. Ví dụ: bạn có thể thu nhỏ lời chào hoặc hiển thị thông tin hữu ích dựa trên các cuộc trò chuyện trước đây. Để thực hiện việc này, hãy sử dụng đến thuộc tính AppRequest.User lastSeen để xác định xem người dùng từng tương tác với Hành động của bạn. Nếu thuộc tính lastSeen được bao gồm trong tải trọng yêu cầu, bạn có thể sử dụng lời chào khác so với bình thường.

Mã bên dưới sử dụng thư viện ứng dụng Node.js để tìm nạp giá trị của 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();
}

Bạn có thể cải thiện lời chào này hơn nữa bằng cách điều chỉnh câu trả lời cho phù hợp với giá trị của lastSeen. Ví dụ: người dùng có tương tác cuối cùng xảy ra nhiều tháng trước khi tương tác hiện tại có thể nhận được lời chào khác với những người đã sử dụng Hành động vào ngày trước đó.

Điều chỉnh âm lượng trong cuộc trò chuyện

Trên các thiết bị được hỗ trợ, Trợ lý cho phép người dùng điều khiển âm lượng của thiết bị trong hành động trò chuyện bằng cách nói những câu như "tăng âm lượng" hoặc "đặt 50%". Nếu bạn có ý định xử lý các cụm từ huấn luyện tương tự, ý định của bạn sẽ được ưu tiên. Bạn nên để Trợ lý xử lý những việc này yêu cầu của người dùng trừ phi Hành động của bạn có lý do cụ thể.