Un asistente contextual que va más allá de las simples interacciones de estilo de preguntas frecuentes requiere algo más que un algoritmo y una oración. Un asistente de conversación debe haber recopilado los detalles importantes necesarios para responder las preguntas de los usuarios en el contexto adecuado. De lo contrario, no se conseguirá un resultado positivo. Bastante simple, y conocido como slot filling. Pero, ¿cómo reúnes y defines los detalles que son importantes antes de tomar acción o proporcionar una respuesta?

Este proceso es fácil con nuestra última novedad de FormPolicy. Esta es una característica nueva que implementa el slot filling de una manera fácil y efectiva. ¿Cómo? FormPolicy te permite cubrir todos los caminos felices con una sola historia. Los formularios también te permiten alterar la lógica en un camino feliz, sin necesidad de cambiar los datos de entrenamiento.

Entonces, ¿cómo implementar esta nueva técnica? Me alegra que hayas preguntado. Aquí te indicamos cómo hacer que FormPolicy lo haga todo por ti.

Contorno

  1. Introducción al slot filling.

2. Construyendo un asistente de búsqueda de restaurantes usando los nuevos formularios:

  • Paso 1: Extraer detalles de las entradas del usuario utilizando Rasa NLU.
  • Paso 2: Entrenando el modelo de diálogo: manejando el camino feliz con formas.
  • Paso 3: Definiendo el dominio.
  • Paso 4: Definiendo la FormAction.
  • Paso 5: Expandir FormAction para manejar casos más avanzados.
  • Paso 6: Manejo de las desviaciones del camino feliz.
  • Paso 7: Probando el asistente de búsqueda de restaurante.

3. Resumen

4. Recursos útiles.

Introducción al slot filling

La presentación de slots es un proceso de recopilación de información importante para cumplir con la solicitud del usuario. Se trata de tener datos relevantes a mano que pueden ser útiles en una conversación determinada.

Tomemos como ejemplo un asistente de búsqueda de restaurantes para ilustrarlo. Antes de que el asistente pueda realizar una acción de búsqueda en un restaurante, debe conocer las preferencias de los usuarios, como el tipo de restauración, el rango de precios, la ubicación, etc., para poder hacer una sugerencia útil.

Para almacenar dicha información, Rasa Core utiliza ranuras (slots). En casos simples, puede implementar el slot filling utilizando solo ranuras (slots), pero las cosas se complican rápidamente una vez que la complejidad de las conversaciones crece. Con más detalles, vienen más posibles giros de diálogo, lo que crea mayores y mayores requisitos de datos de capacitación. Aquí es donde FormAction viene al rescate. Te permite imponer una lógica estricta en el proceso de recopilación de información y reducir considerablemente la cantidad de datos de capacitación necesarios para construir un buen modelo de diálogo.

Construyendo un asistente de búsqueda de restaurantes usando Rasa Forms

En la parte restante de este tutorial, aprenderás cómo usar la nueva FormPolicy en la realidad. Este tutorial se basa en un asistente de búsqueda de restaurantes llamado formbot. Puedes encontrar todo el código dentro del repositorio de Rasa Core GitHub :

git clone https://github.com/RasaHQ/rasa_core.git
cd rasa_core/examples/formbot

Al seguir este tutorial y usar el código dentro del repositorio, construirás un asistente divertido, capaz de sugerir restaurantes según las preferencias del usuario, como el tipo de cocina, el número de personas, el lugar que prefieres y otros requisitos posibles. Aquí puedes encontrar una recreación de una conversación real con el chatbot:

Paso 1: Extraer detalles de las entradas del usuario utilizando Rasa NLU

Antes de almacenar información importante como ranuras, el asistente debe extraerlas de las entradas del usuario.

Para que tu asistente pueda hacer eso, es necesario entrenar el modelo NLU que clasificará la intención de las entradas del usuario y extraerá detalles importantes como entidades.

El ejemplo de Formbot ya viene con ejemplos de entrenamiento que puedes usar para entrenar el modelo NLU. Utilizando los ejemplos de capacitación proporcionados, puedes enseñar a tu asistente a comprender entradas como saludos, consultas de búsqueda de restaurantes, entradas para suministrar la información solicitada, etc., y luego extraer entidades como tipo de restaurante, cantidad de personas, requisitos adicionales, etc. Puedes encontrar la capacitación de NLU ejemplos dentro del archivo data/nlu_data.md del ejemplo formbot.

Para entrenar el modelo, ejecuta el siguiente comando. Este comando es un comando de shell de acceso directo que llamará a la función Rasa NLU train, pasará los datos de entrenamiento y los archivos de configuración del modelo y guardará el modelo dentro del directorio models / nlu / current de su directorio de trabajo:

make train-nlu

Nota: si eres nuevo en Rasa NLU y deseas obtener más información al respecto, asegúrate de consultar la documentación de Rasa NLU.

Paso 2: Entrenando el modelo de diálogo: manejando el camino feliz con formas

Una vez que el asistente es capaz de comprender las entradas del usuario, es hora de construir un modelo de gestión de diálogo. Al usar Formularios para rellenar espacios, es mejor comenzar por entrenar al modelo para manejar los caminos felices, situaciones en las que el usuario proporciona toda la información requerida y le permite al asistente dirigir la conversación.

Lo mejor de las nuevas formas es que el asistente aprende a manejar todos los caminos felices de una sola historia de entrenamiento. Mira el video de abajo para ver la ilustración:

¿Cómo funciona?

Una vez que restaurant_form predice la “acción de formulario”, el asistente sigue pidiendo los detalles necesarios hasta que se configuren todos los espacios requeridos. No hay restricciones sobre la forma en que el usuario debe proporcionar los detalles: si un usuario especifica todas las preferencias en la solicitud inicial del restaurante, por ejemplo, “Reserve una mesa para dos en el restaurante chino”, el asistente omitirá las preguntas sobre la cocina y número de personas.

Si el usuario no especifica ninguno de estos detalles en una solicitud inicial, el asistente pregunta todos los detalles en las preguntas de seguimiento hasta que se proporcionen todos ellos. Ambas situaciones representan dos conversaciones diferentes (puede haber más de dos), pero al usar FormsPolicy, ambas se aprenderán usando la misma historia. A continuación se muestra un fragmento de la historia de entrenamiento utilizada para modelar todos los caminos felices en un ejemplo de formbot:

## happy path   * greet   - utter_greet   * request_restaurant   - restaurant_form   - form{"name": "restaurant_form"}   - form{"name": null}   - utter_slots_values   * thankyou   - utter_noworries

Consulte el archivo data/stories.md del ejemplo de Formbot para investigar las historias de capacitación con más detalle.

Paso 3: Definiendo el dominio

Para entrenar el modelo de gestión de diálogos con Rasa Core, también necesitas definir el dominio . Aquí es donde puedes especificar qué detalles extraídos deben almacenarse como ranuras.

Hay tres cosas importantes que debes considerar al definir el dominio para un asistente con el llenado de espacios:

  1. En Rasa Core, diferentes tipos de slots tienen una influencia diferente en las predicciones de la siguiente acción. Cuando utilizas FormAction para llenar los espacios, estás aplicando reglas estrictas que le dicen a tu asistente qué información debe solicitar a continuación. De esta manera, permite que FormAction maneje todos los caminos felices en una sola historia, ya que verifica qué ranuras solicitadas están completas y cuáles no. Para que esto funcione, las ranuras solicitadas en tu archivo de dominio deben definirse como no modificadas.
  2. Los nombres de las plantillas que se utilizarán para solicitar las ranuras necesarias faltantes deben seguir el formato utter_ask_ {slotname}. Esto es importante para que FormAction sepa qué plantilla usar para qué ranura.
  3. Además de todas las partes habituales del dominio (intenciones, entidades, plantillas, acciones y ranuras), deberás incluir una sección adicional llamada formularios. Esta sección debe incluir los nombres de todas las acciones de formulario que tu asistente debe poder predecir en función de las historias definidas en un archivo de datos de entrenamiento.

A continuación se muestra un fragmento del dominio utilizado en un ejemplo de formbot:

entities:   - cuisine   - num_people   - number   - feedback   - seatingslots:   cuisine:   type:unfeaturized   auto_fill:false   num_people:    type: unfeaturized    auto_fill: false    outdoor_seating:    type: unfeaturized    auto_fill: false    preferences:    type: unfeaturized    auto_fill: false    feedback:    type: unfeaturized    auto_fill: false    requested_slot:    type: unfeaturizedforms:    - restaurant_form

Paso 4: Definiendo la FormAction

El siguiente paso es implementar la FormAction que, una vez predicha, manejará el llenado de la ranura. Puedes implementar todas las FormActions en el archivo actions.py donde implementarías cualquier otra acción personalizada que te gustaría que tu asistente maneje. Vamos a definir la formAction para el relleno de la ranura auxiliar restaurante paso a paso (echa un vistazo a la actions.py archivo del ejemplo formbot para ver un código completo):

  • Primero, define la clase de acción de formulario. Ten en cuenta que las acciones de formulario, a diferencia de las acciones personalizadas normales, heredan de la clase FormAction:
  • La primera función que debes definir en una clase de acción de formulario se llama nombre, que simplemente define el nombre de la acción (la misma que definiste en el archivo de dominio). En un ejemplo de búsqueda de restaurante se define como restaurant_form:
  • A continuación, una función llamada required_slots se usa para definir una lista de ranuras que el asistente debe completar antes de responder a la solicitud del usuario:

Consejo profesional: la función required_slots es un gran lugar para introducir alguna lógica de ranura personalizada. Por ejemplo, podría tener sentido incluir la opción de asientos al aire libre solo para los restaurantes de una cocina específica. Puedes lograr esto introduciendo una lógica simple como en el ejemplo que te muestro a continuación, donde la ranura outdoor_seating solo será necesaria cuando los usuarios piden restaurantes que sirven comida griega:

  • El bloque de construcción final de una acción de formulario simple es una función llamada enviar que define lo que debería suceder una vez que se completen todos los espacios requeridos. En el caso de un asistente de búsqueda de restaurantes, una vez que se completen todas las ranuras, el asistente ejecutará la plantilla utter_submit que, en función de cómo se haya definido en un archivo domain.yml, confirmará que el asistente tiene toda la información que necesita para continuar:

Y ahí lo tienen, una implementación simple de FormAction. Hay mucho más que puedes agregar para permitir que tu asistente maneje casos aún más avanzados. Veamos esto en el siguiente paso de este tutorial.

Paso 5: Manejo de casos avanzados con FormAction

Algunas ranuras necesarias pueden provenir de entradas de usuario muy diferentes. Por ejemplo, el usuario podría responder a la pregunta “¿Te gustaría sentarte afuera?” Con las siguientes respuestas:

  • ‘Sí’
  • ‘No’
  • “Prefiero estar sentado en el interior” (o una respuesta directa similar).

Cada una de estas respuestas corresponde a diferentes intenciones o tiene diferentes entidades importantes, pero dado que proporcionan una respuesta viable a la pregunta, un asistente debe poder aceptarlo y establecer un espacio para avanzar.

Aquí es donde entra en juego la función slot_mappings en una FormAction: define cómo extraer valores de slot de las posibles respuestas de los usuarios y los asigna a un slot específico. A continuación se muestra un ejemplo de la función slot_mappings para la outdoor_seating comentada anteriormente . De acuerdo con la lógica definida, la outdoor_seating se rellenará utilizando:

  • Valor ‘Verdadero’ si el usuario responde con la intención ‘afirmar’ a la pregunta.
  • Valor ‘False’ si el usuario responde con la intención ‘deny’ a la pregunta.
  • Valor de la entidad extraída seating.

Puedes encontrar más ejemplos de asignación de ranura dentro de la slot_mappings función del actions.py archivo del ejemplo formbot.

def slot_mappings(self):      # type: () -> Dict[Text: Union[Dict, List[Dict]]]      """A dictionary to map required slots to      - an extracted entity      - intent: value pairs      - a whole message or a list of them, where a first                                    match will be picked"""        return { "outdoor_seating": [self.from_entity(entity="seating"),                        self.from_intent(intent='affirm',                                                   value=True),                        self.from_intent(intent='deny',                                                   value=False)]}

Otra cosa útil que puedes hacer con FormAction es la validación de espacios. Por ejemplo, antes de permitir que tu asistente continúe con las preguntas, es posible que desees verificar el valor de la ranura con los valores posibles en tu base de datos o verificar si el valor está en el formato correcto. Puedes lograrlo creando una función llamada validaren su clase de FormAction. De forma predeterminada, comprueba si se extrajo la ranura solicitada, pero puedes agregar tanta lógica adicional como sea necesario. A continuación se muestra un ejemplo de la función de validación que primero verifica si la ranura solicitada se completó y luego verifica si el número de personas proporcionado está en el formato correcto: si el número es un número entero, el asistente usará el valor proporcionado, si no responderá con un mensaje que indica que el formato del valor de la ranura no es válido, establece la ranura en Ninguno y solicítalo nuevamente.

def validate(self,                   dispatcher: CollectingDispatcher,                   tracker: Tracker,                   domain: Dict[Text, Any]) -> List[Dict]:      """Validate extracted requested slot              else reject the execution of the form action      """      # extract other slots that were not requested      # but set by corresponding entity      slot_values = self.extract_other_slots(dispatcher, tracker, domain)        # extract requested slot      slot_to_fill = tracker.get_slot(REQUESTED_SLOT)      if slot_to_fill:          slot_values.update(self.extract_requested_slot(dispatcher,                                                         tracker, domain))          if not slot_values:              # reject form action execution              # if some slot was requested but nothing was extracted              # it will allow other policies to predict another action              raise ActionExecutionRejection(self.name(),                                             "Failed to validate slot {0}"                                             "with action {1}"                                             "".format(slot_to_fill,                                                           self.name()))        # we'll check when validation failed in order      # to add appropriate utterances      for slot, value in slot_values.items():            if slot == 'num_people':              if not self.is_int(value) or int(value) <= 0:                  dispatcher.utter_template('utter_wrong_num_people',                                                tracker)                  # validation failed, set slot to None                  slot_values[slot] = None

