Blog de Amazon Web Services (AWS)

Creación de chatbots complejos encadenando intenciones en Amazon Lex (Intentos de cadena)

Por Giovanna Chiaratti, Arquitecta de Soluciones AWS Brasil

 

Introducción

Digamos que abriste una pizzería. Con la finalidad de automatizar el servicio y reducir los costos,  piensas en crear un chatbot para automatizar el cumplimiento de pedidos y de esta manera acelerar el servicio; dando a los clientes mayor autonomía y reduciendo costos. Sería interesante incluir la posibilidad de pedir una entrada y un postre, además de la pizza, con ello aumentaría el promedio del costo por pedido.

Amazon Lex es una solución a esta necesidad. Pero, ¿Cómo podemos enfocar esto en Amazon Lex para que el usuario pase por todas las posibilidades (entrada, pizza y postre)?

En este blog explicaré cómo crear un chatbot en AWS utilizando Amazon Lex, un servicio para crear interfaces de conversación en cualquier aplicación usando voz y texto, encadenando intenciones y creando árboles de decisión para que el usuario tenga una mejor experiencia y pueda vender más.

 

Resumen de la solución

Amazon Lex es el organizador de su ChatBot. En Amazon Lex, podrá configurar cuáles son las intenciones potenciales de un usuario. La intención es la acción principal que un usuario puede realizar. En nuestro ejemplo, el usuario puede querer pedir una entrada, una pizza, un postre o los tres.

Consideremos que: pedir una entrada es la primera intención, pedir una pizza sería la segunda intención y pedir un postre es la tercera intención. Nuestro objetivo es guiar al usuario a través de las tres intenciones, en el orden lógico para el mejor servicio y una mejor funcionalidad de nuestra aplicación.

El primer punto es decidir o dibujar la lógica que debe tener su chatbot, es decir, qué intención debe presentarse primero al usuario, la segunda y la tercera. En nuestro ejemplo, parece que hay un orden lógico. Vale la pena esta reflexión cuando pensamos en chatbots más complejos antes de dibujar el chatbot en sí.

En esta reflexión se debe tener en cuenta la lógica de su aplicación, las formas de respuestas apropiadas y la intersección de intenciones.

Vamos a entender los componentes del chatbot. Como vimos antes, las intenciones son las opciones generales que un usuario puede elegir en su chatbot, por lo que serían: ordenar una entrada, ordenar una pizza, ordenar un postre o bien ordenar los tres. Las intenciones están construidas por ranuras.

Las ranuras son parámetros, son las características de las intenciones. Las ranuras se presentan a los usuarios, generalmente en forma de pregunta.

Pensando en nuestro ejemplo, la intención es «pedir una pizza» y la ranura sería «pizza con borde relleno o no», «pizza con masa delgada o gruesa», «pizza con queso o no», así sucesivamente. En la intención de «pedir un postre», las ranuras podrían ser: «jarabe de chocolate?» , «¿Quieres 01 o 02 unidades?» , etc. Es decir, las ranuras son parámetros de las intenciones

Spoiler: Las ranuras recopilan detalles, información o parámetros para que AWS Lambdas pueda consultar o enviar el pedido. AWS Lambdas conserva la lógica del chatbot.

 

 

 

Así que la conversación va al usuario para llenar las ranuras de la intención «Pedir pizza». Es importante recordar que cada intención puede tener cinco ranuras, es decir, hay cinco especificaciones que se pueden hacer dentro de la intención. Si desea agregar más especificaciones, debe agregar más intenciones.

Ahora, siguiendo el flujo de nuestro chatbot pizzería, después de completar la intención «Ordenar Pizza» el usuario será dirigido a la intención «Pedir postre». Hay dos opciones para encadenar estas intenciones. El primero es: en el momento en que el usuario responde a todas las ranuras en la intención «Ordenar Pizza», el chatbot devuelve una respuesta intuitiva, como:

«¡Su pedido se ha realizado correctamente! Le gustaría incluir:

  • Una entrada
  • Un postre».

 

En el momento en que el usuario ingrese la palabra «postre», si se trata de palabras clave «Pedir postre» (enunciado), Lex dirigirá al usuario a la intención «Pedir postre» y le dirigirá a responder a todas las ranuras para ese propósito.

La segunda forma de dirigir al usuario a otra intención es a través de Lambda.

 

Mano en la masa

Amazon Lex se integra de forma nativa con funciones de Lambda. Lambda es la lógica detrás del chatbot: las funciones lambda reciben respuestas del usuario a las ranuras (parámetros) y las procesan. Lambda nos permite utilizar Amazon Lex para desarrollar chatbots complejos, como consultas de bases de datos, transformación y actualización desde cualquier otro sistema, integrándose con más de 175 servicios de AWS.  Desde  Lambda, puede llamar a cualquier otro servicio de AWS u otros Lambdas y podemos pensar exhaustivamente, como enviar mensajes a colas de SQS, actualizar un banco de datos en SQL y mucho más.

En nuestro ejemplo, el usuario será dirigido a la siguiente intención «Pedir postre».

Tenga en cuenta que, como hablamos antes, cada intención puede tener hasta cinco ranuras (parámetros). Para el encadenado de intenciones realizadas a través de funciones lambda utilizaremos una de las ranuras de la siguiente intención para recibir la respuesta de la intención anterior. A continuación puede ver una explicación gráfica:

 

 

 

La respuesta del usuario «Pay» será popular la primera ranura «tipo» [tipo de postre, Pay o pastel] de la intención «Order Postre». ¿Cómo sucede eso?

 

 

Veamos cómo las funciones lambda están estructuradas para recibir la respuesta de las ranuras y también cómo encadenar intenciones a través de lambda.

Recuerda, cada vez que mencionamos al usuario aquí, estaremos hablando del cliente en la pizzería.

Amazon Lex es responsable de llenar los espacios de una intención que pida y obtener las respuestas de los usuarios. Una vez completada la intención, Amazon Lex envía una carga útil json con la información recopilada a un Lambda que procesa, almacena o hace lo que sea necesario con ella y devuelve una respuesta a Amazon Lex indicando qué hacer a continuación.

 

RequestID: XXXXXXXX

{

  "alternativeIntents": [

    {

      "intentName": "AMAZON.FallbackIntent",

      "nluIntentConfidence": null,

      "slots": {}

    }

  ],

  "botVersion": "$LATEST",

  "dialogState": "ReadyForFulfillment",

  "intentName": "pedirPizza",

  "message": null,

  "messageFormat": null,

  "nluIntentConfidence": {

    "score": 1

  },

  "responseCard": null,                #caso houvesse um ResponseCard configurado

  "sentimentResponse": null,           # o Amazon Lex enviaria outra resposta.

  "sessionAttributes": {},

  "sessionId": "2021-02-03TXXXXXXXXXX ",

  "slotToElicit": null,

  "slots": {

    "borda": "sim",

    "queijo": "mozarela",

    "sabor": "peperoni",

    "slotFour": "fina",

    "tamanho": "8"

  }

}

 

Como dijimos, el json anterior es rellenado por Amazon Lex con todas las ranuras que recogió del usuario para la intención Order Pizza y enviado como parámetro de entrada a Lambda, que se define en el campo «Fulfillment — AWS Lambda Function».

Este json de entrada de Lambda refleja la configuración realizada en la Figura 1.

 

 

Esta función Lambda debe devolver como respuesta otro json en el formato que Amazon Lex espera. Este formato se define aquí.

 

Consejo: Si agregó una ResponseCard, aparecerá en la posición señalada por la flecha en la figura anterior.

 

A continuación mostramos el código de la función Lambda en Python 3.7 que procesa la intención Order Pie.

 

Este Lambda recibe de Amazon Lex el json [def lambda_handler] anterior y procesa la información recopilada en las ranuras según la lógica que escriba [def c_pizza], como guardar la elección del cliente en un artículo de pedido en un medio persistente (por ejemplo, un BD) para luego enviar el pedido a la cocina. Después de este procesamiento, Lambda responde la información a Amazon Lex en el formato requerido aquí como devolución del método [def ResPostaPizza]:

 

def respostaPizza(pedidoPizza):
    if pedidoPizza["success"]:
        return {
            "dialogAction": {
                "type": "ElicitSlot",
                "message": {
                    "contentType": "PlainText",
                    "content": "Seu pedido foi feito com sucesso. Gostaria de pedir um brigadeiro ou beijinho?."
                },
                "intentName": "pedirSobremesa",
                "slotToElicit": "tipo"
            }
        }
    else:
        return {
            "dialogAction": {
                "type": "Close",
                "fulfillmentState": "Fulfilled",
                "message": {
                    "contentType": "PlainText",
                    "content": "Houve um erro"
                },

            }
        }



def c_pizza(sabor, tamanho, borda, massa, queijo):
    pedidoPizza = []       #sua lógica do código...
   
    return pedidoPizza

