Migra de Dialogflow ES a CX

Los agentes de Dialogflow CX te proporcionan herramientas y controles de conversación más potentes que los agentes de Dialogflow ES. Si tu agente de Dialogflow ES maneja conversaciones complejas, deberías considerar migrar a Dialogflow CX.

En esta guía, se describe cómo migrar un agente de Dialogflow ES a Dialogflow CX. Estos dos tipos de agentes tienen muchas diferencias fundamentales, por lo que no hay una forma sencilla de realizar esta migración.

Si usas esta guía para una migración, envía comentarios positivos o negativos haciendo clic en el Enviar comentarios que se encuentra arriba. Usaremos estos comentarios para mejorar esta guía con el tiempo.

A grandes rasgos, El proceso recomendado es uno híbrido automático o manual. Usarás una herramienta que lea algunos de los datos de tu agente de Dialogflow ES, los escriba en tu agente de Dialogflow CX y capture una lista de tareas pendientes. Luego, vuelve a crear tu agente de CX completo con las prácticas recomendadas, la lista de tareas pendientes y los datos que migró la herramienta.

Comprende Dialogflow CX

Antes de intentar esta migración, deberías tener una comprensión sólida de cómo funciona Dialogflow CX. Puedes comenzar aquí:

  1. Aspectos básicos
  2. Videos de introducción
  3. Guías de inicio rápido

También debes leer los documentos conceptuales adicionales con atributos que probablemente necesites en tu agente nuevo. Concéntrate en lo siguiente:

Comprende las diferencias entre la experiencia del cliente y la experiencia del empleado

En esta sección, se enumeran las diferencias más importantes entre Dialogflow ES y CX. Cuando realices pasos de migración manual más adelante, consulta esta sección para obtener orientación.

Control de la estructura y la ruta de la conversación

ES proporciona lo siguiente para el control de la estructura y la ruta de conversación:

  • Intents se usan como componentes básicos del agente. En cualquier momento de la conversación, se encuentra una coincidencia con un intent y, en cierto sentido, cada intent es un nodo para la conversación.
  • El contexto se usa para controlar la conversación. El contexto se usa para controlar qué intents pueden coincidir en cualquier momento. El contexto expira después de un cierto número de turnos de conversación, por lo que este tipo de control puede resultar inexacto en conversaciones largas.

La CX proporciona una jerarquía de recursos de estructura más precisos y más precisos sobre la ruta de la conversación:

  • Páginas son nodos de gráfico para la conversación. Las conversaciones de CX son similares a las máquinas de estados. En cualquier momento de la conversación, una página está activa. Basado en las entradas o los eventos del usuario final, la conversación puede pasar a otra página. Es común que una página permanezca activa durante varios turnos conversacionales.
  • Flujos son grupos de páginas relacionadas. Cada flujo debe manejar un tema de conversación de alto nivel.
  • Controladores de estado se usan para controlar las transiciones y las respuestas. Existen tres tipos de controladores de estado:
    • Ruta de intent: Contiene un intent que debe coincidir. respuestas opcionales y transición de página opcional.
    • Ruta de condición: Contiene una condición que debe cumplirse. respuestas opcionales y transición de página opcional.
    • Controlador de eventos: contiene un nombre de evento que debe invocarse. respuestas opcionales y transición de página opcional.
  • Alcance se usa para controlar si se puede llamar a un controlador de estado. La mayoría de los controladores se asocian con una página o con todo el flujo. Si la página o el flujo asociados están activos, entonces el controlador estará dentro del alcance y se lo podrá llamar. Una ruta de intent de CX dentro del permiso es similar a un intent de ES con un contexto de entrada que está activo.

Cuando diseñes los flujos y las páginas de tu agente, asegúrate de comprender los consejos de la sección de flujos de la guía de diseño de agentes.

Relleno de formularios

Usos de ES llenado de ranuras para recopilar los parámetros requeridos del usuario final:

  • Estos parámetros son parámetros de intents marcados como obligatorios.
  • El intent seguirá coincidiendo hasta que se recopilen todos los parámetros obligatorios.
  • Puedes definir un mensaje para solicitarle al usuario final que proporcione un valor.

Usos de la CX completar formularios para recopilar los parámetros requeridos del usuario final:

  • Estos parámetros se asocian con una página y se recopilan mientras la página está activa.
  • Usas rutas de condición en las páginas para determinar lo siguiente: se complete el formulario. Por lo general, estas rutas de condición realizan la transición a otra página.
  • Puedes definir una instrucción, así como controladores de reintento para controlar de forma fluida varios intentos de recopilar un valor.

Transiciones

ES pasa automáticamente de un intent al siguiente Cuando la entrada del usuario final coincide con un intent. Esta coincidencia solo se puede producir para intents que no tienen contexto de entrada o intents que tienen un contexto de entrada activo.

La CX realiza transiciones de una página a la siguiente cuando un controlador de estado en el alcance satisface sus requisitos y proporciona un destino de transición. Con estas transiciones, puedes guiar de manera confiable a los usuarios finales en las conversaciones. Existen varias formas de controlar estas transiciones:

  • La coincidencia de intents puede activar una ruta de intents.
  • Satisfacer una condición puede activar una ruta de condición.
  • La invocación de un evento puede activar un controlador de eventos.
  • Los controladores que vuelven a solicitar instrucciones pueden causar una transición cuando falla el usuario final para proporcionar un valor después de varios intentos.
  • Puedes usar objetivos de transición simbólicos para los objetivos de transición.