Puedes encontrar más ejemplos de la validación ranura (comprobación de la base de datos, cadena coincidente) en el actions.py archivo del ejemplo formbot.

Paso 6: Manejo de las desviaciones del camino feliz.

La idea principal detrás del relleno de ranuras con FormAction es que se aplica una lógica estricta para recopilar las piezas importantes de información y manejar el camino feliz, mientras que el aprendizaje automático normal se utiliza para manejar con gracia las desviaciones del camino feliz. Estas desviaciones pueden ser algunos mensajes de chat en medio de la sesión de acción de formulario o las situaciones en las que los usuarios se niegan a proporcionar todos los detalles necesarios. Para manejar situaciones como esta, tienes que escribir las historias que representan esos giros de conversación.

Por ejemplo, la historia a continuación representa la situación en la que el usuario decidió dejar de proporcionar la información en medio de la sesión de acción de formulario, pero luego regresó para proporcionar los detalles necesarios:

## stop but continue path  * request_restaurant   - restaurant_form   - form{"name": "restaurant_form"}  * stop   - utter_ask_continue  * affirm   - restaurant_form   - form{"name": null}   - utter_slots_values  * thankyou   - utter_noworries

Para permitir que tu asistente maneje casos aún más avanzados, necesitas recopilar más historias como esta para cubrir diferentes turnos de diálogo. En algunas situaciones, es posible que desees manejar las rutas infelices de manera diferente según la ranura que el usuario solicite actualmente. Para lograrlo, dentro del archivo de dominio debe configurarse requested_slot categórico. Esto permitirá que las predicciones de la próxima respuesta se vean influenciadas según la ranura que se solicite actualmente.

Consulta el archivo data/stories.md del ejemplo de formbot para ver más posibles historias de ruta infelices.

Paso 7: Probando el asistente de búsqueda de restaurante

Ya has aprendido mucho sobre la implementación de FormAction y has definido todos los bits necesarios del modelo de gestión de diálogo. Ahora es el momento de la parte más emocionante: ¡probar al asistente!

Primero, entrena el modelo de gestión de diálogos utilizando el siguiente comando que llamará a la función de tren de Rasa Core, te pasará el dominio y los archivos de datos, y almacenará el modelo entrenado dentro del directorio de modelos / diálogo de tu directorio de trabajo:

make train-core

Una vez que el modelo está entrenado, ¡es hora de cargarlo junto con el modelo NLU previamente entrenado, y probar cómo funciona el robot de búsqueda de restaurantes!

Primero, en un nuevo terminal, inicia un servidor patito ejecutando el siguiente comando:

docker run -p 8000:8000 rasa/duckling

Inicia tu asistente ejecutando el siguiente comando que activará el servidor local para acciones personalizadas y cargará el asistente para que pueda chatear:

make run

Para ver mejor cómo funciona FormAction, dedica un tiempo a probar cómo se desempeña el asistente en diferentes caminos felices e infelices.

Resumen

Construir buenos asistentes contextuales no es fácil. La combinación de FormAction con el ML tradicional te permite crear asistentes que pueden manejar conversaciones más profundas sin tener que escribir muchas historias de entrenamiento para manejar el camino feliz. Además de esto, FormAction hace que sea mucho más fácil realizar cambios en el código y el diálogo de tu asistente, ya que las ranuras solicitadas no se utilizan directamente en las historias de capacitación.

¡Prueba los nuevos formularios en tus propios conjuntos de datos y comparte tus comentarios con nosotros uniéndote a la discusión en este hilo del Foro de la Comunidad Rasa!

Recursos

Por Justina Petraitytė

Data scientist, desarrollador de inteligencia artificial conversacional y educador con la pasión por crear excelentes aplicaciones y convertir los datos en conocimientos significativos y productos innovadores. Tengo más de 5 años de experiencia en la industria en la implementación de soluciones de aprendizaje automático para diversos problemas comerciales (predicción de retención de usuarios, agrupación en clústeres, motores de recomendación, PNL, IA conversacional), consulta de datos y gestión de datos, análisis de datos, informes y visualización de datos.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *