Suggerimenti per l'implementazione (Dialogflow)

Esamina i seguenti suggerimenti per implementare buone pratiche di progettazione della conversazione nell'Azione.

Sono previste variazioni

Puoi gestirlo nell'input "L'utente dice" in Dialogflow. Inoltre, utilizza più intent che possono essere mappati alla stessa azione, in cui ogni intent può essere attivato con insiemi diversi di frasi di tipo "L'utente dice".

Invia richieste utili e fallisce correttamente

A volte l'Azione non può andare avanti perché non ha ricevuto un input (noto come nessun input) o non ha capito l'input di un utente (noto come no-match). In questo caso, l'assistente tenta innanzitutto di determinare se l'utente vuole attivare un'azione diversa. Se l'Assistente non corrisponde all'input dell'utente a un'altra Azione, l'utente continua nel contesto dell'Azione. Questo scenario può verificarsi in qualsiasi momento, quindi la best practice prevede di gestire in modo univoco situazioni senza input e senza corrispondenza a ogni turno di una conversazione con un fallback. Utilizzando i fallback, puoi aiutare gli utenti a tornare in pista.

A questo scopo, inizializza una variabile fallbackCount nell'oggetto conv.data e impostala su 0. Prepara un array di due prompt di riserva (aumento della chiarezza) e un prompt di riserva finale che termini la conversazione.

Poi, crea un intent di riserva (preferibilmente uno per ogni intento strategico nell'agente). Nel gestore di intent, estrai il conteggio di fallback dall'oggetto conv.data, incrementalo e, se è inferiore a 3, estrai il prompt dall'array su 3. Se il conteggio è pari o superiore a 4, chiudi la conversazione utilizzando il prompt finale. In tutti gli intent che non sono di riserva, reimposta il conteggio dei fallback su 0. Idealmente, modelli di fallback per intenti specifici che siano specifici di questi ultimi.

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

Preparati ad aiutarti in qualsiasi momento

Crea un intent che ascolti frasi di assistenza come "cosa posso fare?", "cosa puoi dirmi" o "aiuto". A questo scopo, offri alcune risposte (a rotazione) che offrano una panoramica di ciò che può fare l'agente e indirizzi gli utenti a una possibile azione. Idealmente, puoi anche utilizzare intent di assistenza di follow-up in Dialogflow per creare diversi scenari di assistenza per intent strategici diversi.

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

Consenti agli utenti di riprodurre le informazioni

Racchiudi tutti i metodi app.ask(output) con una funzione proxy che aggiunge l'output a conv.data.lastPrompt. Crea un intent ripetuto che ascolti richieste che si ripetono, ad esempio "cosa?" "ripetilo" oppure "riesci a ripetere?". Crea un array di prefissi ripetitivi che possono essere utilizzati per confermare che l'utente ha chiesto di ripetere qualcosa. Nel gestore di intent di ripetizione, chiama ask() con una stringa concatenata del prefisso di ripetizione e il valore di conv.data.lastPrompt. Dovrai spostare tutti i tag di apertura SSML, se utilizzati nell'ultimo prompt.

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

Personalizza la conversazione con le preferenze dell'utente

L'Azione può chiedere agli utenti le loro preferenze e memorizzarle per utilizzarle in un secondo momento, consentendoti di personalizzare conversazioni future con l'utente.

In questo esempio l'Azione offre agli utenti un bollettino meteo relativo a un codice postale. Il codice di esempio riportato di seguito chiede all'utente se vuole che l'Azione memorizzi il codice postale per le conversazioni successive.

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

Dopo aver chiesto all'utente quale codice postale si trova nella prima finestra di dialogo, puoi saltare la richiesta alla successiva chiamata e utilizzare lo stesso codice postale. Dovresti comunque fornire una via di fuga (ad esempio un chip di suggerimento che consenta di scegliere un codice postale diverso), ma riducendo un turno di conversazione nel caso comune, crei un'esperienza molto più fluida.

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

Personalizza per gli utenti di ritorno

Il mantenimento di uno stato tra una conversazione e l'altra garantisce un'esperienza molto più naturale per gli utenti di ritorno. Il primo passo per creare questa esperienza è accogliere gli utenti di ritorno in modo diverso. Ad esempio, puoi perfezionare il saluto o mostrare informazioni utili in base alle conversazioni passate. A questo scopo, utilizza la proprietà lastSeen in arrivo AppRequest.User per determinare se l'utente ha già interagito con l'Azione in precedenza. Se la proprietà lastSeen è inclusa nel payload della richiesta, puoi utilizzare un saluto diverso dal normale.

Il codice seguente utilizza la libreria client Node.js per recuperare il valore di 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();
}

Puoi migliorare ulteriormente questo saluto personalizzando la risposta sul valore effettivo di lastSeen. Ad esempio, gli utenti la cui ultima interazione si è verificata molti mesi prima dell'interazione corrente potrebbero ricevere un saluto diverso rispetto a quelli che hanno utilizzato l'Azione il giorno precedente.

Controllo del volume nelle conversazioni

Sui dispositivi supportati, l'assistente consente agli utenti di regolare il volume del dispositivo nell'ambito dell'Azione conversazionale dicendo, ad esempio, "alza il volume" o "imposta il volume al 50%". Se hai intent che gestiscono frasi di addestramento simili, hanno la precedenza. Ti consigliamo di consentire all'assistente di gestire queste richieste degli utenti, a meno che l'Azione non abbia un motivo specifico.