Migrazione da Dialogflow ES a CX

Gli agenti Dialogflow CX offrono controlli e strumenti per le conversazioni più potenti rispetto agli agenti Dialogflow ES. Se l'agente Dialogflow ES gestisce conversazioni complesse, ti consigliamo di eseguire la migrazione a Dialogflow CX.

Questa guida descrive come eseguire la migrazione di un agente da Dialogflow ES a Dialogflow CX. Questi due tipi di agenti presentano molte differenze fondamentali, pertanto non esiste un modo semplice per eseguire la migrazione.

Se utilizzi questa guida per una migrazione, fornisci un feedback positivo o negativo facendo clic sul pulsante Invia feedback qui sopra. Utilizzeremo questo feedback per migliorare la guida nel tempo.

A livello generale, il processo consigliato è un processo ibrido automatizzato/manuale. Utilizzerai uno strumento che legge alcuni dati dell'agente Dialogflow ES, li scrive nell'agente Dialogflow CX e acquisisce un elenco DA FARE. Quindi ricrei l'agente CX completo utilizzando le best practice, l'elenco DA FARE e i dati di cui è stata eseguita la migrazione dallo strumento.

Informazioni su Dialogflow CX

Prima di tentare questa migrazione, dovresti avere una solida comprensione di come funziona Dialogflow CX. Puoi iniziare da qui:

  1. Informazioni di base
  2. Video introduttivi
  3. Guide rapide

Dovresti anche leggere altri documenti concettuali con funzionalità che probabilmente ti serviranno nel nuovo agente. Concentrati sui seguenti aspetti:

Capire le differenze tra ES/CX

Questa sezione elenca le differenze più importanti tra Dialogflow ES e CX. Quando esegui i passaggi di migrazione manuale in un secondo momento, consulta questa sezione per indicazioni.

Controllo di struttura e percorso di conversazione

ES offre quanto segue per il controllo della struttura e del percorso di conversazione:

  • Gli intent sono utilizzati come componenti di base dell'agente. In qualsiasi punto della conversazione, viene abbinato un intent e, in un certo senso, ogni intent è un nodo per la conversazione.
  • Il contesto viene utilizzato per controllare la conversazione. Il contesto viene utilizzato per controllare quali intent possono essere abbinati in un determinato momento. Il contesto scade dopo un determinato numero di turni conversazionali, quindi questo tipo di controllo può non essere preciso per le conversazioni lunghe.

CX offre una gerarchia di risorse strutturate e controlli più precisi sul percorso di conversazione:

  • Le pagine sono nodi di grafico per la conversazione. Le conversazioni CX sono simili alle macchine a stato. In qualsiasi momento della conversazione, è attiva una pagina. In base agli input o agli eventi dell'utente finale, la conversazione può passare a un'altra pagina. È normale che una pagina rimanga attiva per più turni di conversazione.
  • I flussi sono gruppi di pagine correlate. Ogni flusso deve gestire un argomento di conversazione generale.
  • I gestori degli stati vengono utilizzati per controllare le transizioni e le risposte. Esistono tre tipi di gestori di stato:
    • Route dell'intent: contiene un intent che deve essere abbinato, risposte facoltative e una transizione di pagina facoltativa.
    • Route della condizione: contiene una condizione da soddisfare, risposte facoltative e una transizione di pagina facoltativa.
    • Gestore di eventi: contiene il nome di un evento da richiamare, risposte facoltative e una transizione di pagina facoltativa.
  • L'ambito viene utilizzato per controllare se è possibile chiamare un gestore di stato. La maggior parte dei gestori è associata a una pagina o a un intero flusso. Se la pagina o il flusso associati sono attivi, il gestore rientra nell'ambito e può essere chiamato. Una route di intent CX nell'ambito è simile a un intent ES con un contesto di input attivo.

Quando progetti i flussi e le pagine dell'agente, assicurati di comprendere i consigli riportati nella sezione relativa ai flussi della guida alla progettazione dell'agente.

Compilazione moduli

ES utilizza il riempimento degli slot per raccogliere i parametri richiesti dall'utente finale:

  • Questi parametri sono parametri di intent contrassegnati come obbligatori.
  • L'intent continua a essere abbinato finché non vengono raccolti tutti i parametri obbligatori.
  • Puoi definire un prompt in cui chiedi all'utente finale di fornire un valore.

CX utilizza la compilazione di moduli per raccogliere i parametri richiesti dall'utente finale:

  • Questi parametri sono associati a una pagina e vengono raccolti mentre la pagina è attiva.
  • Puoi utilizzare le route delle condizioni per le pagine per determinare che la compilazione del modulo è stata completata. Questi percorsi di condizione in genere passano a un'altra pagina.
  • Puoi definire un prompt e i gestori di richieste di ripetizione per gestire agevolmente più tentativi di raccolta di un valore.

Transizioni

ES passa automaticamente da un intent all'altro quando l'input utente finale viene associato a un intent. Questa corrispondenza può verificarsi solo per intent che non hanno un contesto di input o che hanno un contesto di input attivo.

L'esperienza cliente passa da una pagina all'altra quando un gestore di stati nell'ambito soddisfa i propri requisiti e fornisce un obiettivo di transizione. Con queste transizioni puoi guidare in modo affidabile gli utenti finali nelle conversazioni. Esistono diversi modi per controllare queste transizioni:

  • La corrispondenza degli intent può attivare una route di intent.
  • Se soddisfi una condizione, è possibile attivare una route di condizione.
  • La chiamata di un evento può attivare un gestore di eventi.
  • I gestori di richieste di ripetizione possono causare una transizione quando l'utente finale non riesce a fornire un valore dopo più tentativi.
  • Puoi utilizzare i target di transizione simbolici per i target di transizione.

Risposte degli agenti

Le risposte dell'agente ES vengono inviate all'utente finale quando viene soddisfatta un intent:

  • L'agente può selezionare un messaggio per la risposta da un elenco di possibili risposte.
  • Le risposte possono essere specifiche della piattaforma, che può utilizzare formati di risposta avanzata.
  • Le risposte possono essere generate dai webhook.

Le risposte dell'agente CX vengono inviate all'utente finale quando viene chiamato il fulfillment. A differenza del fulfillment ES, che prevede sempre un webhook, il fulfillment CX può prevedere o meno la chiamata a un webhook, a seconda che per la risorsa di fulfillment sia stato configurato un webhook. Sia le risposte statiche che dinamiche basate sulle risposte webhook sono controllate dal fulfillment. Esistono diversi modi per creare le risposte degli agenti:

  • L'evasione degli ordini può essere fornita a qualsiasi tipo di gestore di stato.
  • È possibile concatenare più risposte durante una svolta conversazionale tramite la coda di risposte. In alcuni casi, questa funzionalità può semplificare la progettazione dell'agente.
  • CX non supporta risposte specifiche della piattaforma integrate. Tuttavia, fornisce più tipi di risposta, tra cui un payload personalizzato che può essere utilizzato per risposte specifiche della piattaforma.

Parametri

I parametri ES hanno le seguenti caratteristiche:

  • Definita solo negli intent.
  • Impostata in base a input utente finale, eventi, webhook e chiamate API.
  • Con riferimento a risposte, prompt dei parametri, codice webhook e valori dei parametri:
    • Il formato di riferimento di base è $parameter-name.
    • I riferimenti supportano la sintassi del suffisso .original, .partial e .recent.
    • I riferimenti possono specificare il contesto attivo: #context-name.parameter-name.
    • I riferimenti possono specificare i parametri evento: #event-name.parameter-name.