def lambda_handler(event, context):
    pedidoPizza = c_pizza(event["currentIntent"]["slots"]["sabor"], event["currentIntent"]["slots"]["tamanho"], event["currentIntent"]["slots"]["borda"], event["currentIntent"]["slots"]["massa"], event["currentIntent"]["slots"]["queijo"])
    return respostaPizza(pedidoPizza) #aqui passamos os parâmetros dos slots para a                                                            #função respostaPizza.

 

Lo que se ha descrito anteriormente, completa la intención orden pizza. Pero también queríamos encadenar la intención de pedir postre para ofrecer al usuario la oportunidad de añadir postre a su solicitud. Para dirigir al usuario al postre orden de intención, es decir, para encadenar este siguiente intento, agregamos a la respuesta devuelta por nuestro Lambda el DialogAction.Type: ElicitsLot y le informamos de la siguiente intención a través del campo IntenName:Order Postre, como se muestra en la figura a continuación.

Al recibir esta respuesta, Amazon Lex reanuda el control, guiando al usuario a negar o responder a las ranuras de esta intención , pedir postre, de acuerdo a su deseo.

Al llegar al final de este árbol de decisiones, es decir, al final del servicio al usuario, donde se le ofrecieron todas las intenciones posibles al que pudiera o no haber aceptado la «oferta» de cada una, la última llamada Lambda puede componer la solicitud agregando los datos recogidos y almacenados previamente en un medio persistente y enviarlo a una cola de Amazon SQS. Pero este es el tema de un próximo blog.

 

def respostaPizza(ordem):
    if ordem["success"]:
        return {
            "dialogAction": {
                "type": "ElicitSlot",
                "message": {
                    "contentType": "PlainText",
                    "content": "Seu pedido foi feito com sucesso. Gostaria de pedir um brigadeiro ou beijinho?"                                                                                     #mensagem para o usuário
                },
                "intentName": "pedirSobremesa",         #próximo intent a ser mostrado
                "slotToElicit": "tipo"                  #próximo slot a ser mostrado
            }
        }
    else:
        return {
            "dialogAction": {
                "type": "Close",
                "fulfillmentState": "Fulfilled",
                "message": {
                    "contentType": "PlainText",
                    "content": "Houve um erro"
                },

            }
        }

 

Conclusión

Con este, paso a paso, vemos que podemos encadenar intenciones en Amazon Lex y crear árboles de decisión elaborados, guiar al usuario de forma granular, adaptar el chatbot a las necesidades de nuestra aplicación e integrar el chatbot con sistemas externos a través de llamadas API realizadas por funciones de Lambda.

Podemos ir más allá e integrar Amazon Lex con servicios que se conectan con funciones de Lambda, lo que significa que puede coordinar servicios dentro y fuera de AWS, implementar Amazon Lex en múltiples plataformas como Slack, Facebook y Twilio, entre otros sistemas empresariales como Salesforce y Zendesk. ¡Oh! Y no se olvide: implementar un chatbot complejo debe ir acompañado de una buena pizza.

 

 

 


Sobre a autora

Giovanna Chiaratti es arquitecta de soluciones para socios en América Latina enfocada en países de habla hispana.  Admirador y estudioso de tecnologías como el aprendizaje automático, la inteligencia artificial y el servidor sin servidor.  Trabaja para escalar los socios de consultoría y tecnología para ayudar a AWS a crear soluciones seguras, innovadoras e inteligentes.

 

 

 

Revisores

Fernando Batagin Junior actúa como arquitecto de soluciones para socios, guiándolos a través del proceso de integración o implementación de sus soluciones de software en AWS. Profundo conocimiento de ingeniería de software, se centra en la modernización de las soluciones de socios existentes en Brasil. Cuenta con veinte años de experiencia en diseño y desarrollo de software, principalmente en banca, pasando por varios lenguajes como C, C++, Java, JavaScript, VisualBasic y C# y metodologías de modelado como UML.

 

 

 

Gerson Itiro Hidaka actualmente trabaja como arquitecto de soluciones de AWS y presta servicios a socios de todo el mundo denominados Integradores e influenciadores de sistemas globales (GSII) en la región de América Latina. Entusiasta de tecnologías como Internet de las cosas (IOT), drones, Devops y un experto en tecnologías como la virtualización, sin servidor, contenedor y Kubernetes. Ha trabajado con soluciones de TI durante más de 24 años, con experiencia en numerosos proyectos de infraestructura, red, migración, recuperación ante desastres y optimización de DevOps en su cartera.