Evalúa la calidad de las frases de entrenamiento en intents de Dialogflow

En este instructivo, se muestra cómo analizar y evaluar la calidad de las frases de entrenamiento proporcionadas a los intents de tu agente de Dialogflow. El propósito de este análisis es evitar que el agente se confunda con frases irrelevantes para los intents a los que se proporcionan o más relevantes para otros intents.

El enfoque que debes tomar es generar incorporaciones semánticas de las frases de entrenamiento mediante el uso del módulo del codificador de oraciones universal de TensorFlow Hub (tf.Hub). Luego, calcularás las medidas de cohesión y separación en función de la similitud entre las incorporaciones dentro de los mismos intents y de intents diferentes. En el instructivo, también se identifican frases de entrenamiento “confusas”, que están más cerca (en el espacio de incorporaciones) de los intents que son diferentes a los que se proporcionaron.

Puedes encontrar el código de este instructivo en este notebook de Colab. En el artículo, se da por hecho que tienes conocimientos básicos previos de Dialogflow. Para obtener más información sobre Dialogflow, consulta este instructivo de varias partes sobre cómo compilar, proteger y escalar un chatbot mediante Dialogflow Enterprise Edition en Google Cloud.

Introducción

Dialogflow te permite compilar interfaces conversacionales sobre tus productos y servicios a través de un motor de comprensión del lenguaje natural (CLN) potente para procesar y comprender entradas de lenguaje natural. Los casos prácticos de Dialogflow incluyen lo siguiente:

  • Compilar bots de reserva para aerolíneas, cines, etcétera
  • Cómo simplificar un sistema a fin de pedir comida rápida para la entrega
  • Habilitar un servicio de atención al cliente eficaz mediante centros de llamadas semiautomáticos

Si bien puedes implementar flujos conversacionales complejos para controlar el enunciado de un usuario, Dialogflow realiza los siguientes pasos:

  1. El usuario hace preguntas como: “¿Cuál es el total de mi factura del último mes?”.
  2. El agente analiza la entrada y la hace coincidir con un intent, como bill_value_inquiry.
  3. El agente también extrae información de entidades, como “el mes pasado”.
  4. Con el intent de las entidades extraídas, el agente invoca una entrega para responder la solicitud del usuario.

En la siguiente tabla, se describen los conceptos clave de la plataforma de Dialogflow.

Término Descripción
agente Los agentes se describen mejor como módulos de CLN que se pueden integrar en tu sistema. Un agente convierte las solicitudes de texto o de voz de los usuarios en datos accionables cuando la entrada de un usuario coincide con un intent en tu agente.
intent En una conversación, los intents asignan las entradas del usuario a las respuestas. En cada intent, defines ejemplos (frases de entrenamiento) de enunciados de usuarios que pueden activarlo, qué se debe extraer de cada enunciado y cómo responderlos.
entidades Cuando los intents permiten que tu agente comprenda la motivación que subyace a una determinada entrada del usuario, las entidades se usan para seleccionar fragmentos específicos de información que tus usuarios mencionan. Por ejemplo, se pueden usar direcciones, nombres de productos o importes con unidades para cumplir con la solicitud del usuario.
entrega La entrega te permite usar la información de la entidad extraída por el agente para generar respuestas dinámicas o activar acciones en tu backend en función de cada intent.

Para obtener más detalles sobre los conceptos de Dialogflow, consulta la documentación de Dialogflow.

Los intents son esenciales para un sistema de Dialogflow, ya que vinculan la solicitud del usuario con la lógica empresarial correcta para cumplirla. Por ejemplo, un sistema de Dialogflow para un proveedor de servicios de telecomunicaciones puede tener intents como bill_value_inquiry, pay_bill, upgrade_contract, cancel_contract y add_service. Sin embargo, para hacer coincidir el enunciado del usuario (texto o voz) con el intent correcto, los intents deben entrenarse con un conjunto de frases de entrenamiento relevantes. Por ejemplo, para un intent de consulta sobre el clima, las frases de entrenamiento podrían ser las siguientes:

  • “¿Cómo está el clima en este momento?”
  • “¿Cuál será la temperatura en El Cairo mañana?”
  • “¿Tengo que llevar un paraguas a Zúrich la próxima semana?”

