Von Dialogflow ES zu CX migrieren

Dialogflow CX-Agents bieten Ihnen leistungsfähigere Unterhaltungssteuerungen und Tools als Dialogflow ES-Agents. Wenn Ihr Dialogflow ES-Agent komplexe Unterhaltungen verarbeitet, sollten Sie eine Migration zu Dialogflow CX in Betracht ziehen.

In dieser Anleitung wird beschrieben, wie Sie einen Agent von Dialogflow ES zu Dialogflow CX migrieren. Diese beiden Agent-Typen weisen viele grundlegende Unterschiede auf, sodass es keine einfache Möglichkeit gibt, diese Migration durchzuführen.

Wenn Sie diesen Leitfaden für eine Migration verwenden, geben Sie bitte positives oder negatives Feedback, indem Sie oben auf die Schaltfläche Feedback geben klicken. Wir nutzen dieses Feedback zur Verbesserung dieses Leitfadens.

Grundsätzlich wird ein automatisierter/manueller Hybridprozess empfohlen. Sie verwenden ein Tool, das einige Daten des Dialogflow ES-Agents liest, diese Daten in Ihren Dialogflow CX-Agent schreibt und eine ToDo-Liste erfasst. Anschließend erstellen Sie den vollständigen CX-Agent mithilfe der Best Practices, der ToDo-Liste und der vom Tool migrierten Daten neu.

Dialogflow CX verstehen

Bevor Sie mit dieser Migration beginnen, sollten Sie sich mit der Funktionsweise von Dialogflow CX vertraut gemacht haben. Beginnen Sie hier:

  1. Grundlagen
  2. Einführungsvideos
  3. Kurzanleitung

Lesen Sie auch zusätzliche Konzeptdokumente mit Funktionen, die Sie in Ihrem neuen Agent wahrscheinlich benötigen. Konzentrieren Sie sich auf Folgendes:

ES/CX-Unterschiede verstehen

In diesem Abschnitt werden die wichtigsten Unterschiede zwischen Dialogflow ES und CX aufgeführt. Wenn Sie später manuelle Migrationsschritte ausführen, sollten Sie diesen Abschnitt zur Orientierung lesen.

Steuerung des Struktur- und Unterhaltungspfads

Es bietet Folgendes für die Steuerung von Struktur- und Unterhaltungspfaden:

  • Intents werden als Bausteine des Agents verwendet. Zu jedem Zeitpunkt in der Unterhaltung wird ein Intent zugeordnet und in gewisser Weise ist jeder Intent ein Knoten für die Unterhaltung.
  • Kontext wird zum Steuern der Unterhaltung verwendet. Mit dem Kontext wird gesteuert, welche Intents jederzeit zugeordnet werden können. Der Kontext läuft nach einer bestimmten Anzahl von Unterhaltungsrunden ab, sodass diese Art der Steuerung bei langen Unterhaltungen ungenau sein kann.

CX bietet eine Hierarchie von Strukturressourcen und genauere Steuerelemente für den Unterhaltungspfad:

  • Seiten sind Diagrammknoten für die Unterhaltung. CX-Unterhaltungen ähneln Statusmaschinen. Zu jedem Zeitpunkt der Konversation ist jeweils eine Seite aktiv. Auf der Grundlage von Endnutzereingaben oder Ereignissen kann die Unterhaltung zu einer anderen Seite übergehen. Es ist üblich, dass eine Seite mehrere Unterhaltungsrunden lang aktiv bleibt.
  • Abläufe sind Gruppen verwandter Seiten. Jeder Ablauf sollte ein übergeordnetes Gesprächsthema behandeln.
  • Zustands-Handler werden verwendet, um Übergänge und Antworten zu steuern. Es gibt drei Arten von Status-Handlern:
    • Intent-Route: enthält einen zugeordneten Intent, optionale Antworten und einen optionalen Seitenwechsel.
    • Bedingungsroute: Enthält eine Bedingung, die erfüllt sein muss, optionale Antworten und einen optionalen Seitenwechsel.
    • Event-Handler: Enthält einen Ereignisnamen, der aufgerufen werden muss, optionale Antworten und einen optionalen Seitenwechsel.
  • Mit Geltungsbereich wird gesteuert, ob ein Status-Handler aufgerufen werden kann. Die meisten Handler sind einer Seite oder dem gesamten Ablauf zugeordnet. Wenn die verknüpfte Seite oder der verknüpfte Ablauf aktiv ist, befindet sich der Handler im Geltungsbereich und kann aufgerufen werden. Eine CX-Intent-Route im Bereich ähnelt einem ES-Intent mit einem aktiven Eingabekontext.

Beachten Sie beim Entwerfen der Abläufe und Seiten des Agents die Hinweise im Abschnitt zum Ablauf im Leitfaden zum Erstellen von Agents.

Formular ausfüllen

ES verwendet die Slot-Füllung, um die erforderlichen Parameter vom Endnutzer zu erfassen:

  • Diese Parameter sind Intent-Parameter, die als erforderlich gekennzeichnet sind.
  • Der Intent wird weiter abgeglichen, bis alle erforderlichen Parameter erfasst sind.
  • Sie können eine Aufforderung definieren, die den Endnutzer auffordert, einen Wert anzugeben.

CX verwendet das Ausfüllen von Formularen, um erforderliche Parameter vom Endnutzer zu erfassen:

  • Diese Parameter sind mit einer Seite verknüpft und werden erfasst, während die Seite aktiv ist.
  • Mit Bedingungsrouten für Seiten stellen Sie fest, ob das Formular vollständig ausgefüllt ist. Diese Bedingungsrouten wechseln in der Regel zu einer anderen Seite.
  • Sie können eine Aufforderung sowie Handler für erneute Aufforderungen definieren, um mehrere Versuche zum Erfassen eines Werts ordnungsgemäß zu verarbeiten.

Übergänge

ES wechselt automatisch von einem Intent zum nächsten, wenn die Endnutzereingabe einem Intent zugeordnet wird. Dieser Abgleich kann nur für Intents ohne Eingabekontext oder Intents mit aktivem Eingabekontext erfolgen.

CX wechselt von einer Seite zur nächsten, wenn ein Status-Handler im Bereich die Anforderungen erfüllt und ein Übergangsziel bereitstellt. Mit diesen Umstellungen können Sie Endnutzer zuverlässig durch Unterhaltungen führen. Es gibt mehrere Möglichkeiten, diese Übergänge zu steuern:

  • Intent-Abgleich kann eine Intent-Route auslösen.
  • Das Erfüllen einer Bedingung kann eine Bedingungsroute auslösen.
  • Durch das Aufrufen eines Ereignisses kann ein Ereignis-Handler ausgelöst werden.
  • Handler für Aufforderungen können einen Übergang verursachen, wenn der Endnutzer nach mehreren Versuchen keinen Wert angibt.
  • Sie können symbolische Übergangsziele für Übergangsziele verwenden.

Agent-Antworten

Antworten des ES-Agents werden an den Endnutzer gesendet, wenn ein Intent zugeordnet wird:

  • Der Agent kann eine Nachricht für die Antwort aus einer Liste möglicher Antworten auswählen.
  • Antworten können plattformspezifisch sein, sodass Rich-Media-Antworten verwendet werden können.
  • Antworten können von Webhooks gesteuert werden.

Die Antworten des CX-Agents werden an den Endnutzer gesendet, wenn die Auftragsausführung aufgerufen wird. Im Gegensatz zur ES-Auftragsausführung, die immer einen Webhook umfasst, kann bei der CX-Auftragsausführung ein Webhook aufgerufen werden oder nicht, je nachdem, ob für die Auftragsausführungsressource ein Webhook konfiguriert ist. Sowohl statische als auch dynamische Antworten, die auf Webhook-Antworten basieren, werden durch die Auftragsausführung gesteuert. Es gibt mehrere Möglichkeiten, Agent-Antworten zu erstellen:

  • Die Auftragsausführung kann für jede Art von Status-Handler bereitgestellt werden.
  • Mehrere Antworten können während einer Unterhaltung über die Antwortwarteschlange verkettet werden. Diese Funktion kann in einigen Fällen das Design Ihres Agents vereinfachen.
  • CX unterstützt keine integrierten plattformspezifischen Antworten. Sie bietet jedoch mehrere Antworttypen, einschließlich einer benutzerdefinierten Nutzlast, die für plattformspezifische Antworten verwendet werden kann.

Parameter

ES-Parameter haben folgende Eigenschaften:

  • Wird nur in Intents definiert.
  • Wird durch Endnutzereingabe, Ereignisse, Webhooks und API-Aufrufe festgelegt.
  • Wird in Antworten, Parameteraufforderungen, Webhook-Code und Parameterwerten referenziert:
    • Das grundlegende Referenzformat ist $parameter-name.
    • Referenzen unterstützen die Suffixsyntax .original, .partial und .recent.
    • Verweise können den aktiven Kontext angeben: #context-name.parameter-name.
    • Referenzen können Ereignisparameter angeben: #event-name.parameter-name.

CX-Parameter haben folgende Eigenschaften:

  • Wird in Intents und Seitenformularen definiert.
  • Intent- und Formularparameter werden an Sitzungsparameter weitergegeben, wo sie für die Dauer der Sitzung als Referenz verfügbar sind.
  • Wird durch Endnutzereingabe, Webhooks, Voreinstellung für Auftragsausführungsparameter und API-Aufrufe festgelegt.
  • Wird in Antworten, Parameteraufforderungen, Handlern für Aufforderungen, Parametervoreinstellungen und Webhook-Code referenziert:
    • Das Referenzformat ist $session.params.parameter-id für Sitzungsparameter und $intent.params.parameter-id für Intent-Parameter.
    • Intent-Parameterverweise unterstützen die Suffixsyntax .original und .resolved. Sitzungsparameter unterstützen diese Syntax nicht.

Systementitäten

ES unterstützt viele Systementitäten.

CX unterstützt viele der gleichen Systementitäten. Es gibt jedoch einige Unterschiede. Prüfen Sie bei der Migration, ob die Systementitäten, die Sie in ES verwenden, auch von CX für dieselbe Sprache unterstützt werden. Ist dies nicht der Fall, sollten Sie benutzerdefinierte Entitäten dafür erstellen.

Ereignisse

ES-Ereignisse haben folgende Merkmale:

  • Kann über API-Aufrufe oder Webhooks aufgerufen werden, um einen Intent zuzuordnen.
  • Kann Parameter festlegen.
  • Eine geringe Anzahl von Ereignissen wird von Integrationsplattformen aufgerufen.

CX-Ereignisse haben folgende Eigenschaften:

  • Kann über API-Aufrufe oder Webhooks aufgerufen werden, um einen Event-Handler aufzurufen.
  • Parameter können nicht festgelegt werden.
  • Viele integrierte Ereignisse können verwendet werden, um fehlende Endnutzereingaben, nicht erkannte Endnutzereingaben, durch einen Webhook ungültig gemachte Parameter und Webhook-Fehler zu beheben.
  • Aufrufe können mit denselben Umfangsregeln gesteuert werden wie andere Status-Handler.

Integrierte Intents

ES unterstützt die folgenden integrierten Intents:

Im Folgenden wird die CX-Unterstützung für integrierte Intents beschrieben:

  • Begrüßungs-Intents werden unterstützt.
  • Es sind keine Fallback-Intents vorhanden. Verwenden Sie stattdessen no-match-Ereignisse in Event-Handlern.
  • Verwenden Sie für negative Beispiele den standardmäßigen negativen Intent.
  • Es sind keine vordefinierten Follow-up-Intents vorhanden. Sie müssen diese Intents gemäß den Anforderungen Ihres Agents erstellen. Beispielsweise müssen Sie wahrscheinlich einen Intent erstellen, um negative Antworten auf eine Agent-Frage zu verarbeiten ("nein", "nein, danke", "nein, ich nicht" usw.). CX-Intents sind für den gesamten Agent wiederverwendbar. Sie müssen sie also nur einmal definieren. Wenn Sie für diese gemeinsamen Intents in verschiedenen Bereichen unterschiedliche Intent-Routen verwenden, können Sie die Unterhaltung viel besser steuern.