Respuestas del agente

Las respuestas del agente de ES se envían al usuario final cuando se detecta una coincidencia con un intent:

  • El agente puede seleccionar un mensaje para la respuesta de una lista de respuestas posibles.
  • Las respuestas pueden ser específicas de una plataforma y se pueden usar formatos de respuesta enriquecida.
  • Las respuestas se pueden controlar mediante webhooks.

Las respuestas del agente de CX se envían al usuario final cuando entrega se llama. A diferencia de la entrega ES, que siempre incluye un webhook La entrega de CX puede consistir o no en llamar a un webhook dependiendo de si el recurso de entrega tiene un webhook configurado. Respuestas estáticas y dinámicas basadas en respuestas de webhook se controlan mediante la entrega. Existen varias formas de crear respuestas del agente:

  • La entrega se puede proporcionar a cualquier tipo de controlador de estado.
  • Se pueden concatenar múltiples respuestas durante un turno de conversación a través del cola de respuestas. En algunos casos, esta función puede simplificar el diseño de tu agente.
  • CX no admite respuestas integradas específicas de la plataforma. Sin embargo, proporciona varios tipos de respuestas, incluida una carga útil personalizada que puede usarse para respuestas específicas de la plataforma.

Parámetros

Parámetros de ES tienen las siguientes características:

  • Se define solo en intents.
  • Se establece por entradas del usuario final, eventos, webhooks y llamadas a la API.
  • Se hace referencia a ellos en las respuestas, los mensajes de los parámetros, el código del webhook y los valores de los parámetros:
    • El formato de referencia básico es $parameter-name.
    • Las referencias admiten la sintaxis de sufijos .original, .partial y .recent.
    • Las referencias pueden especificar el contexto activo: #context-name.parameter-name.
    • Las referencias pueden especificar parámetros de eventos: #event-name.parameter-name.

Parámetros de CX tienen las siguientes características:

  • Se definen en los intents y los formularios de página.
  • Los parámetros de intent y formulario son se propaga a los parámetros de sesión y se pueden consultar allí durante toda la sesión.
  • Establecido por la entrada del usuario final, webhooks ajuste predeterminado de los parámetros de entrega, y llamadas a la API.
  • Se hace referencia en las respuestas, en los mensajes de parámetros, en los controladores de solicitudes nuevas, parámetros predeterminados de los parámetros y el código de webhook:
    • El formato de referencia es $session.params.parameter-id para los parámetros de sesión y $intent.params.parameter-id para los parámetros de intent.
    • Las referencias de parámetros de intent admiten la sintaxis de los sufijos .original y .resolved. Los parámetros de sesión no admiten esta sintaxis.

Entidades del sistema

ES admite muchas entidades del sistema.

CX admite muchos de los mismos entidades de sistema pero hay algunas diferencias. Durante la migración, verificar que las entidades de sistema que usas en ES también son compatibles con CX en el mismo idioma. Si no es así, di lo siguiente: debes crear entidades personalizadas para ellos.

Eventos

Eventos de ES tienen las siguientes características:

  • Se puede invocar desde llamadas a la API o webhooks para que coincidan con un intent.
  • Puede establecer parámetros.
  • Las plataformas de integración invocan una pequeña cantidad de eventos.

Eventos de CX tienen las siguientes características:

  • Se puede invocar desde llamadas a la API o webhooks para llamar a un controlador de eventos.
  • No se pueden establecer los parámetros.
  • Se pueden usar muchos eventos integrados para controlar falta de información del usuario final, entrada no reconocida del usuario final, parámetros invalidados por un webhook y errores de webhook.
  • Las invocaciones se pueden controlar con el mismo reglas de alcance como otros controladores de estado.

Intents integrados

ES admite los siguientes intents integrados:

A continuación, se describe la compatibilidad de CX con intents integrados:

  • Intents de bienvenida compatibles.
  • No se proporcionan intents de resguardo. Usa el sin coincidencias en controladores de eventos.
  • Para los ejemplos negativos, usa el intent negativo predeterminado.
  • No se proporcionan intents de seguimiento predefinidos. Debes crear estos intents según lo requiera tu agente. Por ejemplo: es probable que debas crear un intent para manejar respuestas negativas a la pregunta de un agente ("no", "no, gracias", "no, no", etc.). Los intents de CX se pueden volver a usar en todo tu agente, por lo que solo debes definirlos una vez. Mediante el uso de rutas de intents diferentes para estos intents comunes, en diferentes ámbitos, te da un mayor control sobre la conversación.

Webhooks

Webhooks de ES tienen las siguientes características:

  • Puedes configurar un servicio de webhook para el agente.
  • Cada intent se puede marcar como que usa el webhook.
  • No hay compatibilidad integrada para controlar los errores de webhook.
  • Los webhooks usan acciones o nombres de intents para determinar en qué parte del agente se llamó.
  • La consola proporciona editor directo.