Cuando creas varios intents en tu sistema, algunas frases que le proporcionas pueden ser confusas o engañosas, por ejemplo, una frase que es más relevante para otro intent puede usarse a fin de entrenar al intent equivocado. Supongamos que tienes un agente de Dialogflow que sirve como fuente de información veraz para una organización de ventas. Es posible que tengas dos intents para recuperar contactos: uno para los equipos de cuentas internos y otro para el cliente. Puedes llamarlos get_internal_contacts y get_external_contacts. Una frase de entrenamiento típica para cada intent sería la siguiente:

  • get_internal_contacts: “¿Quién es el punto de contacto del cliente X?”
  • get_external_contacts: “¿Cómo me comunico con el cliente X?”

Supongamos que tus usuarios proporcionaron la siguiente solicitud mientras buscaban los contactos externos: “Contactos del cliente X”. Es posible que esta solicitud confunda al agente de Dialogflow porque la frase puede coincidir con ambos intents. Si el intent equivocado coincide, los usuarios tendrán una experiencia deficiente porque deberán cambiar la formulación de la solicitud, lo cual resulta molesto y lleva mucho tiempo.

Por lo tanto, debes asegurarte de que las frases dentro del mismo intent tengan una mayor similitud y las frases entre intents diferentes sean menos similares. En el resto del instructivo, se explica cómo evaluar la calidad de la frase de entrenamiento que se proporciona para cada intent y cómo identificar frases de entrenamiento potencialmente confusas.

Enfoque

El enfoque usado en este instructivo es calcular la similitud entre dos frases y, por extensión, calcular la matriz de similitud de todas las frases de entrenamiento. Una vez que tengas esa matriz, podrás calcular lo siguiente:

  • Cohesión: El valor de similitud promedio entre cada par de frases en el mismo intent. Ese valor se calcula para cada intent. Cuanto mayor sea el valor de cohesión del intent, mejores serán sus frases de entrenamiento.
  • Separación: Dados dos intents, la distancia promedio entre cada par de frases de entrenamiento en los dos intents.
  • Frases confusas: Frases de entrenamiento muy similares a las frases de entrenamiento de otros intents.

Para calcular un valor de similitud entre dos frases, debes convertir cada una en un vector de atributos de valor real, que representa la semántica de la frase (incorporaciones). Para ayudarte con esta tarea, en el instructivo se usa TensorFlow Hub (tf.Hub), una biblioteca que se usa para la publicación, el descubrimiento y el consumo de módulos reutilizables de modelos de aprendizaje automático. Estos módulos pueden ser modelos previamente entrenados o incorporaciones extraídas de textos, imágenes, etcétera. Puedes explorar las incorporaciones de texto disponibles. En el instructivo, se emplea el módulo del codificador de oraciones universal (v2), que se usa con el objetivo de codificar texto en vectores de 512 dimensiones que pueden usarse para la clasificación de texto, la similitud semántica, la agrupación en clústeres y otras tareas de lenguaje natural.

En este instructivo, usarás la similitud coseno como una métrica de proximidad entre dos vectores de incorporación. Dados dos vectores de valor real (en nuestro ejemplo, dos vectores de incorporación extraídos de dos frases de entrenamiento), la similitud coseno permite calcular el coseno del ángulo comprendido entre ellos mediante la siguiente fórmula:

$$ \cos(A,B) = \frac{\sum_{i=1}^{n}A_iB_i}{\sqrt{\sum_{i=1}^{n}{A_i^2}}\sqrt{\sum_{i=1}^{n}{B_i^2}}} $$

En esta fórmula, n es la cantidad de elementos en el vector. Cuanto más pequeño sea el ángulo entre los vectores, mayor será el valor del coseno de este ángulo, lo que indica una mayor similitud. El valor de similitud coseno entre dos vectores siempre está entre 0 y 1.

En la Figura 1, se muestra una descripción general del enfoque:

Descripción general de la evaluación de cohesión y separación de intents

Figura 1: Descripción general de la evaluación de cohesión y separación de intents