Webhooks

ES-Webhooks haben folgende Eigenschaften:

  • Sie können einen einzelnen Webhook-Dienst für den Agent konfigurieren.
  • Jeder Intent kann als Webhook gekennzeichnet werden.
  • Es gibt keine integrierte Unterstützung für die Behandlung von Webhook-Fehlern.
  • Intent-Aktionen oder Intent-Namen werden von Webhooks verwendet, um zu bestimmen, von wo im Agent sie aufgerufen wurden.
  • Sie enthält den Inline-Editor.

CX-Webhooks haben folgende Eigenschaften:

  • Sie können mehrere Webhook-Dienste für den Agent konfigurieren.
  • Für jede Auftragsausführung kann optional ein Webhook-Aufruf angegeben werden.
  • Die Webhook-Fehlerbehandlung wird standardmäßig unterstützt.
  • Ein CX-Auftragsausführungs-Webhook enthält ein Tag. Dieses Tag ähnelt einer ES-Aktion, wird jedoch nur beim Aufrufen von Webhooks verwendet. Der Webhook-Dienst kann anhand dieser Tags ermitteln, von wo im Agent er aufgerufen wurde.
  • Die Konsole hat keinen integrierten Webhook-Codeeditor. Die Verwendung von Cloud Functions ist üblich, es gibt jedoch viele Optionen.

Bei der Migration zu CX müssen Sie den Webhook-Code ändern, da sich die Anfrage- und Antwortattribute unterscheiden.

Integrationen

ES-Integrationen und CX-Integrationen unterstützen verschiedene Plattformen. Bei Plattformen, die von beiden Agent-Typen unterstützt werden, kann es Unterschiede bei der Konfiguration geben.

Wenn die von Ihnen verwendete ES-Integration nicht von CX unterstützt wird, müssen Sie möglicherweise die Plattform wechseln oder die Integration selbst implementieren.

Weitere CX-spezifische Funktionen

Viele weitere Funktionen werden nur von CX bereitgestellt. Wir empfehlen, diese Funktionen während der Migration zu verwenden. Beispiel:

Best Practices

Machen Sie sich vor der Migration mit den Best Practices für das Design des CX-Agents vertraut. Viele dieser Best Practices für CX ähneln den Best Practices für ES, einige gelten jedoch nur für CX.

Informationen zum Migrationstool

Das Migrationstool kopiert den Großteil der ES-Daten in den CX-Agent und schreibt es in eine TODO-Datei mit einer Liste der Elemente, die manuell migriert werden müssen. Das Tool kopiert nur benutzerdefinierte Entitätstypen und Intent-Trainingsformulierungen. Sie sollten dieses Tool an Ihre spezifischen Anforderungen anpassen.

Code des Migrationstools

Hier ist der Code für das Tool. Sehen Sie sich den Code für dieses Tool an, damit Sie seine Funktionsweise verstehen. Sie können diesen Code ändern, um bestimmte Situationen in Ihrem Agent zu verarbeiten. In den folgenden Schritten führen Sie dieses Tool aus.

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

Tool-Migration von Entitätstypen

ES-Entitätstypen und CX-Entitätstypen sind sehr ähnlich und daher der am einfachsten zu migrierende Datentyp. Das Tool kopiert Entitätstypen einfach unverändert.

Toolmigration von Intents

ES-Intents und CX-Intents unterscheiden sich stark.

ES-Intents werden als Bausteine des Agents verwendet. Sie enthalten Trainingsformulierungen, Antworten, Kontext für die Unterhaltungssteuerung, Webhook-Konfigurationen, Ereignisse, Aktionen und Slot-Füllparameter.

Dialogflow CX hat den Großteil dieser Daten in andere Ressourcen verschoben. CX-Intents haben nur Trainingsformulierungen und Parameter. Dadurch sind Intents für den gesamten Agent wiederverwendbar. Das Tool kopiert nur diese beiden Arten von Intent-Daten in Ihre CX-Intents.

Einschränkungen für das Migrationstool

Folgendes wird vom Migrationstool nicht unterstützt:

  • Mega-Agents: Das Tool kann nicht aus mehreren Sub-Agents lesen. Sie können es jedoch mehrmals für jeden Sub-Agent aufrufen.
  • Mehrsprachige Agents: Ändern Sie das Tool so, dass mehrsprachige Trainingsformulierungen und Entitätseinträge erstellt werden.
  • Überprüfung der Systementität für nicht englische Sprachen: Das Tool erstellt TODO-Elemente, wenn es Systementitäten findet, die nicht von CX unterstützt werden, in der Annahme, dass Englisch die Standardsprache ist und eine Region in den USA verwendet wird. Die Unterstützung von Systementitäten variiert je nach Sprache und Region. Für andere Sprachen und Regionen müssen Sie das Tool entsprechend anpassen.

Wichtige Migrationsschritte

In den folgenden Unterabschnitten werden die erforderlichen Migrationsschritte beschrieben. Sie müssen diese manuellen Schritte nicht in der richtigen Reihenfolge ausführen. Möglicherweise müssen Sie diese Schritte sogar gleichzeitig oder in einer anderen Reihenfolge ausführen. Lesen Sie die Schritte und beginnen Sie mit der Planung von Änderungen, bevor Sie Änderungen vornehmen.

Nachdem Sie das Migrationstool ausgeführt haben, können Sie den CX-Agent neu erstellen. Es wird zwar noch ein gewisses Maß an Migrationsarbeit geben, aber der Großteil der manuell eingegebenen Daten ist in Ihrem CX-Agent und in der TODO-Datei vorhanden.

Dialogflow CX-Agent erstellen

Falls noch nicht geschehen, erstellen Sie den Dialogflow CX-Agent. Verwenden Sie dieselbe Standardsprache wie für den ES-Agent.

Migrationstool ausführen

Führen Sie die folgenden Schritte aus, um das Tool auszuführen:

  1. Falls noch nicht geschehen, installieren Sie Go auf Ihrem Computer.
  2. Erstellen Sie ein Verzeichnis für den Toolcode mit dem Namen migrate.
  3. Kopieren Sie den obigen Toolcode in eine Datei mit dem Namen main.go in diesem Verzeichnis.
  4. Ändere den Code bei Bedarf ab.
  5. Erstellen Sie in diesem Verzeichnis ein Go-Modul. Beispiel:

    go mod init migrate
    
  6. Installieren Sie die Dialogflow ES V2- und Dialogflow CX V3 Go-Clientbibliotheken:

    go get cloud.google.com/go/dialogflow/apiv2
    go get cloud.google.com/go/dialogflow/cx/apiv3
    
  7. Prüfen Sie, ob Sie die Authentifizierung der Clientbibliothek eingerichtet haben.

  8. Führen Sie das Tool aus und speichern Sie die Ausgabe in der Datei:

    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
    

Fehlerbehebung für das Migrationstool

Wenn beim Ausführen des Tools Fehler auftreten, prüfen Sie Folgendes:

Fehler Lösung
RPC-Fehler, der besagt, dass in einem Teil der Trainingsformulierung ein Parameter erwähnt wird, der für den Intent nicht definiert ist. Dies kann passieren, wenn Sie die ES API zuvor zum Erstellen von Intent-Parametern auf eine Weise verwendet haben, die nicht mit den Trainingsformulierungen übereinstimmt. Um dieses Problem zu beheben, benennen Sie den ES-Parameter über die Console um, prüfen Sie, ob Ihre Trainingsformulierungen den Parameter richtig verwenden, und klicken Sie dann auf „Speichern“. Dies kann auch der Fall sein, wenn Ihre Trainingsformulierungen auf nicht vorhandene Parameter verweisen.

Nachdem Sie die Fehler behoben haben, müssen Sie die Intents und Entitäten aus dem CX-Agent löschen, bevor Sie das Migrationstool noch einmal ausführen.

ES-Intent-Daten in CX verschieben

Das Tool migriert Intent-Trainingsformulierungen und -parameter zu CX-Intents. Es gibt jedoch noch viele andere ES-Intent-Felder, die manuell migriert werden können.

Für einen ES-Intent kann eine entsprechende CX-Seite, ein entsprechender CX-Intent oder beides erforderlich sein.

Wenn eine ES-Intent-Zuordnung verwendet wird, um die Unterhaltung von einem bestimmten Unterhaltungsknoten zu einem anderen zu übertragen, sollten zwei Seiten in Ihrem Agent vorhanden sein, die sich auf diesen Intent beziehen:

  • Die ursprüngliche Seite mit der Intent-Route, die zur nächsten Seite übergeht: Die Intent-Route auf der ursprünglichen Seite kann CX-Auftragsausführungsnachrichten enthalten, die den ES-Intent-Antworten ähneln. Möglicherweise haben Sie auf dieser Seite viele Intent-Routen. Während die ursprüngliche Seite aktiv ist, können diese Intent-Routen die Unterhaltung in viele mögliche Pfade verschieben. Viele ES-Intents nutzen dieselbe CX-Originalseite.
  • Die nächste Seite ist das Übergangsziel für die Intent-Route auf der ursprünglichen Seite: Die Auftragsausführung der CX-Einträge für die nächste Seite kann CX-Auftragsausführungsnachrichten enthalten, die den ES-Intent-Antworten ähneln.

Wenn ein ES-Intent erforderliche Parameter enthält, sollten Sie eine entsprechende CX-Seite mit denselben Parametern in einem Formular erstellen.

Es ist üblich, dass ein CX-Intent und eine CX-Seite dieselbe Parameterliste verwenden. Das bedeutet, dass ein einzelner ES-Intent eine entsprechende CX-Seite und einen entsprechenden CX-Intent hat. Wenn ein CX-Intent mit Parametern in einer Intent-Route zugeordnet wird, wird die Unterhaltung häufig auf eine Seite mit denselben Parametern weitergeleitet. Die aus der Intent-Übereinstimmung extrahierten Parameter werden an Sitzungsparameter weitergegeben. Diese können Seitenformularparameter teilweise oder vollständig ausfüllen.

Fallback-Intents und vordefinierte Follow-up-Intents sind in CX nicht vorhanden. Siehe integrierte Intents.

In der folgenden Tabelle wird beschrieben, wie bestimmte Intent-Daten aus ES- und CX-Ressourcen zugeordnet werden:

ES – Intent-Daten Entsprechende CX-Daten Maßnahme erforderlich
Trainingssätze Intent-Trainingsformulierungen Per Tool migriert. Das Tool prüft, ob Systementitäten unterstützt werden, und erstellt TODO-Elemente für nicht unterstützte Systementitäten.
Agent-Antworten Antwortnachrichten zur Auftragsausführung Siehe Agent-Antworten.
Kontext für die Unterhaltungssteuerung Keine Weitere Informationen finden Sie unter Steuerung für Struktur- und Unterhaltungspfad.
Webhook-Einstellung Konfiguration des Auftragsausführungs-Webhooks Weitere Informationen zu Webhooks
Ereignisse Event-Handler auf Ablauf- oder Seitenebene Ereignisse ansehen
Aktionen Webhook-Tags für die Auftragsausführung Weitere Informationen zu Webhooks
Parameter Intent-Parameter und/oder Seitenformularparameter Werden per Tool zu Intent-Parametern migriert. Wenn die Parameter erforderlich sind, erstellt das Tool TODO-Elemente, um möglicherweise auf eine Seite zu migrieren. Siehe Parameter.
Parameter-Prompts Aufforderungen für Seitenformularparameter Weitere Informationen zum Ausfüllen von Formularen