Webhooks de CX tienen las siguientes características:

  • Puedes configurar varios servicios de webhook para el agente.
  • Cada entrega puede especificar opcionalmente una llamada de webhook.
  • Hay compatibilidad integrada para manejo de errores de webhook.
  • Un webhook de entrega de CX contiene una etiqueta. Esta etiqueta es similar a una acción ES, pero solo se usa cuando se llama a webhooks. El servicio de webhook puede usar estas etiquetas para determinar desde dónde se llamó al agente.
  • La consola no tiene un editor de código de webhook integrado. Es común usar Cloud Functions, pero hay muchas opciones.

Cuando migres a CX debes cambiar el código del webhook ya que las propiedades de solicitud y respuesta son diferentes.

Integraciones

Integraciones de ES y Integraciones de CX admitir diferentes plataformas. En el caso de las plataformas compatibles con ambos tipos de agentes, puede haber diferencias en la configuración.

Si la integración de ES que usabas no es compatible con CX, quizás debas cambiar de plataforma o implementar la integración por tu cuenta.

Más funciones exclusivas para la CX

Hay muchas otras funciones que solo CX ofrece. Te recomendamos que uses estas funciones durante la migración. Por ejemplo:

Prácticas recomendadas

Antes de migrar, familiarizarte con Prácticas recomendadas para el diseño de agentes de CX. Muchas de estas prácticas recomendadas de la CX son similares a las de ES, pero otros son exclusivos de la CX.

Acerca de la herramienta de migración

La herramienta de migración copia la mayor parte de los datos de ES en tu agente de CX y escribe en un archivo TODO con una lista de elementos que se deben migrar manualmente. La herramienta solo copia tipos de entidades personalizadas y frases de entrenamiento de intents. Deberías personalizar esta herramienta según tus necesidades específicas.

Código de la herramienta de migración

Este es el código de la herramienta. Debes revisar el código de esta herramienta para que comprendas lo que hace. Te recomendamos que cambies este código para controlar situaciones específicas en tu agente. En los pasos que se indican a continuación, ejecutarás esta herramienta.

// Package main implements the ES to CX migration tool.
package main

import (
	"context"
	"encoding/csv"
	"flag"
	"fmt"
	"os"
	"strings"
	"time"

	v2 "cloud.google.com/go/dialogflow/apiv2"
	proto2 "cloud.google.com/go/dialogflow/apiv2/dialogflowpb"
	v3 "cloud.google.com/go/dialogflow/cx/apiv3"
	proto3 "cloud.google.com/go/dialogflow/cx/apiv3/cxpb"
	"google.golang.org/api/iterator"
	"google.golang.org/api/option"
)

// Commandline flags
var v2Project *string = flag.String("es-project-id", "", "ES project")
var v3Project *string = flag.String("cx-project-id", "", "CX project")
var v2Region *string = flag.String("es-region-id", "", "ES region")
var v3Region *string = flag.String("cx-region-id", "", "CX region")
var v3Agent *string = flag.String("cx-agent-id", "", "CX region")
var outFile *string = flag.String("out-file", "", "Output file for CSV TODO items")
var dryRun *bool = flag.Bool("dry-run", false, "Set true to skip CX agent writes")

// Map from entity type display name to fully qualified name.
var entityTypeShortToLong = map[string]string{}

// Map from ES system entity to CX system entity
var convertSystemEntity = map[string]string{
	"sys.address":         "sys.address",
	"sys.any":             "sys.any",
	"sys.cardinal":        "sys.cardinal",
	"sys.color":           "sys.color",
	"sys.currency-name":   "sys.currency-name",
	"sys.date":            "sys.date",
	"sys.date-period":     "sys.date-period",
	"sys.date-time":       "sys.date-time",
	"sys.duration":        "sys.duration",
	"sys.email":           "sys.email",
	"sys.flight-number":   "sys.flight-number",
	"sys.geo-city-gb":     "sys.geo-city",
	"sys.geo-city-us":     "sys.geo-city",
	"sys.geo-city":        "sys.geo-city",
	"sys.geo-country":     "sys.geo-country",
	"sys.geo-state":       "sys.geo-state",
	"sys.geo-state-us":    "sys.geo-state",
	"sys.geo-state-gb":    "sys.geo-state",
	"sys.given-name":      "sys.given-name",
	"sys.language":        "sys.language",
	"sys.last-name":       "sys.last-name",
	"sys.street-address":  "sys.location",
	"sys.location":        "sys.location",
	"sys.number":          "sys.number",
	"sys.number-integer":  "sys.number-integer",
	"sys.number-sequence": "sys.number-sequence",
	"sys.ordinal":         "sys.ordinal",
	"sys.percentage":      "sys.percentage",
	"sys.person":          "sys.person",
	"sys.phone-number":    "sys.phone-number",
	"sys.temperature":     "sys.temperature",
	"sys.time":            "sys.time",
	"sys.time-period":     "sys.time-period",
	"sys.unit-currency":   "sys.unit-currency",
	"sys.url":             "sys.url",
	"sys.zip-code":        "sys.zip-code",
}

// Issues found for the CSV output
var issues = [][]string{
	{"Field", "Issue"},
}

// logIssue logs an issue for the CSV output
func logIssue(field string, issue string) {
	issues = append(issues, []string{field, issue})
}

// convertEntityType converts an ES entity type to CX
func convertEntityType(et2 *proto2.EntityType) *proto3.EntityType {
	var kind3 proto3.EntityType_Kind
	switch kind2 := et2.Kind; kind2 {
	case proto2.EntityType_KIND_MAP:
		kind3 = proto3.EntityType_KIND_MAP
	case proto2.EntityType_KIND_LIST:
		kind3 = proto3.EntityType_KIND_LIST
	case proto2.EntityType_KIND_REGEXP:
		kind3 = proto3.EntityType_KIND_REGEXP
	default:
		kind3 = proto3.EntityType_KIND_UNSPECIFIED
	}
	var expansion3 proto3.EntityType_AutoExpansionMode
	switch expansion2 := et2.AutoExpansionMode; expansion2 {
	case proto2.EntityType_AUTO_EXPANSION_MODE_DEFAULT:
		expansion3 = proto3.EntityType_AUTO_EXPANSION_MODE_DEFAULT
	default:
		expansion3 = proto3.EntityType_AUTO_EXPANSION_MODE_UNSPECIFIED
	}
	et3 := &proto3.EntityType{
		DisplayName:           et2.DisplayName,
		Kind:                  kind3,
		AutoExpansionMode:     expansion3,
		EnableFuzzyExtraction: et2.EnableFuzzyExtraction,
	}
	for _, e2 := range et2.Entities {
		et3.Entities = append(et3.Entities, &proto3.EntityType_Entity{
			Value:    e2.Value,
			Synonyms: e2.Synonyms,
		})
	}
	return et3
}

// convertParameterEntityType converts a entity type found in parameters
func convertParameterEntityType(intent string, parameter string, t2 string) string {
	if len(t2) == 0 {
		return ""
	}
	t2 = t2[1:] // remove @
	if strings.HasPrefix(t2, "sys.") {
		if val, ok := convertSystemEntity[t2]; ok {
			t2 = val
		} else {
			t2 = "sys.any"
			logIssue("Intent<"+intent+">.Parameter<"+parameter+">",
				"This intent parameter uses a system entity not supported by CX English agents. See the migration guide for advice. System entity: "+t2)
		}
		return fmt.Sprintf("projects/-/locations/-/agents/-/entityTypes/%s", t2)
	}
	return entityTypeShortToLong[t2]
}

// convertIntent converts an ES intent to CX
func convertIntent(intent2 *proto2.Intent) *proto3.Intent {
	if intent2.DisplayName == "Default Fallback Intent" ||
		intent2.DisplayName == "Default Welcome Intent" {
		return nil
	}

	intent3 := &proto3.Intent{
		DisplayName: intent2.DisplayName,
	}

	// WebhookState
	if intent2.WebhookState != proto2.Intent_WEBHOOK_STATE_UNSPECIFIED {
		logIssue("Intent<"+intent2.DisplayName+">.WebhookState",
			"This intent has webhook enabled. You must configure this in your CX agent.")
	}

	// IsFallback
	if intent2.IsFallback {
		logIssue("Intent<"+intent2.DisplayName+">.IsFallback",
			"This intent is a fallback intent. CX does not support this. Use no-match events instead.")
	}

	// MlDisabled
	if intent2.MlDisabled {
		logIssue("Intent<"+intent2.DisplayName+">.MlDisabled",
			"This intent has ML disabled. CX does not support this.")
	}

	// LiveAgentHandoff
	if intent2.LiveAgentHandoff {
		logIssue("Intent<"+intent2.DisplayName+">.LiveAgentHandoff",
			"This intent uses live agent handoff. You must configure this in a fulfillment.")
	}

	// EndInteraction
	if intent2.EndInteraction {
		logIssue("Intent<"+intent2.DisplayName+">.EndInteraction",
			"This intent uses end interaction. CX does not support this.")
	}

	// InputContextNames
	if len(intent2.InputContextNames) > 0 {
		logIssue("Intent<"+intent2.DisplayName+">.InputContextNames",
			"This intent uses context. See the migration guide for alternatives.")
	}

	// Events
	if len(intent2.Events) > 0 {
		logIssue("Intent<"+intent2.DisplayName+">.Events",
			"This intent uses events. Use event handlers instead.")
	}

	// TrainingPhrases
	var trainingPhrases3 []*proto3.Intent_TrainingPhrase
	for _, tp2 := range intent2.TrainingPhrases {
		if tp2.Type == proto2.Intent_TrainingPhrase_TEMPLATE {
			logIssue("Intent<"+intent2.DisplayName+">.TrainingPhrases",
				"This intent has a training phrase that uses a template (@...) training phrase type. CX does not support this.")
		}
		var parts3 []*proto3.Intent_TrainingPhrase_Part
		for _, part2 := range tp2.Parts {
			parts3 = append(parts3, &proto3.Intent_TrainingPhrase_Part{
				Text:        part2.Text,
				ParameterId: part2.Alias,
			})
		}
		trainingPhrases3 = append(trainingPhrases3, &proto3.Intent_TrainingPhrase{
			Parts:       parts3,
			RepeatCount: 1,
		})
	}
	intent3.TrainingPhrases = trainingPhrases3

	// Action
	if len(intent2.Action) > 0 {
		logIssue("Intent<"+intent2.DisplayName+">.Action",
			"This intent sets the action field. Use a fulfillment webhook tag instead.")
	}

	// OutputContexts
	if len(intent2.OutputContexts) > 0 {
		logIssue("Intent<"+intent2.DisplayName+">.OutputContexts",
			"This intent uses context. See the migration guide for alternatives.")
	}

	// ResetContexts
	if intent2.ResetContexts {
		logIssue("Intent<"+intent2.DisplayName+">.ResetContexts",
			"This intent uses context. See the migration guide for alternatives.")
	}

	// Parameters
	var parameters3 []*proto3.Intent_Parameter
	for _, p2 := range intent2.Parameters {
		if len(p2.Value) > 0 && p2.Value != "$"+p2.DisplayName {
			logIssue("Intent<"+intent2.DisplayName+">.Parameters<"+p2.DisplayName+">.Value",
				"This field is not set to $parameter-name. This feature is not supported by CX. See: https://cloud.google.com/dialogflow/es/docs/intents-actions-parameters#valfield.")
		}
		if len(p2.DefaultValue) > 0 {
			logIssue("Intent<"+intent2.DisplayName+">.Parameters<"+p2.DisplayName+">.DefaultValue",
				"This intent parameter is using a default value. CX intent parameters do not support default values, but CX page form parameters do. This parameter should probably become a form parameter.")
		}
		if p2.Mandatory {
			logIssue("Intent<"+intent2.DisplayName+">.Parameters<"+p2.DisplayName+">.Mandatory",
				"This intent parameter is marked as mandatory. CX intent parameters do not support mandatory parameters, but CX page form parameters do. This parameter should probably become a form parameter.")
		}
		for _, prompt := range p2.Prompts {
			logIssue("Intent<"+intent2.DisplayName+">.Parameters<"+p2.DisplayName+">.Prompts",
				"This intent parameter has a prompt. Use page form parameter prompts instead. Prompt: "+prompt)
		}
		if len(p2.EntityTypeDisplayName) == 0 {
			p2.EntityTypeDisplayName = "@sys.any"
			logIssue("Intent<"+intent2.DisplayName+">.Parameters<"+p2.DisplayName+">.EntityTypeDisplayName",
				"This intent parameter does not have an entity type. CX requires an entity type for all parameters..")
		}
		parameters3 = append(parameters3, &proto3.Intent_Parameter{
			Id:         p2.DisplayName,
			EntityType: convertParameterEntityType(intent2.DisplayName, p2.DisplayName, p2.EntityTypeDisplayName),
			IsList:     p2.IsList,
		})
		//fmt.Printf("Converted parameter: %+v\n", parameters3[len(parameters3)-1])
	}
	intent3.Parameters = parameters3

	// Messages
	for _, message := range intent2.Messages {
		m, ok := message.Message.(*proto2.Intent_Message_Text_)
		if ok {
			for _, t := range m.Text.Text {
				warnings := ""
				if strings.Contains(t, "#") {
					warnings += " This message may contain a context parameter reference, but CX does not support this."
				}
				if strings.Contains(t, ".original") {
					warnings += " This message may contain a parameter reference suffix of '.original', But CX only supports this for intent parameters (not session parameters)."
				}
				if strings.Contains(t, ".recent") {
					warnings += " This message may contain a parameter reference suffix of '.recent', but CX does not support this."
				}
				if strings.Contains(t, ".partial") {
					warnings += " This message may contain a parameter reference suffix of '.partial', but CX does not support this."
				}
				logIssue("Intent<"+intent2.DisplayName+">.Messages",
					"This intent has a response message. Use fulfillment instead."+warnings+" Message: "+t)
			}
		} else {
			logIssue("Intent<"+intent2.DisplayName+">.Messages",
				"This intent has a non-text response message. See the rich response message information in the migration guide.")
		}
		if message.Platform != proto2.Intent_Message_PLATFORM_UNSPECIFIED {
			logIssue("Intent<"+intent2.DisplayName+">.Platform",
				"This intent has a message with a non-default platform. See the migration guide for advice.")
		}
	}

	return intent3
}

// migrateEntities migrates ES entities to your CX agent
func migrateEntities(ctx context.Context) error {
	var err error

	// Create ES client
	var client2 *v2.EntityTypesClient
	options2 := []option.ClientOption{}
	if len(*v2Region) > 0 {
		options2 = append(options2,
			option.WithEndpoint(*v2Region+"-dialogflow.googleapis.com:443"))
	}
	client2, err = v2.NewEntityTypesClient(ctx, options2...)
	if err != nil {
		return err
	}
	defer client2.Close()
	var parent2 string
	if len(*v2Region) == 0 {
		parent2 = fmt.Sprintf("projects/%s/agent", *v2Project)
	} else {
		parent2 = fmt.Sprintf("projects/%s/locations/%s/agent", *v2Project, *v2Region)
	}

	// Create CX client
	var client3 *v3.EntityTypesClient
	options3 := []option.ClientOption{}
	if len(*v3Region) > 0 {
		options3 = append(options3,
			option.WithEndpoint(*v3Region+"-dialogflow.googleapis.com:443"))
	}
	client3, err = v3.NewEntityTypesClient(ctx, options3...)
	if err != nil {
		return err
	}
	defer client3.Close()
	parent3 := fmt.Sprintf("projects/%s/locations/%s/agents/%s", *v3Project, *v3Region, *v3Agent)

	// Read each V2 entity type, convert, and write to V3
	request2 := &proto2.ListEntityTypesRequest{
		Parent: parent2,
	}
	it2 := client2.ListEntityTypes(ctx, request2)
	for {
		var et2 *proto2.EntityType
		et2, err = it2.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return err
		}
		fmt.Printf("Entity Type: %s\n", et2.DisplayName)

		if *dryRun {
			convertEntityType(et2)
			continue
		}

		request3 := &proto3.CreateEntityTypeRequest{
			Parent:     parent3,
			EntityType: convertEntityType(et2),
		}
		et3, err := client3.CreateEntityType(ctx, request3)
		entityTypeShortToLong[et3.DisplayName] = et3.Name
		if err != nil {
			return err
		}

		// ES and CX each have a quota limit of 60 design-time requests per minute
		time.Sleep(2 * time.Second)
	}
	return nil
}

// migrateIntents migrates intents to your CX agent
func migrateIntents(ctx context.Context) error {
	var err error

	// Create ES client
	var client2 *v2.IntentsClient
	options2 := []option.ClientOption{}
	if len(*v2Region) > 0 {
		options2 = append(options2,
			option.WithEndpoint(*v2Region+"-dialogflow.googleapis.com:443"))
	}
	client2, err = v2.NewIntentsClient(ctx, options2...)
	if err != nil {
		return err
	}
	defer client2.Close()
	var parent2 string
	if len(*v2Region) == 0 {
		parent2 = fmt.Sprintf("projects/%s/agent", *v2Project)
	} else {
		parent2 = fmt.Sprintf("projects/%s/locations/%s/agent", *v2Project, *v2Region)
	}

	// Create CX client
	var client3 *v3.IntentsClient
	options3 := []option.ClientOption{}
	if len(*v3Region) > 0 {
		options3 = append(options3,
			option.WithEndpoint(*v3Region+"-dialogflow.googleapis.com:443"))
	}
	client3, err = v3.NewIntentsClient(ctx, options3...)
	if err != nil {
		return err
	}
	defer client3.Close()
	parent3 := fmt.Sprintf("projects/%s/locations/%s/agents/%s", *v3Project, *v3Region, *v3Agent)

	// Read each V2 entity type, convert, and write to V3
	request2 := &proto2.ListIntentsRequest{
		Parent:     parent2,
		IntentView: proto2.IntentView_INTENT_VIEW_FULL,
	}
	it2 := client2.ListIntents(ctx, request2)
	for {
		var intent2 *proto2.Intent
		intent2, err = it2.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return err
		}
		fmt.Printf("Intent: %s\n", intent2.DisplayName)
		intent3 := convertIntent(intent2)
		if intent3 == nil {
			continue
		}

		if *dryRun {
			continue
		}

		request3 := &proto3.CreateIntentRequest{
			Parent: parent3,
			Intent: intent3,
		}
		_, err := client3.CreateIntent(ctx, request3)
		if err != nil {
			return err
		}

		// ES and CX each have a quota limit of 60 design-time requests per minute
		time.Sleep(2 * time.Second)
	}
	return nil
}

// checkFlags checks commandline flags
func checkFlags() error {
	flag.Parse()
	if len(*v2Project) == 0 {
		return fmt.Errorf("Need to supply es-project-id flag")
	}
	if len(*v3Project) == 0 {
		return fmt.Errorf("Need to supply cx-project-id flag")
	}
	if len(*v2Region) == 0 {
		fmt.Printf("No region supplied for ES, using default\n")
	}
	if len(*v3Region) == 0 {
		return fmt.Errorf("Need to supply cx-region-id flag")
	}
	if len(*v3Agent) == 0 {
		return fmt.Errorf("Need to supply cx-agent-id flag")
	}
	if len(*outFile) == 0 {
		return fmt.Errorf("Need to supply out-file flag")
	}
	return nil
}

// closeFile is used as a convenience for defer
func closeFile(f *os.File) {
	err := f.Close()
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR closing CSV file: %v\n", err)
		os.Exit(1)
	}
}

func main() {
	if err := checkFlags(); err != nil {
		fmt.Fprintf(os.Stderr, "ERROR checking flags: %v\n", err)
		os.Exit(1)
	}
	ctx := context.Background()
	if err := migrateEntities(ctx); err != nil {
		fmt.Fprintf(os.Stderr, "ERROR migrating entities: %v\n", err)
		os.Exit(1)
	}
	if err := migrateIntents(ctx); err != nil {
		fmt.Fprintf(os.Stderr, "ERROR migrating intents: %v\n", err)
		os.Exit(1)
	}
	csvFile, err := os.Create(*outFile)
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR opening output file: %v", err)
		os.Exit(1)
	}
	defer closeFile(csvFile)
	csvWriter := csv.NewWriter(csvFile)
	if err := csvWriter.WriteAll(issues); err != nil {
		fmt.Fprintf(os.Stderr, "ERROR writing CSV output file: %v", err)
		os.Exit(1)
	}
	csvWriter.Flush()
}

Migración de herramientas de tipos de entidades

Tipos de entidades de ES y Tipos de entidades de CX son muy similares, por lo que son los más fáciles de migrar. La herramienta simplemente copia los tipos de entidades tal como están.

Migración de intents de la herramienta

Los intents de ES y los intents de CX son muy diferentes.

Los intents de ES se usan como componentes básicos del agente. y contienen frases de entrenamiento, respuestas para el control de las conversaciones, configuración de webhook, eventos, acciones y parámetros de llenado de ranuras.

Dialogflow CX transfirió la mayoría de estos datos a otros recursos. Los intents de CX solo tienen frases y parámetros de entrenamiento, lo que hace que los intents sean reutilizables en todo el agente. La herramienta solo copia estos dos tipos de datos de intents en tus intents de CX.

Limitaciones de la herramienta de migración

La herramienta de migración no admite lo siguiente:

  • Agentes combinado: La herramienta no puede leer de varios agentes secundarios. pero puedes llamar a la herramienta varias veces con cada agente secundario.
  • Agentes multilingües: Deberías modificar la herramienta. para crear frases de entrenamiento y entradas de entidad multilingües.
  • Verificación de la entidad del sistema para idiomas distintos al inglés: La herramienta crea elementos TODO cuando encuentra entidades del sistema que no están con la asistencia de CX, suponiendo que el inglés es el idioma predeterminado, y que usa una región de EE.UU. La compatibilidad con las entidades del sistema varía según el idioma y la región. Para otros idiomas y regiones, debes modificar la herramienta para realizar esta verificación.

Pasos esenciales para la migración

En las siguientes subsecciones, se describen los pasos de migración que se deben realizar. No es necesario que siga estos pasos manuales en orden. y quizás debas realizar estos pasos simultáneamente o en un orden diferente. Lee los pasos y empieza a planificar tus cambios. antes de hacer cambios.

Después de ejecutar la herramienta de migración, puedes recompilar tu agente de CX. Aún tendrás bastante trabajo de migración pero la mayor parte de los datos ingresados se mostrarán en tu agente de CX y el archivo TODO.

Crea tu agente de Dialogflow CX

Si aún no lo hiciste, Crea tu agente de Dialogflow CX. Asegúrate de usar el mismo idioma predeterminado que tu agente de ES.

Ejecuta la herramienta de migración

Sigue estos pasos para ejecutar la herramienta:

  1. Si aún no lo hiciste, instala Go en tu máquina.
  2. Crea un directorio para el código de la herramienta llamado migrate.
  3. Copia el código de herramienta anterior. a un archivo en este directorio llamado main.go.
  4. Si es necesario, modifica el código para tu caso.
  5. Crea un Módulo Go en este directorio. Por ejemplo:

    go mod init migrate
    
  6. Instala las bibliotecas cliente Dialogflow ES V2 y Dialogflow CX V3 Go:

    go get cloud.google.com/go/dialogflow/apiv2
    go get cloud.google.com/go/dialogflow/cx/apiv3
    
  7. Asegúrate de haber configurado autenticación de bibliotecas cliente.

  8. Ejecuta la herramienta y guarda el resultado en el archivo:

    go run main.go -es-project-id=<ES_PROJECT_ID> -cx-project-id=<CX_PROJECT_ID> \
    -cx-region-id=<CX_REGION_ID> -cx-agent-id=<CX_AGENT_ID> -out-file=out.csv
    

Solución de problemas de la herramienta de migración

Si experimentas errores al ejecutar la herramienta, comprueba lo siguiente:

Error Solución
Error de RPC que indica que una parte de la frase de entrenamiento menciona un parámetro no definido para el intent. Esto puede suceder si anteriormente usaste la API de ES para crear parámetros de intents de una manera que no era coherente con las frases de entrenamiento. Para solucionar este problema, cambia el nombre del parámetro ES desde la consola, verifica que tus frases de entrenamiento usen el parámetro correctamente y, luego, haz clic en Guardar. Esto también puede ocurrir si tus frases de entrenamiento hacen referencia a parámetros inexistentes.

Después de corregir los errores, deberás borrar los intents y las entidades del agente de CX antes de volver a ejecutar la herramienta de migración.

Cómo transferir datos de intents de ES a CX

La herramienta migra las frases y los parámetros de entrenamiento de intents a intents de CX. pero hay muchos otros campos de intents de ES para migrar manualmente.

Un intent de ES puede necesitar una página de CX correspondiente. la intención de CX correspondiente o ambas.