La figura ilustra la siguiente secuencia:

  1. Importar los intents y sus frases de entrenamiento
  2. Generar incorporaciones para las frases de entrenamiento con el módulo previamente entrenado del codificador de oraciones universal tf.Hub
  3. Crear una visualización de las incorporaciones generadas en un espacio bidimensional
  4. Calcular la matriz de similitud coseno de las incorporaciones, que contiene los valores de similitud en pares entre todas las frases de entrenamiento en diferentes intents
  5. Calcular las métricas de cohesión y separación
  6. Identificar las frases confusas

Objetivos

  • (Opcional) Crear un agente de Dialogflow
  • Importar intents con frases de entrenamiento
  • Ejecutar el notebook de Colab para evaluar la calidad del intent

Costos

En este instructivo, se usan los siguientes componentes facturables de Google Cloud:

  • Dialogflow: La edición estándar es gratuita, mientras que la edición empresarial ofrece Asistencia para empresas paga. Puedes elegir qué edición usar cuando creas tu agente de Dialogflow. Tu cuenta puede incluir agentes de ambas ediciones. Para obtener más detalles, consulta la página de precios de Dialogflow.

Antes de comenzar

  1. Accede a tu Cuenta de Google.

    Si todavía no tienes una cuenta, regístrate para obtener una nueva.

  2. En la página de selección de proyectos de Cloud Console, selecciona o crea un proyecto de Cloud.

    Ir a la página Selector de proyectos

  3. Asegúrate de que la facturación esté habilitada para tu proyecto de Google Cloud. Obtén información sobre cómo confirmar que tienes habilitada la facturación para tu proyecto.

  4. Habilita la API Dialogflow.

    Habilita la API

  5. Crea una cuenta de servicio para llamar a la API de Dialogflow.

    Crear cuenta de servicio
  6. En el cuadro de diálogo Service account details (Detalles de la cuenta de servicio), ingresa el nombre y la descripción de la cuenta como se muestra en la siguiente captura de pantalla y, luego, haz clic en Create (Crear):

    Captura de pantalla del cuadro de diálogo Service account details (Detalles de la cuenta de servicio)
  7. Configura la función como Dialogflow API Client (Cliente de la API de Dialogflow) y haz clic en Continue (Continuar).

    Captura de pantalla del cuadro de diálogo de permisos de la cuenta de servicio

Completa el instructivo en el notebook de Colab

En las siguientes secciones, se explican los pasos que se analizaron en la sección Enfoque para calcular las métricas de cohesión y separación y, también, identificar frases confusas.

Comienza a usar el notebook de Colab

  1. Ve al notebook de Colab: https://colab.research.google.com/drive/....

  2. Crea una copia local en tu Google Drive.

    Copia el notebook a tu Google Drive

  3. En Cloud Shell, instala las bibliotecas de Python necesarias para el resto del instructivo antes de importar las bibliotecas y los módulos requeridos.

    !pip install --quiet --upgrade tensorflow dialogflow scipy tensorflow-hub seaborn
    
  4. Configura el PROJECT_ID de Google Cloud y el SERVICE_ACCOUNT_EMAIL que creaste en la sección Antes de comenzar.

    Configura PROJECT_ID y SERVICE_ACCOUNT_EMAIL de Google Cloud

  5. Autentica tu sesión a fin de crear una clave para tu cuenta de servicio:

    auth.authenticate_user()
    !gcloud config set project {PROJECT_ID}
    !gcloud iam service-accounts keys create sa-key.json \
        --iam-account={SERVICE_ACCOUNT_EMAIL} --project={PROJECT_ID}
    

    Después de ejecutar estos comandos, se mostrará un vínculo.

  6. Síguelo para autenticar tu cuenta de usuario.

  7. Copia el código de autenticación de la página web y pégalo en el campo del notebook Enter verification code (Ingresar código de verificación):

    Campo **Enter verification code** (Ingresar código de verificación) en el notebook

Configura un agente de Dialogflow

Si ya tienes un agente de Dialogflow que desees usar en este instructivo, puedes omitir este paso. Sin embargo, si no tienes un agente o deseas configurar uno nuevo, puedes descargar un archivo ZIP con el contenido de un agente de Dialogflow exportado, llamado intents-healthcheck. Importa este agente a tu cuenta de Dialogflow de la siguiente manera:

  1. Descarga el archivo ZIP del agente importado:

    gsutil cp gs://dialogflow-intent-health-check/intent-quality-demo.zip .
    
  2. Ve a https://dialogflow.com/.

  3. Haz clic en el botón Ir a Console situado en la esquina superior derecha.

  4. En el menú de la izquierda, haz clic en Create new agent (Crear agente nuevo).

    Crear agente nuevo

  5. Ingresa el nombre del agente: intents-healthcheck.

  6. Selecciona tu proyecto de Google Cloud de la lista Proyecto de Google.

    • Un proyecto de Google Cloud solo puede tener un agente de Dialogflow. Por lo tanto, si no encuentras tu proyecto de Google Cloud en la lista, ya hay un agente asociado al proyecto.
    • Si seleccionas Create a new project (Crear un proyecto nuevo), Dialogflow creará un proyecto de Google Cloud con el mismo nombre que tu agente.
  7. Haz clic en Crear.

    Ingresa información sobre el agente

  8. En el menú de la izquierda, selecciona el agente nuevo y haz clic en el ícono Configuración . Luego, en el menú que se encuentra en el centro de la página, selecciona Export and Import (Exportar e importar).

    Cuadro de diálogo Export and Import (Exportar e importar)

  9. Haz clic en Restore from zip (Restablecer desde  ZIP):

    1. Selecciona el archivo agent-backup.zip que descargaste en el paso 1.
    2. Escribe RESTORE en el cuadro de texto que se encuentra en la parte inferior del formulario para realizar la confirmación.
    3. Haz clic en Restore (Restablecer).

    Restablecer el agente desde un Archivo ZIP

    Después de restablecer el agente, Dialogflow creará cinco intents.

  10. Selecciona Intents en el menú de la izquierda para verificar los intents importados. Verás los siguientes intents:

    Verificar los intents importados

Usa este agente restablecido para el resto del instructivo.

Explicación paso a paso del código en el notebook de Colab

En las secciones que siguen, se describen las acciones que realiza el código en el notebook cuando lo ejecutas.

Recupera tus intents

El siguiente código recupera intents y sus frases de entrenamiento del agente de Dialogflow con el método fetch_intents_training_phrases. Este método muestra un diccionario, en el que las claves son los intents nombrados en tu agente de Dialogflow, y cada valor es una lista de las frases de entrenamiento en cada entidad. En el código, project hace referencia al proyecto al que pertenece tu agente y service_account_file al archivo que creaste antes.

def get_intents(service_account_file, project):

    dialogflow_entity_client =  dialogflow.EntityTypesClient.from_service_account_file(service_account_file)
    parent = dialogflow_entity_client.project_agent_path(project)
    entities = list(dialogflow_entity_client.list_entity_types(parent))

    dialogflow_intents_client = dialogflow.IntentsClient.from_service_account_file(service_account_file)
    parent = dialogflow_intents_client.project_agent_path(project)
    intents = list(dialogflow_intents_client.list_intents(
        parent=parent,
        intent_view=dialogflow.enums.IntentView.INTENT_VIEW_FULL))

    entities_name_to_value = {}
    for intent in intents:
        entities_used = {entity.display_name
            for entity in intent.parameters}

        for entity in entities:
            if entity.display_name in entities_used \
                    and entity.display_name not in entities_name_to_value:
                entities_name_to_value[entity.display_name] = np.random.choice(
                    np.random.choice(entity.entities).synonyms, replace=False)

    intent_to_training_phrases = defaultdict(list)
    for intent in intents:
        for training_phrase in intent.training_phrases:
            parts = [entities_name_to_value[part.alias] if part.entity_type else part.text
                for part in training_phrase.parts]
            intent_to_training_phrases[intent.display_name].append("".join(parts))
        # Remove intents with no training phrases
        if not intent_to_training_phrases[intent.display_name]:
            del intent_to_training_phrases[intent.display_name]
    return intent_to_training_phrases
 

El siguiente código verifica los intents recuperados:

intent_training_phrases = fetch_intents_training_phrases("sa-key.json", project_id)
for intent in intent_training_phrases:
    print("{}:{}".format(intent, len(intent_training_phrases[intent])))

El método fetch_intents_training_phrases muestra la siguiente lista. Este fragmento de código muestra los intents en el agente de demostración intents-healthcheck, seguidos del recuento de las frases de entrenamiento disponibles en cada uno.

start_conversation:4
close_conversation:5
get_internal_contacts:17
request_help:7
get_external_contacts:6

Genera incorporaciones para las frases de entrenamiento

El siguiente código descarga el módulo previamente entrenado del codificador de oraciones universal tf.Hub:

embed_module = hub.Module("https://tfhub.dev/google/universal-sentence-encoder/2")

Después del primer uso, el módulo se almacena en caché de forma local.

El siguiente código implementa un método que acepta una lista de oraciones y muestra una lista de incorporaciones basadas en el módulo tf.Hub:

def make_embeddings_fn():
    placeholder = tf.placeholder(dtype=tf.string)
    embed = embed_module(placeholder)
    session = tf.Session()
    session.run([tf.global_variables_initializer(), tf.tables_initializer()])
    def _embeddings_fn(sentences):
        computed_embeddings = session.run(
            embed, feed_dict={placeholder: sentences})
        return computed_embeddings
    return _embeddings_fn

generate_embeddings = make_embeddings_fn()

Este método garantiza que se cree la tf.Session y que el módulo de incorporación se cargue una sola vez y no cada vez que se llama al método.

El siguiente código genera incorporaciones para las frases de entrenamiento en los intents:

{
    intent: {
        training_phrase': [embedding_array]
    }
}

training_phrases_with_embeddings = defaultdict(list)
for intent_name, training_phrases_list in intent_training_phrases.items():
    computed_embeddings = generate_embeddings(training_phrases_list)
    training_phrases_with_embeddings[intent_name] = dict(zip(training_phrases_list, computed_embeddings))

Este fragmento de código crea el diccionario anidado training_phrases_with_embeddings.

El siguiente código verifica las incorporaciones generadas:

training_phrases_with_embeddings = defaultdict(list)
for intent_name, training_phrases_list in intent_training_phrases.items():
    computed_embeddings = generate_embeddings(training_phrases_list)
    training_phrases_with_embeddings[intent_name] = dict(zip(training_phrases_list, computed_embeddings))
 

En el siguiente fragmento de código, se muestra cada frase de entrenamiento en el intent start_conversation, junto con los primeros cinco elementos del vector de incorporación de cada frase. El codificador de oraciones universal genera un vector de incorporación de 512 dimensiones para cada frase de entrenamiento.

Ciao!:[-0.03649221  0.02498418 -0.03456857  0.02827227  0.00471277]
Howdy!:[-0.02732556 -0.00821852 -0.00794602  0.06356855 -0.03726532]
Hello!:[-0.0255452   0.00690543 -0.00611844  0.05633081 -0.0142823 ]
Hi!:[-0.03227544 -0.00985429 -0.01329378  0.06012927 -0.03646606]

Visualiza las incorporaciones en un espacio bidimensional

El siguiente código reduce la dimensionalidad de las incorporaciones de 512 a 2 mediante un análisis de componentes principales para calcular los componentes principales:

from sklearn.decomposition import PCA
embedding_vectors = None

for intent in training_phrases_with_embeddings:
    embeddings = list(training_phrases_with_embeddings[intent].values())
    if embedding_vectors is None:
        embedding_vectors = embeddings
    else:
        embedding_vectors = np.concatenate((only_embeddings, embeddings))

pca = PCA(n_components=3)
pca.fit(embedding_vectors)

Este fragmento de código usa la clase PCA en sklearn para generar una representación 2D de las incorporaciones de frases de entrenamiento.

El siguiente código genera una visualización de las incorporaciones de frases con la dimensionalidad reducida:

import matplotlib.pyplot as plt

fig = plt.figure(figsize=(15,10))
ax = fig.add_subplot(111)

legend = []