I parametri CX hanno le seguenti caratteristiche:

  • Definiti negli intent e nei moduli delle pagine.
  • I parametri di intent e di modulo vengono propagati ai parametri di sessione, dove sono disponibili come riferimento per la durata della sessione.
  • Impostato per input utente finale, webhook, preimpostazione del parametro di fulfillment e chiamate API.
  • Ci sono riferimento in risposte, prompt di parametri, gestori di richieste di nuovo, preimpostazioni di parametri e codice webhook:
    • Il formato di riferimento è $session.params.parameter-id per i parametri di sessione e $intent.params.parameter-id per i parametri per intent.
    • I riferimenti ai parametri di intent supportano la sintassi dei suffissi .original e .resolved. I parametri di sessione non supportano questa sintassi.

Entità di sistema

ES supporta molte entità di sistema.

CX supporta molte delle stesse entità di sistema, ma con alcune differenze. Quando esegui la migrazione, verifica che le entità di sistema che utilizzi in ES siano supportate anche da CX per la stessa lingua. In caso contrario, devi creare entità personalizzate.

Eventi

Gli eventi ES hanno le seguenti caratteristiche:

  • Può essere richiamato da chiamate API o webhook per corrispondere a un intent.
  • Consente di impostare parametri.
  • Un numero ridotto di eventi viene richiamato dalle piattaforme di integrazione.

Gli eventi CX hanno le seguenti caratteristiche:

  • Può essere richiamato da chiamate API o webhook per chiamare un gestore di eventi.
  • Impossibile impostare parametri.
  • Molti eventi integrati possono essere utilizzati per gestire la mancanza di input utente dell'utente finale, l'input utente finale non riconosciuto, i parametri invalidati da un webhook ed errori relativi ai webhook.
  • Le chiamate possono essere controllate dalle stesse regole di ambito degli altri gestori di stato.

Intent integrati

ES supporta i seguenti intent integrati:

Di seguito viene descritto il supporto dell'esperienza cliente per gli intent integrati:

  • Sono supportati gli intent di benvenuto.
  • Non vengono forniti intent di riserva. Utilizza invece gli eventi no-match nei gestori di eventi.
  • Per gli esempi negativi, utilizza l'intent negativo predefinito.
  • Gli intent di follow-up predefiniti non sono forniti. Devi creare questi intent come richiesto dall'agente. Ad esempio, probabilmente dovrai creare un intent per gestire le risposte negative a una domanda dell'agente ("no", "no grazie", "no, non lo so" e così via). Gli intent CX sono riutilizzabili nell'agente, quindi devi definirli una sola volta. L'utilizzo di route intent diverse per questi intent comuni, in ambiti diversi, ti offre un controllo molto migliore sulla conversazione.

Webhook

I hook ES hanno le seguenti caratteristiche:

  • Puoi configurare un solo servizio webhook per l'agente.
  • Ogni intent può essere contrassegnato come utilizzando il webhook.
  • Non esiste un supporto integrato per la gestione degli errori dei webhook.
  • Le azioni o i nomi degli intent vengono utilizzati dai webhook per determinare da dove sono stati chiamati nell'agente.
  • La console fornisce l'editor incorporato.

I hook CX hanno le seguenti caratteristiche:

  • Puoi configurare più servizi webhook per l'agente.
  • Ogni fulfillment può specificare facoltativamente una chiamata webhook.
  • È integrato il supporto per la gestione degli errori dei webhook.
  • Un webhook di fulfillment CX contiene un tag. Questo tag è simile a un'azione ES, ma viene utilizzato solo quando si chiamano webhook. Il servizio webhook può usare questi tag per determinare da dove è stato chiamato nell'agente.
  • La console non ha un editor di codice webhook integrato. È comune utilizzare Cloud Functions, ma ci sono molte opzioni.

Quando esegui la migrazione a CX, devi modificare il codice webhook, poiché le proprietà della richiesta e della risposta sono diverse.

Integrazioni

Le integrazioni ES e le integrazioni CX supportano piattaforme diverse. Per le piattaforme supportate da entrambi i tipi di agenti, potrebbero esserci differenze nella configurazione.

Se l'integrazione ES che stavi utilizzando non è supportata da CX, potresti dover cambiare piattaforma o implementare l'integrazione autonomamente.

Altre funzionalità solo per l'esperienza cliente

Ci sono molte altre funzionalità fornite solo da CX. Ti consigliamo di utilizzare queste funzionalità durante la migrazione. Ad esempio:

best practice

Prima di eseguire la migrazione, acquisisci familiarità con le best practice di progettazione dell'agente CX. Molte di queste best practice per l'esperienza cliente sono simili alle best practice per ES, ma alcune sono specifiche per l'esperienza cliente.

Informazioni sullo strumento di migrazione

Lo strumento di migrazione copia la maggior parte dei dati ES nell'agente CX e scrive in un file TODO con un elenco di elementi di cui è necessario eseguire la migrazione manuale. Lo strumento copia solo tipi di entità personalizzate e frasi di addestramento degli intent. Ti consigliamo di personalizzare questo strumento in base alle tue esigenze specifiche.

Codice dello strumento di migrazione

Di seguito è riportato il codice dello strumento. Esamina il codice di questo strumento in modo da comprenderne la funzione. Ti consigliamo di modificare questo codice per gestire situazioni specifiche dell'agente. Eseguirai questo strumento nei passaggi riportati di seguito.

// 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()
}

Migrazione degli strumenti dei tipi di entità

I tipi di entità ES e i tipi di entità CX sono molto simili e sono quindi i tipi di dati più semplici di cui eseguire la migrazione. Lo strumento copia semplicemente i tipi di entità così come sono.

Migrazione dello strumento degli intent

Gli intent ES e gli intent CX sono molto diversi.

Gli intent ES sono utilizzati come componenti di base dell'agente e contengono frasi di addestramento, risposte, contesto per il controllo della conversazione, configurazioni dei webhook, eventi, azioni e parametri di riempimento degli slot.

Dialogflow CX ha spostato la maggior parte di questi dati in altre risorse. Gli intent CX hanno solo frasi e parametri di addestramento, rendendoli riutilizzabili in tutto l'agente. Lo strumento copia solo questi due tipi di dati sugli intent negli intent CX.

Limitazioni dello strumento di migrazione

Lo strumento di migrazione non supporta quanto segue:

  • Mega agenti: lo strumento non può leggere da più sub-agenti, ma puoi richiamare lo strumento più volte per ogni sub-agente.
  • Agenti multilingue: è necessario modificare lo strumento per creare frasi di addestramento multilingue e voci di entità.
  • Verifica delle entità di sistema per le lingue diverse dall'inglese: lo strumento crea elementi TODO quando trova entità di sistema non supportate da CX, partendo dal presupposto che l'inglese è la lingua predefinita e utilizza una regione degli Stati Uniti. Il supporto delle entità di sistema varia in base alla lingua e alla regione. Per le altre lingue e aree geografiche, devi modificare lo strumento per eseguire questo controllo.

Passaggi di migrazione essenziali

Le seguenti sottosezioni descrivono i passaggi da eseguire per la migrazione. Non è necessario seguire questi passaggi manuali in sequenza e potresti anche doverli eseguire contemporaneamente o in un ordine diverso. Leggi la procedura e inizia a pianificare le modifiche prima di apportare le modifiche.

Dopo aver eseguito lo strumento di migrazione, puoi ricreare l'agente CX. Avrai ancora una discreta quantità di lavoro di migrazione da eseguire, ma la maggior parte dei dati inseriti manualmente sarà presente nell'agente CX e nel file TODO.

Crea l'agente Dialogflow CX

Se non lo hai già fatto, crea il tuo agente Dialogflow CX. Assicurati di utilizzare la stessa lingua predefinita dell'agente ES.

Esegui lo strumento di migrazione