Si se usa una coincidencia de intent de ES para hacer la transición de la conversación de un nodo de conversación en particular a otro, tu agente debería tener dos páginas relacionadas con este intent:

  • La página original que contiene la ruta del intent, que pasará a la página siguiente: La ruta del intent en la página original pueden tener mensajes de entrega de CX similares a las respuestas de intent de ES. Es posible que tengas muchas rutas de intents en esta página. Mientras la página original está activa, estas rutas de intents pueden hacer la transición de la conversación a muchas rutas posibles. Muchos intents de ES compartirán la misma página original de CX correspondiente.
  • En la siguiente página, que es el objetivo de transición para la ruta de intents en la página original: Entrega de entrada de CX para la página siguiente pueden tener mensajes de entrega de CX similares a las respuestas de intent de ES.

Si un intent de ES contiene parámetros obligatorios, debes crear una página de CX correspondiente con los mismos parámetros en un formulario.

Es común que un intent de CX y una página de CX compartan la misma lista de parámetros. lo que significaría que un solo intent de ES tiene una página de CX correspondiente y el intent de CX correspondiente. Cuando se detecta una coincidencia con un intent de CX con parámetros en una ruta de intents, la conversación suele pasar a una página con los mismos parámetros. Los parámetros extraídos de la coincidencia del intent se se propaga a los parámetros de sesión que están disponibles para completar de forma parcial o total los parámetros del formulario de la página.

Los intents de resguardo y los intents de seguimiento predefinidos no existen en CX. Consulta los intents integrados.

En la siguiente tabla, se describe cómo asignar datos de intents específicos de los recursos de ES a CX:

Datos de intents de ES Datos de CX correspondientes Acción obligatoria
Frases de entrenamiento Frases de entrenamiento de intents Migrado por herramienta. La herramienta verifica la compatibilidad de las entidades del sistema y crea elementos TODO para las entidades del sistema no compatibles.
Respuestas del agente Mensajes de respuesta de entrega Consulta las respuestas del agente.
Contexto para el control de conversaciones Ninguno Consulta Estructura y control de la ruta de la conversación.
Configuración del webhook Configuración del webhook de entrega Consulta Webhooks.
Eventos Controladores de eventos a nivel de flujo o de página Consulta los eventos.
Acciones Etiquetas de webhook de entrega Consulta Webhooks.
Parámetros Parámetros de intents o parámetros de formulario de la página Se migró a los parámetros de intents por herramienta. Si los parámetros son obligatorios, la herramienta crea elementos de TODO para posiblemente migrar a una página. Consulta los parámetros.
Mensajes de parámetros Mensajes del parámetro del formulario de página Consulta relleno de formularios.

Crea flujos

Crear un flujo para cada tema de conversación de alto nivel Los temas de cada flujo deben ser distintos, para que la conversación no entre flujos de un flujo a otro con frecuencia.

Si usabas un agente combinado, cada subagente debería convertirse en uno o más flujos.

Comienza con rutas de conversación básicas

Es mejor probar tu agente con el simulador mientras itera los cambios. Por lo tanto, al principio debes enfocarte en las rutas de conversación básicas al principio de la conversación, y pruébalo a medida que haces cambios. Una vez que las pongas en funcionamiento, pasarás a rutas de conversación más detalladas.

Controladores de estado a nivel de flujo frente a los de página

Cuando crees controladores de estado, considera si deben aplicarse a nivel del flujo o a nivel de la página. Un controlador de nivel de flujo se encuentra dentro del alcance (por lo tanto, cualquier página dentro del flujo) está activo. Un controlador de nivel de página solo está dentro del alcance cuando la página específica está activa. Los controladores de nivel de flujo son similares a los intents de ES sin contexto de entrada. Los controladores a nivel de la página son similares a los intents de ES con contexto de entrada.

Código de webhook

Las propiedades de solicitud y respuesta de webhook son diferentes para CX. Consulta la sección de webhooks.

Conectores de conocimiento

CX no es compatible conectores de conocimiento aún. Deberás implementarlos como intents normales o esperar hasta que Dialogflow CX admite conectores de conocimiento.

Configuración de agentes

Revisa tu Configuración del agente de ES, y ajustar Configuración del agente de CX según sea necesario.

Usa el archivo TODO

La herramienta de migración genera un archivo CSV. Los elementos de esta lista se enfocan en datos específicos que pueden requerir atención. Importa este archivo a una hoja de cálculo. Resuelve cada elemento de la hoja de cálculo, usando una columna para marcar como completado.

Migración del uso de la API

Si tu sistema usa la API ES para llamadas de tiempo de ejecución o de diseño, debe actualizar este código para usar el API de CX: Si solo usas las llamadas de detección de intents en el tiempo de ejecución, esta actualización debería ser bastante sencilla.

Integraciones

Si tu agente usa integraciones, consulta la sección de integraciones, y realizar los cambios necesarios.

En las siguientes subsecciones, se describen los pasos de migración recomendados.

Validación

Usa validación del agente para verificar que tu agente siga las prácticas recomendadas.

Prueba

Mientras realizas los pasos de migración manuales mencionados anteriormente, deberías probar tu agente con el simulator. Cuando parezca que tu agente funciona, debes comparar las conversaciones entre los agentes de ES y CX y verificar que el comportamiento sea similar o mejorado.

Mientras pruebas estas conversaciones con el simulador, deberías crear casos de prueba para evitar regresiones futuras.

Entornos

Revisa tu Entornos de ES y actualiza tu Entornos de CX según sea necesario.