Revisa las siguientes sugerencias para implementar prácticas recomendadas de diseño de conversaciones en tu acción.
Se esperan variaciones
Administra esto en la entrada "El usuario dice" en Dialogflow. Además, usa más de un intent que pueda asignarse a la misma acción, en el que cada intent se pueda activar con diferentes conjuntos de frases de "El usuario dice".
Proporciona solicitudes útiles y falla con facilidad
A veces, tu acción no puede avanzar porque no recibió una entrada (conocida como no entrada) o no comprendió la entrada del usuario (conocida como no coincidencia). Cuando esto sucede, Asistente primero determina si el usuario desea activar una acción diferente. Si Asistente no hace coincidir la entrada del usuario con otra acción, el usuario continúa en el contexto de tu acción. Esto puede suceder en cualquier momento, por lo que la práctica recomendada es controlar de forma única las situaciones sin entrada y sin coincidencia en cada turno en una conversación con un resguardo. Con los resguardos, puedes ayudar a los usuarios a recuperar el ritmo.
Para ello, inicializa una variable fallbackCount
en tu objeto conv.data
y establécela en 0. Prepara un arreglo de dos mensajes de resguardo (que se escalan con mayor claridad) y un mensaje de resguardo final que finalice la conversación.
Luego, crea un intent de resguardo (lo ideal sería uno para cada intent accionable en el agente). En el controlador del intent, extrae el recuento de resguardo del objeto conv.data
, auméntalo y, si es inferior a 3, extrae el mensaje del arreglo de 3. Si el recuento es 4 o más, cierra la conversación con el mensaje final. En todos los intents que no sean de resguardo, restablece el recuento de resguardo a 0.
Lo ideal es que las plantillas de los intents para que los intents específicos sean específicos.
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(); }
Esté preparado para ayudarlo en cualquier momento
Crear un intent que escuche frases de ayuda, como "¿qué puedo hacer?" "¿Qué puedes decirme?" o "Ayuda". En este intent, ofrece una respuesta (rotación) que ofrezca una descripción general de lo que puede hacer el agente y dirige a los usuarios a una acción posible. Lo ideal es que también uses intents de ayuda de seguimiento en Dialogflow a fin de crear diferentes situaciones de ayuda para diferentes intents accionables.
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(); }
Permitir que los usuarios vuelvan a reproducir información
Une todos tus métodos app.ask(output)
con una función de proxy que agregue el resultado a conv.data.lastPrompt
. Crea un intent repetido que escuche los mensajes para que el usuario repita, como “¿qué?”, "¿Puedes repetirlo?" o "¿Puedes repetirlo?". Crea un arreglo de prefijos de repetición que puedas usar para reconocer que el usuario solicitó que se repitiera algo. En el controlador de intents repetidos, llama a ask()
con una string concatenada del prefijo de repetición y el valor de conv.data.lastPrompt
. Ten en cuenta que deberás cambiar cualquier etiqueta de apertura de SSML si se usa en el último mensaje.
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(); }
Personaliza la conversación con las preferencias del usuario
Tu acción puede pedirles a los usuarios sus preferencias y recordarlas para usarlas más adelante, lo que te permite personalizar las conversaciones futuras con ese usuario.
Esta acción de ejemplo ofrece a los usuarios un informe del clima para un código postal. El siguiente código de ejemplo le pregunta al usuario si desea que la acción recuerde su código postal para conversaciones posteriores.
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(); }
Después de preguntarle al usuario en qué código postal se encuentra durante su primer diálogo, puedes omitir ese mensaje en su próxima invocación y usar el mismo código postal. De todos modos, debes proporcionar una ruta de escape (como un chip de sugerencia que les permita elegir un código postal diferente), pero, cuando se reduce un giro de conversación en el caso común, se crea una experiencia mucho más 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(); }
Personalizar para usuarios recurrentes
Mantener cierto estado entre las conversaciones garantiza una experiencia mucho más natural para los usuarios recurrentes. El primer paso para diseñar esta experiencia es saludar a los usuarios recurrentes de manera diferente. Por ejemplo, puedes mostrar el saludo o mostrar información útil en función de conversaciones pasadas. Para ello, usa la propiedad AppRequest.User
lastSeen
entrante a fin de determinar si el usuario interactuó con tu acción anteriormente. Si la propiedad lastSeen
se incluye en la carga útil de la solicitud, puedes usar un saludo diferente al normal.
El siguiente código usa la biblioteca cliente de Node.js para recuperar el valor 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(); }
Puedes mejorar aún más este saludo si adaptas la respuesta al valor real de lastSeen
. Por ejemplo, es posible que los usuarios cuya última interacción ocurrió varios meses antes de la interacción actual reciban un saludo diferente que los que usaron la acción el día anterior.
Control de volumen en conversaciones
En los dispositivos compatibles, Asistente permite a los usuarios controlar el volumen del dispositivo dentro de tu acción de conversación con frases como "sube el volumen" o "establece el volumen al 50%". Si tienes intents que controlan frases de entrenamiento similares, tus intents tienen prioridad. Te recomendamos que permitas que Asistente controle estas solicitudes de usuario, a menos que tu acción tenga un motivo específico.