Per eseguire lo strumento, procedi nel seguente modo:

  1. Se non lo hai già fatto, installa Go sulla tua macchina.
  2. Crea una directory per il codice dello strumento denominata migrate.
  3. Copia il codice dello strumento riportato sopra in un file in questa directory denominata main.go.
  4. Modifica il codice, se necessario per la tua richiesta.
  5. Crea un modulo Go in questa directory. Ad esempio:

    go mod init migrate
    
  6. Installa le librerie client di Dialogflow ES V2 e Dialogflow CX V3 Go:

    go get cloud.google.com/go/dialogflow/apiv2
    go get cloud.google.com/go/dialogflow/cx/apiv3
    
  7. Assicurati di aver configurato l'autenticazione libreria client.

  8. Esegui lo strumento e salva l'output in un file:

    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
    

Risoluzione dei problemi dello strumento di migrazione

Se si verificano errori durante l'esecuzione dello strumento, verifica quanto segue:

Errore Risoluzione
Errore RPC per cui una parte della frase di addestramento menziona un parametro non definito per l'intent. Questo può accadere se in precedenza hai utilizzato l'API di ES per creare parametri di intent in un modo non coerente con le frasi di addestramento. Per risolvere il problema, rinomina il parametro ES dalla console, verifica che le frasi di addestramento utilizzino correttamente il parametro, quindi fai clic su Salva. Ciò può accadere anche se le tue frasi di addestramento fanno riferimento a parametri inesistenti.

Dopo aver corretto gli errori, dovrai cancellare gli intent e le entità dell'agente CX prima di eseguire nuovamente lo strumento di migrazione.

Spostamento dei dati sull'intent ES a CX

Lo strumento esegue la migrazione delle frasi e dei parametri di addestramento degli intent agli intent CX, ma è necessario eseguire la migrazione manuale di molti altri campi di intent ES.

Un intent ES potrebbe richiedere una pagina CX corrispondente, un intent CX corrispondente o entrambi.

Se viene utilizzata una corrispondenza di intent ES per trasferire la conversazione da un determinato nodo di conversazione a un altro, dovresti avere due pagine nell'agente relative a questo intent:

  • La pagina originale che contiene la route intent, che passerà alla pagina successiva: la route intent nella pagina originale potrebbe contenere messaggi di fulfillment CX simili alle risposte intent di ES. In questa pagina potrebbero essere presenti molte route intent. Anche se la pagina originale è attiva, questi intent route possono trasferire la conversazione a molti percorsi possibili. Molti intent ES condivideranno la stessa pagina originale CX corrispondente.
  • La pagina successiva, che è il target di transizione per la route dell'intent nella pagina originale: il fulfillment della voce CX per la pagina successiva potrebbe contenere messaggi di fulfillment CX simili alle risposte di intent di ES.

Se un intent ES contiene parametri obbligatori, devi creare una pagina CX corrispondente con gli stessi parametri in un modulo.

È comune che un intent CX e una pagina CX condividano lo stesso elenco di parametri, il che significa che un singolo intent ES ha una pagina CX e un intent CX corrispondenti. Quando si verifica una corrispondenza con un intent CX con parametri in una route di intent, la conversazione spesso passa a una pagina con gli stessi parametri. I parametri estratti dalla corrispondenza di intent vengono propagati ai parametri di sessione, che sono disponibili per i parametri del modulo della pagina parzialmente o completamente compilati.

Gli intent di riserva e gli intent di follow-up predefiniti non esistono nell'esperienza cliente. Vedi gli intent integrati.

La seguente tabella descrive come mappare dati specifici sull'intent da risorse ES a risorse CX:

Dati ES Intent Dati sull'esperienza cliente corrispondenti Azione richiesta
Frasi di addestramento Frasi di addestramento dell'intent Migrazione eseguita dallo strumento. Lo strumento verifica il supporto delle entità di sistema e crea elementi TODO per entità di sistema non supportate.
Risposte degli agenti Messaggi di risposta all'evasione dell'ordine Vedi Risposte degli agenti.
Contesto per il controllo della conversazione Nessuna esperienza Vedi Controllo di struttura e percorso di conversazione.
Impostazione webhook Configurazione webhook di evasione degli ordini Consulta i webhook.
Eventi Gestori di eventi a livello di flusso o di pagina Vedi gli eventi.
Azioni Tag webhook di evasione degli ordini Consulta i webhook.
Parametri Parametri intent e/o parametri modulo pagina Migrazione ai parametri intent per strumento. Se i parametri sono obbligatori, lo strumento crea elementi TODO di cui eventualmente eseguire la migrazione a una pagina. Consulta la sezione Parametri.
Prompt dei parametri Prompt dei parametri del modulo della pagina Consulta la sezione sulla compilazione di moduli.

Creazione di flussi

Crea un flusso per ogni argomento di conversazione generale. Gli argomenti di ogni flusso devono essere distinti, in modo che la conversazione non passi spesso da un flusso all'altro.

Se utilizzi un mega-agente, ogni sub-agente dovrebbe diventare uno o più flussi.

Inizia con i percorsi di conversazione di base

È meglio testare l'agente con il simulatore durante l'iterazione delle modifiche. All'inizio della conversazione dovresti quindi concentrarti sui percorsi di conversazione di base e verificare man mano che apporti le modifiche. Una volta che questi elementi funzionano, passa a percorsi di conversazione più dettagliati.

Gestori di stato a livello di flusso e a livello di pagina

Quando crei gestori di stato, valuta se devono essere applicati a livello di flusso o di pagina. Un gestore a livello di flusso è nell'ambito ogni volta che il flusso (e quindi qualsiasi pagina all'interno del flusso) è attivo. Un gestore a livello di pagina rientra nell'ambito solo quando la pagina specifica è attiva. I gestori a livello di flusso sono simili agli intent ES senza contesto di input. I gestori a livello di pagina sono simili agli intent ES con contesto di input.

Codice webhook

Le proprietà della richiesta e della risposta del webhook sono diverse per l'esperienza cliente. Consulta la sezione sui webhook.

Connettori di conoscenza

CX non supporta ancora i connettori di conoscenza. Dovrai implementarli come intent normali o attendere che Dialogflow CX supporti i connettori di conoscenza.

Impostazioni dell'agente

Controlla le impostazioni dell'agente ES e modifica le impostazioni dell'agente CX in base alle tue esigenze.

Utilizza il file TODO

Lo strumento di migrazione genera un file CSV. Le voci di questo elenco sono incentrate su particolari dati che potrebbero richiedere attenzione. Importa questo file in un foglio di lavoro. Risolvi ogni elemento del foglio di lavoro, utilizzando una colonna per contrassegnare il completamento.

Migrazione dell'utilizzo delle API

Se il sistema utilizza l'API ES per le chiamate di runtime o in fase di progettazione, dovrai aggiornare questo codice per utilizzare l'API CX. Se utilizzi le chiamate di rilevamento intent solo in fase di runtime, questo aggiornamento dovrebbe essere abbastanza semplice.

Integrazioni

Se il tuo agente utilizza le integrazioni, consulta la sezione Integrazioni e apporta le modifiche necessarie.

Le seguenti sottosezioni descrivono i passaggi di migrazione consigliati.

Convalida

Utilizza la convalida dell'agente per verificare che l'agente segua le best practice.

Test

Durante i passaggi di migrazione manuale descritti in precedenza, devi testare l'agente con il simulatore. Una volta che l'agente sembra funzionare, devi confrontare le conversazioni tra gli agenti ES e CX e verificare che il comportamento sia simile o migliorato.

Durante il test di queste conversazioni con il simulatore, è necessario creare casi di test per evitare future regressioni.

Ambienti

Esamina i tuoi ambienti ES e aggiorna gli ambienti CX in base alle esigenze.