Conseils d'implémentation (Dialogflow)

Consultez les conseils suivants pour implémenter de bonnes pratiques de conception des conversations dans votre action.

Variations attendues

Gérez ce problème dans l'entrée "L'utilisateur dit" dans Dialogflow. En outre, utilisez plusieurs intents pouvant être mappés à la même action, chaque intent pouvant être déclenché avec différents ensembles d'expressions "L'utilisateur dit".

Fournir de nouvelles invites et échouer en douceur

Il arrive que votre action ne puisse pas avancer parce qu'elle n'a pas reçu d'entrée (appelée "no-input") ou parce qu'elle n'a pas compris l'entrée utilisateur (appelée "no-match"). Lorsque cela se produit, l'Assistant tente d'abord de déterminer si l'utilisateur souhaite déclencher une autre action. Si l'Assistant ne fait pas correspondre l'entrée utilisateur à une autre action, l'utilisateur poursuit dans le contexte de votre action. Ce scénario peut se produire à tout moment. Par conséquent, la bonne pratique consiste à gérer de manière unique les situations de non-entrée et de non-correspondance à chaque tour d'une conversation avec une solution de remplacement. Les créations de remplacement peuvent aider les utilisateurs à se remettre sur la bonne voie.

Pour ce faire, initialisez une variable fallbackCount dans votre objet conv.data et définissez-la sur 0. Préparez un tableau de deux invites de remplacement (escaladées de manière plus claire) et une dernière invite de remplacement qui met fin à la conversation.

Créez ensuite un intent de remplacement (idéalement un intent pour chaque intent exploitable dans l'agent). Dans le gestionnaire d'intents, extrayez le nombre de créations de remplacement de l'objet conv.data, incrémentez-le, puis, s'il est inférieur à 3, extrayez l'invite du tableau de 3. Si le nombre est égal ou supérieur à 4, fermez la conversation à l'aide de la dernière invite. Dans tous les intents qui ne sont pas des solutions de secours, réinitialisez le nombre de créations de remplacement sur 0. Idéalement, modéliser les solutions de remplacement pour des intents spécifiques afin qu'elles soient spécifiques à ceux-ci.

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

Soyez prêt à vous aider à tout moment

Créez un intent qui écoute les phrases d'aide telles que "Que puis-je faire ?", « que peux-tu me dire » ou « aide ». Dans cet intent, proposez une réponse (en rotation) qui donne un aperçu de ce que l'agent peut faire et redirige les utilisateurs vers une action possible. Idéalement, utilisez également les intents d'aide de suivi dans Dialogflow afin de créer différents scénarios d'aide pour différents intents exploitables.

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

Permettre aux utilisateurs de revoir des informations

Encapsulez toutes vos méthodes app.ask(output) avec une fonction de proxy qui ajoute la sortie à conv.data.lastPrompt. Créez un intent de répétition qui écoute les invites de répétition de l'utilisateur telles que "quoi ?", « Dites ça encore » ou « Pouvez-vous répéter ça ? ». Créez un tableau de préfixes répétés permettant de confirmer que l'utilisateur a demandé une répétition de l'élément. Dans le gestionnaire d'intents de répétition, appelez ask() avec une chaîne concaténée du préfixe de répétition et la valeur de conv.data.lastPrompt. N'oubliez pas que vous devrez déplacer toutes les balises d'ouverture SSML si elles sont utilisées dans la dernière invite.

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

Personnaliser la conversation avec les préférences utilisateur

Votre action peut demander aux utilisateurs leurs préférences et les mémoriser pour une utilisation ultérieure, ce qui vous permet de personnaliser les futures conversations avec cet utilisateur.

Cet exemple d'action fournit aux utilisateurs un bulletin météo pour un code postal. L'exemple de code suivant demande à l'utilisateur s'il souhaite que l'action mémorise son code postal pour les conversations ultérieures.

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

Après avoir demandé à l'utilisateur dans quel code postal il se trouve lors de sa première boîte de dialogue, vous pouvez ignorer cette invite lors du prochain appel et utiliser le même code postal. Vous devez toujours fournir un itinéraire d'échappement (comme un chip de suggestion leur permettant de choisir un autre code postal), mais en réduisant le tour de conversation dans le cas courant, vous créez une expérience beaucoup plus fluide.

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

Personnaliser pour les utilisateurs connus

Le maintien d'un certain état entre les conversations garantit une expérience beaucoup plus naturelle pour les utilisateurs connus. La première étape de la création de cette expérience consiste à saluer les utilisateurs renvoyés différemment. Par exemple, vous pouvez affiner le message d'accueil ou afficher des informations utiles en fonction des conversations précédentes. Pour ce faire, utilisez la propriété lastSeen AppRequest.User entrante pour déterminer si l'utilisateur a déjà interagi avec votre action. Si la propriété lastSeen est incluse dans la charge utile de la requête, vous pouvez utiliser un message d'accueil différent de celui d'habitude.

Le code ci-dessous utilise la bibliothèque cliente Node.js pour récupérer la valeur de 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();
}

Vous pouvez améliorer encore ce message d'accueil en adaptant la réponse à la valeur réelle de lastSeen. Par exemple, les utilisateurs dont la dernière interaction s'est produite plusieurs mois avant l'interaction en cours peuvent recevoir un message d'accueil différent de ceux qui ont utilisé l'action la veille.

Contrôle du volume des conversations

Sur les appareils compatibles, l'Assistant permet aux utilisateurs de contrôler le volume de l'appareil dans votre action de conversation en énonçant des commandes comme "Monte le son" ou "Règle le volume sur 50 %". Si certains de vos intents gèrent des phrases d'entraînement similaires, ils sont prioritaires. Nous vous recommandons de laisser l'Assistant gérer ces requêtes des utilisateurs, sauf si votre action a une raison spécifique de le faire.