Tips implementasi (Dialogflow)

Tinjau tips berikut untuk menerapkan praktik desain percakapan yang baik ke dalam Action Anda.

Mengharapkan variasi

Tangani ini dalam input "Pengguna berkata" di Dialogflow. Selain itu, gunakan lebih dari satu intent yang dapat dipetakan ke tindakan yang sama, dengan setiap intent dapat dipicu dengan berbagai kumpulan frasa "Pengguna mengucapkan".

Memberikan permintaan ulang yang membantu dan gagal dengan baik

Terkadang Action Anda tidak dapat melanjutkan karena tidak menerima input (dikenal sebagai tanpa input) atau tidak memahami input pengguna (dikenal sebagai tidak ada kecocokan). Saat hal ini terjadi, Asisten akan terlebih dahulu mencoba menentukan apakah pengguna ingin memicu Action yang berbeda atau tidak. Jika Asisten tidak mencocokkan input pengguna dengan Action lain, pengguna akan melanjutkan dalam konteks Action Anda. Skenario ini dapat terjadi kapan saja. Jadi, praktik terbaiknya adalah menangani situasi tidak ada input dan tidak cocok secara unik di setiap giliran dalam percakapan dengan penggantian. Dengan menggunakan fallback, Anda dapat membantu pengguna kembali ke jalurnya.

Untuk melakukannya, inisialisasi variabel fallbackCount di objek conv.data Anda, lalu tetapkan ke 0. Siapkan array dari dua perintah penggantian (dieskalasikan dengan jelas), dan perintah penggantian terakhir yang mengakhiri percakapan.

Kemudian, buat intent penggantian (idealnya satu untuk setiap intent yang dapat ditindaklanjuti di agen). Di pengendali intent, tarik jumlah penggantian dari objek conv.data, tambahkan, dan jika kurang dari 3, tarik perintah dari array 3. Jika jumlahnya 4 atau lebih, tutup percakapan menggunakan perintah akhir. Di semua intent yang bukan fallback, reset jumlah fallback ke 0. Idealnya, buat template fallback untuk intent tertentu agar spesifik untuk intent tersebut.

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

Bersiaplah untuk membantu kapan saja

Membuat intent yang memproses frasa bantuan seperti "apa yang bisa saya lakukan?", "apa yang bisa kamu ceritakan", atau "bantuan". Dalam intent ini, tawarkan beberapa respons (berputar) yang menawarkan ringkasan tentang apa yang dapat dilakukan agen dan mengarahkan pengguna ke tindakan yang mungkin dilakukan. Idealnya, gunakan juga intent bantuan tindak lanjut di Dialogflow untuk membuat skenario bantuan yang berbeda untuk berbagai intent yang dapat ditindaklanjuti.

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

Mengizinkan pengguna memutar ulang informasi

Gabungkan semua metode app.ask(output) dengan fungsi proxy yang menambahkan output ke conv.data.lastPrompt. Buat intent berulang yang memproses permintaan untuk diulang dari pengguna seperti "apa?", "mengatakan lagi", atau "dapatkah kamu mengulanginya?". Buat array awalan berulang yang dapat digunakan untuk mengonfirmasi bahwa pengguna meminta sesuatu untuk diulangi. Dalam pengendali intent berulang, panggil ask() dengan string gabungan dari awalan berulang dan nilai conv.data.lastPrompt. Perlu diingat bahwa Anda harus memindahkan tag pembuka SSML jika digunakan pada prompt terakhir.

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

Personalisasi percakapan dengan preferensi pengguna

Action Anda dapat meminta preferensi mereka dan mengingatnya untuk digunakan nanti, sehingga Anda dapat mempersonalisasi percakapan mendatang dengan pengguna tersebut.

Contoh Action ini memberi pengguna laporan cuaca untuk kode pos. Kode contoh berikut menanyakan kepada pengguna apakah mereka ingin Action mengingat kode posnya untuk percakapan berikutnya.

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

Setelah menanyakan kepada pengguna kode pos mana yang mereka gunakan saat dialog pertama, Anda dapat melewati perintah tersebut pada pemanggilan berikutnya dan menggunakan kode pos yang sama. Anda tetap harus menyediakan rute keluar (seperti chip saran yang memungkinkan pengguna memilih kode pos lain), tetapi dengan mengurangi perubahan percakapan pada kasus umum, Anda akan menciptakan pengalaman yang jauh lebih lancar.

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

Sesuaikan untuk pengguna yang kembali

Mempertahankan beberapa status di antara percakapan memastikan pengalaman yang jauh lebih alami bagi pengguna yang kembali. Langkah pertama dalam membuat pengalaman ini adalah menyapa pengguna secara berbeda. Misalnya, Anda dapat mengecilkan salam atau menampilkan informasi yang berguna berdasarkan percakapan sebelumnya. Untuk melakukannya, gunakan properti AppRequest.User lastSeen yang masuk untuk menentukan apakah pengguna telah berinteraksi dengan Action Anda sebelumnya. Jika properti lastSeen disertakan dalam payload permintaan, Anda dapat menggunakan salam yang berbeda dari biasanya.

Kode di bawah ini menggunakan library klien Node.js untuk mengambil nilai 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();
}

Anda dapat meningkatkan kualitas salam ini lebih lanjut dengan menyesuaikan respons ke nilai lastSeen yang sebenarnya. Misalnya, pengguna yang interaksi terakhirnya terjadi beberapa bulan sebelum interaksi saat ini mungkin menerima salam yang berbeda dari pengguna yang menggunakan Action sehari sebelumnya.

Kontrol volume dalam percakapan

Di perangkat yang didukung, Asisten memungkinkan pengguna mengontrol volume perangkat dalam Action percakapan Anda dengan mengucapkan hal-hal seperti "naikkan volume" atau "setel volume ke 50 persen". Jika Anda memiliki intent yang menangani frasa pelatihan serupa, intent Anda akan diprioritaskan. Sebaiknya izinkan Asisten menangani permintaan pengguna ini kecuali jika Action Anda memiliki alasan khusus.