for color, intent in enumerate(training_phrases_with_embeddings):
    phrases = list(training_phrases_with_embeddings[intent].keys())
    embeddings = list(training_phrases_with_embeddings[intent].values())
    points = pca.transform(embeddings)
    xs = points[:,0]
    ys = points[:,1]
    ax.scatter(xs, ys, marker='o', s=100, c="C"+str(color))
    for i, phrase in enumerate(phrases):
        ax.annotate(phrase, (xs[i], ys[i]))
    legend.append(intent)

ax.legend(legend)
plt.show()

En la siguiente figura, se muestra la visualización resultante: Visualiza las incorporaciones de frases con la dimensionalidad reducida

Procesamiento de similitud en pares entre frases

El siguiente código calcula la similitud coseno en pares para las incorporaciones de frases de entrenamiento mediante sklearn.metrics.pairwise.cosine_similarity. El código crea un marco de datos, similarity_df, con los valores de similitud en pares.

from sklearn.metrics.pairwise import cosine_similarity

flatten = []
for intent in training_phrases_with_embeddings:
        for phrase in training_phrases_with_embeddings[intent]:
            flatten.append((intent, phrase, training_phrases_with_embeddings[intent][phrase]))

data = []
for i in range(len(flatten)):
    for j in range(i+1, len(flatten)):
        intent_1 = flatten[i][0]
        phrase_1 = flatten[i][1]
        embedd_1 = flatten[i][2]
        intent_2 = flatten[j][0]
        phrase_2 = flatten[j][1]
        embedd_2 = flatten[j][2]
        similarity = cosine_similarity([embedd_1], [embedd_2])[0][0]
        record = [intent_1, phrase_1, intent_2, phrase_2, similarity]
        data.append(record)

similarity_df = pd.DataFrame(data,
    columns=["Intent A", "Phrase A", "Intent B", "Phrase B", "Similarity"])

El siguiente código muestra registros de similitud de ejemplo:

different_intent = similarity_df['Intent A'] != similarity_df['Intent B']
display(similarity_df[different_intent].sort_values('Similarity',
ascending=False).head(5))

El siguiente fragmento de código muestra las frases de entrenamiento más similares que no pertenecen al mismo intent:

Las frases de entrenamiento más similares que no pertenecen al mismo intent

Las frases en diferentes intents que tienen un valor de similitud alto pueden ser confusas para el agente de Dialogflow y podrían direccionar la entrada del usuario a un intent incorrecto.

Mide la cohesión y la separación de intents

El siguiente código calcula un valor de cohesión para cada intent, como se describe en la sección Enfoque.

same_intent = similarity_df['Intent A'] == similarity_df['Intent B']
cohesion_df = pd.DataFrame(similarity_df[different_intent].groupby('Intent A', as_index=False)['Similarity'].mean())
cohesion_df.columns = ['Intent', 'Cohesion']
display(cohesion_df)

El resultado es un valor de cohesión para cada intent:

Calcular un valor de cohesión para cada intent

El siguiente código calcula la separación en pares entre intents, como se describe en la sección Enfoque.

different_intent = similarity_df['Intent A'] != similarity_df['Intent B']
separation_df = pd.DataFrame(similarity_df[different_intent].groupby(['Intent A', 'Intent B'], as_index=False)['Similarity'].mean())
separation_df['Separation'] = 1 - separation_df['Similarity']
del separation_df['Similarity']
display(separation_df.sort_values('Separation'))

El resultado es la separación en pares entre intents:

Calcular la separación en pares entre intents

Mejoras adicionales

Para mejorar la calidad de las frases de entrenamiento de tus intents, considera los siguientes enfoques:

  • Busca frases con una similitud alta en diferentes intents y cámbialas o quítalas.
  • Busca las frases más similares que pertenecen a diferentes intents.
  • Agrega más frases de entrenamiento en intents con baja cohesión y, también, investiga frases de entrenamiento en intents con baja separación.

Realiza una limpieza

  1. En Cloud Console, ve a la página Administrar recursos.

    Ir a la página Administrar recursos

  2. En la lista de proyectos, selecciona el proyecto que deseas borrar y haz clic en Borrar .
  3. En el cuadro de diálogo, escribe el ID del proyecto y haz clic en Cerrar para borrar el proyecto.

Próximos pasos