Abläufe erstellen

Erstellen Sie einen Ablauf für jedes übergeordnete Gesprächsthema. Die Themen in jedem Ablauf sollten unterschiedlich sein, damit die Unterhaltung nicht häufig zwischen Abläufen hin und her springt.

Wenn Sie einen Mega-Agent verwenden, sollte jeder Sub-Agent zu einem oder mehreren Abläufen werden.

Mit einfachen Unterhaltungspfaden beginnen

Sie sollten den Agent am besten mit dem Simulator testen, während er Änderungen iteriert. Daher sollten Sie sich zu Beginn der Unterhaltung auf die grundlegenden Unterhaltungspfade konzentrieren und Änderungen vornehmen. Sobald diese funktionieren, können Sie mit detaillierteren Gesprächspfaden fortfahren.

Status-Handler auf Ablaufebene und auf Seitenebene

Überlegen Sie beim Erstellen von Status-Handlern, ob sie auf Ablauf- oder Seitenebene angewendet werden sollen. Ein Handler auf Ablaufebene ist immer dann vorhanden, wenn der Ablauf (und damit jede Seite innerhalb des Ablaufs) aktiv ist. Ein Handler auf Seitenebene wird nur angewendet, wenn die jeweilige Seite aktiv ist. Handler auf Ablaufebene ähneln ES-Intents ohne Eingabekontext. Handler auf Seitenebene ähneln ES-Intents mit Eingabekontext.

Webhook-Code

Die Attribute für Webhook-Anfrage und -Antwort unterscheiden sich bei CX. Weitere Informationen finden Sie im Abschnitt „Webhooks“.

Wissensconnectors

CX unterstützt noch keine Wissensconnectors. Sie müssen diese als normale Intents implementieren oder warten, bis Dialogflow CX Wissensconnectors unterstützt.

Agent-Einstellungen

Prüfen Sie die ES-Agent-Einstellungen und passen Sie die CX-Agent-Einstellungen nach Bedarf an.

Verwende die TODO-Datei

Das Migrationstool gibt eine CSV-Datei aus. Die Elemente in dieser Liste konzentrieren sich auf bestimmte Daten, die möglicherweise Aufmerksamkeit erfordern. Importieren Sie diese Datei in eine Tabelle. Jedes Element in der Tabelle bearbeiten, indem Sie eine Spalte zur Markierung der Fertigstellung verwenden.

Migration der API-Nutzung

Wenn Ihr System die ES API für Laufzeit- oder Entwurfszeitaufrufe verwendet, müssen Sie diesen Code für die Verwendung der CX API aktualisieren. Wenn Sie die Intent-Erkennung nur zur Laufzeit verwenden, sollte diese Aktualisierung ziemlich einfach sein.

Integrationen

Wenn der Agent Integrationen verwendet, lesen Sie den Abschnitt zu Integrationen und nehmen Sie bei Bedarf Änderungen vor.

In den folgenden Unterabschnitten werden die empfohlenen Migrationsschritte beschrieben.

Validierung

Prüfen Sie mithilfe der Agent-Validierung, ob der Agent den Best Practices entspricht.

Testen

Während Sie die obigen manuellen Migrationsschritte ausführen, sollten Sie den Agent mit dem Simulator testen. Sobald der Agent zu funktionieren scheint, sollten Sie die Unterhaltungen zwischen den ES- und CX-Agents vergleichen und prüfen, ob das Verhalten ähnlich oder verbessert ist.

Beim Testen dieser Unterhaltungen mit dem Simulator sollten Sie Testfälle erstellen, um zukünftige Regressionen zu verhindern.

Umgebungen

Prüfen Sie Ihre ES-Umgebungen und aktualisieren Sie Ihre CX-Umgebungen nach Bedarf.