Integración de backend y código personalizado
Estas son algunas de las mejores prácticas para escribir código personalizado y realizar la integración de backend para asistentes digitales.
Al final de una conversación, debe hacer algo con la información recopilada de un usuario. Ese "algo" normalmente requiere acceso a un servicio de backend para consultar datos o datos persistentes para los que necesita crear componentes personalizados. Otro uso para los componentes personalizados es incorporar lógica personalizada que maneje validaciones complejas u otras funciones de utilidad. Oracle Digital Assistant soporta dos tipos de componentes personalizados:
- Componentes del flujo de diálogo personalizado (CCS)
- Controladores de eventos de entidades (EEH)
Durante la fase de planificación y diseño del asistente digital, debe identificar los recursos de backend que necesitará y decidir si las API que tiene disponibles para ello son suficientes o no.
- Debido a que los asistentes digitales no son aplicaciones web, puede que sea necesario optimizar o abstraer las API existentes mediante una capa de optimización para devolver solo los datos y la cantidad de datos necesarios en una conversación de asistente digital.
- Si no tiene servicios REST para que la funcionalidad de backend se integre en una conversación de asistente digital, debe diseñar y disparar un proyecto para crearlos.
Al implantar la integración de servicio de backend, puede tomar decisiones sobre si desplegar componentes personalizados de forma remota o utilizar contenedores de componentes embebidos en las aptitudes de Oracle Digital Assistant.
Como se indica en la siguiente figura, la integración de backend es una parte necesaria de la fase de planificación y de implantación.
Componentes del flujo de diálogo personalizado
Con los componentes de flujo de diálogo personalizados, puede escribir sus propios componentes de interfaz de usuario que puede agregar al flujo de diálogo para ejecutar la lógica de código personalizado en el contexto de una conversación. Los casos de uso para escribir esos componentes incluyen:
-
Consulta y escritura de servicios de backend remoto a través de servicios REST.
-
Soluciones listas para usar que gestionan todas las interacciones de usuario para una tarea específica, como solicitar comentarios de usuario al final de una conversación, registrar e informar errores a un administrador, etc.
-
Soporta la gestión de datos en matrices de objetos guardadas en una variable de flujo de diálogo.
Usar nombres correctos para componentes y parámetros de entrada
No hay un campo para proporcionar descripciones de componentes personalizados que expliquen lo que hacen y qué información se debe transferir a ellos. Por lo tanto, las mejores formas de ayudar a los desarrolladores de aptitudes a utilizar el componente son utilizar buenos nombres para el componente y los parámetros de entrada y seleccionar cuidadosamente las cadenas de acción que devuelve el componente.
-
Los componentes incorporados de YAML utilizan
System.<name>
como nombre. Por lo tanto, especialmente para los flujos de diálogo basados en YAML, puede que desee utilizarCustom.<name>
para que los revisores de aptitudes entiendan que es un componente personalizado al que hace referencia el flujo de diálogo. O bien, puede utilizar un espacio de nombres para proporcionar contexto. Para nuestros componentes personalizados de muestra, a menudo usamosoracle.sample.<name>
para indicar que esos componentes no están destinados a ser de calidad de producción. -
Los parámetros de entrada proporcionan datos al componente personalizado para procesar. A menudo, los datos transferidos a un componente personalizado no son el valor real con el que trabajar, sino el nombre de una variable que contiene los valores de datos para procesar o en la que se deben escribir los datos consultados desde un servicio remoto. En cuanto a los componentes incorporados, utilizan
variable
como nombre de propiedad para contener el nombre de la variable en la que se escribirá el resultado del componente o<name>Var
(por ejemplo,nlpResultVar
) para indicar propiedades que hacen referencia a un nombre de referencia de variable. Puede mejorar aún más esto mediante los postfijos_in
y_out
para indicar si una variable hace referencia a una variable que contiene datos o espera datos del componente. -
Las cadenas de acción son opcionales y pueden ser utilizadas por el desarrollador de aptitudes para determinar el siguiente estado del flujo de diálogo al que navegar. El uso de
success
ofailure
como cadena de acción no proporciona mucho contexto, por lo que sugerimos utilizar algo comoorderSubmitted
,orderRejected
ouserUnauthorized
en su lugar.
Evite hacer suposiciones en su código
La realidad es que a menudo el desarrollador de un componente personalizado es también el desarrollador de aptitudes que lo utiliza. Por este motivo, muchos desarrolladores simplifican su trabajo con componentes personalizados realizando suposiciones sobre las variables que están presentes en la aptitud. Por lo tanto, en lugar de transferir el nombre de una variable al componente, hacen referencia directamente al nombre en la lógica del componente personalizado. No recomendamos esto porque estas suposiciones pueden romper fácilmente un componente personalizado. Recomendamos definir un contrato claro y completo entre el componente personalizado y las aptitudes que lo utilizan.
Biblioteca de pensamiento
Una pregunta común es sobre cuántos componentes personalizados se deben agregar a un paquete de servicios de componentes personalizados. En general, siempre es una buena idea pensar en los servicios de componentes personalizados, y los componentes que contiene, como bibliotecas. Por lo tanto, todos los componentes relacionados con una tarea se pueden guardar en un único servicio de componentes personalizados. Sin embargo, las recomendaciones deben ser capaces de hacer frente a la realidad. Por lo tanto, la pregunta sobre cómo empaquetar componentes personalizados debe responderse en función del uso previsto de los componentes personalizados.
-
La reutilización no es una opción para muchos desarrolladores de componentes personalizados. Cuando se desarrollan y utilizan componentes personalizados en una aptitud específica, tiene sentido agrupar todos esos componentes en un único despliegue de servicio de componentes personalizados. La excepción a esto es para los componentes que se reutilizan realmente en otras aptitudes.
-
Los despliegues de contenedor de componentes embebidos están restringidos por el número de servicios de componentes personalizados por instancia de Oracle Digital Assistant. Por lo tanto, querrá utilizar un único servicio de componentes personalizados por aptitud o buscar un despliegue remoto de los componentes personalizados.
-
Utilice el despliegue remoto de servicios de componentes personalizados en Kubernetes en Oracle Cloud Infrastructure por los siguientes motivos:
-
No revelar información confidencial incluida en el código de componente personalizado. Cualquier persona que tenga acceso completo a la instancia de Oracle Digital Assistant puede descargar los servicios de componentes personalizados desplegados en el contenedor embebido.
-
Para implementar una mejor segmentación del código. Los componentes personalizados solo deben contener código necesario para interactuar con el bot y llamar a los servicios REST. El resto del código se debe almacenar en archivos JavaScript externos (si se utiliza un contenedor embebido) o en capas de integración (servicios REST). Los componentes personalizados incluyen código que realiza las siguientes acciones:
-
leer parámetros de entrada
-
leer/definir valores de variable
-
manejar mensajes recibidos por un componente
-
Representar la interfaz de usuario del componente personalizado
-
determinar la transición al siguiente estado
-
Gestionar Estado de Componente
-
acceso a servicios REST
-
-
Mejorar el rendimiento. El contenedor embebido para desplegar componentes personalizados en aptitudes utiliza funciones de OCI, que tienen un retraso de inicio en frío. Para evitar este retraso, así como el límite en el número de servicios que se pueden desplegar, un despliegue remoto de componente personalizado le proporciona una alternativa sin preocupaciones.
-
Compartir componentes comunes. Aunque nuestra experiencia es que la reutilización no está muy clasificada entre los desarrolladores de componentes personalizados, tiene sentido crear y desplegar componentes personalizados de uso común en un servidor remoto. Puede tener componentes comunes para cosas como el manejo de errores y la escalada, el manejo de autorizaciones OAuth2 de 2 partes y más.
-
Cómo escribir mensajes de log
El registrador por defecto implantado para los componentes personalizados es el registrador de consola. Puede acceder al registrador mediante una llamada a context.logger()
. Puede utilizar las funciones de registro de llamadas disponibles para el registrador de consola, como ".info('...')
o ".warn('...')
".
Nota: El uso de context.logger()
tiene más sentido al desplegar en el contenedor embebido, ya que el contenedor embebido sabe cómo mostrar correctamente estos logs. Para los componentes personalizados que despliegue externamente, es mejor utilizar una biblioteca de registro diferente, como log4js.
Gestionar el estado interno del componente
Los componentes del flujo de diálogo personalizado pueden tener una interacción más larga con un usuario antes de que la navegación pase al siguiente estado del flujo de diálogo. Para esta interacción, debe asegurarse de que el componente maneje su estado interno para que pueda distinguir entre una llamada inicial y las llamadas posteriores. Hay dos opciones para hacerlo:
-
Agregue un token a la carga útil del mensaje de devolución. Cuando el componente personalizado representa una interfaz de usuario en la que los usuarios pueden pulsar un elemento de acción, se devuelve un mensaje de devolución al componente personalizado. El componente personalizado debe evaluar los mensajes de devolución que recibe para determinar si esa devolución proviene de la interfaz de usuario que está representando o de otro componente. Para ello, puede comprobar el mensaje de devolución en cuanto a si contiene un token que el componente personalizado agregó al representar el elemento de acción.
-
Utilice una variable de flujo de diálogo. Si necesita gestionar un estado más complejo entre llamadas a componentes personalizados, por ejemplo, para realizar un seguimiento de los valores extraídos de los mensajes de usuario, puede utilizar una variable de flujo de diálogo para ello. Los componentes personalizados pueden crear variables de flujo de diálogo en tiempo de ejecución en una llamada a
context.variable('variable name', value)
. Si no existe una variable del nombre especificado, se creará. El objeto "valor" puede ser cualquier cosa que necesite realizar un seguimiento.
Validar Parámetros de Entrada
Los parámetros de entrada que defina para un componente personalizado deben validarse para tener contenido. Esto también se aplica a los parámetros definidos como obligatorios. Deben comprobarse los siguientes casos:
-
El parámetro de entrada tiene un juego de valores.
-
El valor no empieza por
'$ {'
, ya que indica una expresión para leer el valor del parámetro de entrada de una variable o que un objeto no se ha resuelto correctamente en el flujo de diálogo.
Uso de la Clase MessageFactory para Mensajes de Componente
Todas las respuestas del bot que envíe desde un componente personalizado deben utilizar la clase MessageFactory
. La clase MessageFactory
se puede utilizar para crear el mismo tipo de mensajes de usuario enriquecidos que el componente de respuesta común, que incluye una lista de valores, anexos, diseños de tarjetas y mensajes de texto.
Además, los mensajes que se definen con la clase MessageFactory
son independientes del canal. Esto significa que crea un mensaje de componente único, que luego los conectores específicos del canal convierten en el formato requerido por el canal de cliente respectivo.
Para acceder a la clase MessageFactory
desde un componente personalizado, utilice la siguiente referencia:
let MessageFactory = context.MessageFactory();
La clase
MessageFactory
sustituye a la clase MessageModel
, que está en desuso. Ambas clases tienen el mismo propósito general, pero MessageFactory
tiene las siguientes ventajas:
- Admite todos los tipos y propiedades de mensajes del modelo de mensajes común (CMM), en lugar de solo un subjuego.
- Su implementación se basa en clases, proporcionando métodos getter, setter y add limpios para cambiar la definición del mensaje. La finalización del código se produce cuando se utiliza Typescript, así como en JavaScript, cuando se incluyen las definiciones de tipo adecuadas en la parte superior del manejador de eventos o componente personalizado.
- La implantación utiliza el patrón del creador, que le permite encadenar un número de setter o agregar métodos, lo que hace que el código sea más legible y reduce el número de líneas que tiene que codificar
Lista de comprobación para componentes personalizados
- ☑ Asegúrese de que los servicios de backend están optimizados o abstraídos para su uso con aptitudes.
- ☑ Los componentes personalizados solo deben contener código relacionado con el bot. El resto del código se debe mover a bibliotecas o clases de utilidades, o se debe desplegar como servicios REST individuales en un servidor remoto o un servicio en la nube.
- ☑ Cree un contrato claro y completo entre los componentes personalizados y las aptitudes en las que se utilizan.
- ☑ Utilice componentes personalizados para evaluaciones complejas. Evite Apache FreeMarker en esos casos.
- ☑ Gestione el estado de los componentes para interacciones de usuarios de varias solicitudes.
- ☑ Valide todos los parámetros de entrada de componentes personalizados.
- ☑ Gestione los errores devolviendo una cadena de acción para que el desarrollador de aptitudes gestione los problemas.
Más Información
- Tutorial: Desarrollo de componentes personalizados para la integración de backend
- Tutorial: Depuración de componentes personalizados
- Límites de contenedor incrustados para servicios de componentes personalizados
- Documentación del SDK del nodo de bots: MessageFactory código de ejemplo para varias respuestas de la interfaz de usuario
Manejadores de eventos de entidades
Un manejador de eventos de entidad es un tipo de componente personalizado que permite llamar al código de componente personalizado en el contexto de la resolución de entidades de bolsa compuesta. Los manejadores de eventos de entidades se utilizan en conversaciones controladas por modelos para interactuar con la entrada del usuario y validarla, así como para llamar a servicios de backend remotos para el acceso de lectura y escritura. A diferencia de los componentes de flujo de diálogo personalizados, la posibilidad de reutilización es mínima para un manejador de eventos, por lo que la implantación por defecto del manejador de eventos de entidad es en el contenedor de aptitudes embebido.
Agregar funcionalidad faltante para resolver componentes de entidades
Gran parte de la funcionalidad que se puede definir para el componente de respuesta común, como los botones globales de ayuda y cancelación, no está disponible para el componente Resolver entidades mediante la configuración.
Sin embargo, puede agregar funciones que faltan mediante manejadores de eventos de entidades. Esto le permite aprovechar la simplicidad del componente Resolver entidades en el flujo de diálogo sin sacrificar la funcionalidad avanzada.
Gestionar estado
Los componentes Resolve Entities y Common Response invocan las funciones del manejador de eventos de entidad al resolver una entidad de bolsa compuesta. No es necesario que realice un seguimiento de qué elemento de bolsa debe resolverse a continuación, ya que todo se realiza por usted.
Sin embargo, es posible que desee guardar información para su uso posterior. Para ello, tiene dos opciones:
-
Las propiedades de resolución de contexto son variables que crea en el objeto de contexto. Las variables y sus valores existen hasta que se resuelva la entidad de bolsa compuesta o hasta que deje el estado del flujo de diálogo que resuelve una entidad de bolsa compuesta. La ventaja de utilizar las propiedades de resolución de contexto es que no es necesario realizar tareas de limpieza.
- Para escribir, utilice:
context.setCustomProperty(name, value);
- Para lectura, utilice:
context.getCustomProperty(name);
- Para escribir, utilice:
-
Las variables de flujo de diálogo creadas en tiempo de ejecución o en tiempo de diseño se pueden utilizar para almacenar los valores que desea mantener más allá de la resolución de la entidad de bolsa compuesta. Se puede acceder al contenido almacenado en variables de flujo de diálogo desde estados de flujo de diálogo (solo para variables definidas en tiempo de diseño) y desde otros manejadores de eventos de entidad.
- Para escribir, utilice:
context.variable(name,value);
- Para lectura, utilice:
context.variable(name);
- Para escribir, utilice:
Cómo escribir mensajes de log
El registrador por defecto implantado para los manejadores de eventos de entidad es el registrador de consola.
Puede acceder al registrador mediante una llamada a context.logger()
.
Puede utilizar las funciones de registro de llamadas disponibles para el registrador de consola, como .info('...')
o .warn('...')
.
Visualización de Mensajes de Usuario
Los mensajes de usuario personalizados se muestran mediante la función context.addMessage()
. Al igual que con los componentes de flujo de diálogo personalizados, nuestra recomendación es utilizar la clase MessageFactory
para crear mensajes independientes del canal en lugar de generar cargas útiles específicas del canal. Los gestores de eventos de entidades también admiten mensajes de tipo lista de valores, diseño de tarjetas y anexos.
Lista de control para controladores de eventos de entidades
- ☑ Almacene los valores temporales en el contexto de resolución, a menos que sea necesario en un estado de flujo de diálogo posterior.
- ☑ Utilice un único servicio de componente personalizado para todos los manejadores de eventos de entidad utilizados en una aptitud.
- ☑ Utilice la clase
MessageFactory
para que los mensajes se muestren a los usuarios.
Más Información
- Video de Oracle Digital Assistant Design Camp: Descripción de los manejadores de eventos de entidades
-
Tutorial: Desarrollo del Manejador de Eventos de Entidad en el Explorador
- Tutorial: Desarrollo del Manejador de Eventos de Entidad en IDE Externo
- Ejemplo: conversaciones basadas en modelos con EEH por ejemplo de un informe de gastos
- Documentación del SDK del nodo de bots: MessageFactory código de ejemplo para varias respuestas de la interfaz de usuario
- Documentación: Funciones del manejador de eventos de entidad (expuestas en el objeto de contexto)
¿Qué componente debería utilizar?
Los manejadores de eventos de entidad se utilizan con entidades de bolsa compuesta, mientras que los componentes de flujo de diálogo personalizados se utilizan en el contexto de conversaciones que cambian entre estados de flujo de diálogo. En última instancia, es probable que esté utilizando ambos. Si sigue la recomendación de utilizar conversaciones controladas por modelos, será más probable que utilice manejadores de eventos de entidades que componentes de flujo de diálogo personalizados.
Desde un punto de vista funcional, los componentes personalizados del flujo de diálogo (CCS) y los manejadores de eventos de entidades (EEH) son muy similares. En la siguiente tabla, se comparan los dos tipos de componentes personalizados.
Funcionalidad | CCS | EEH |
---|---|---|
Node.js soporte del módulo / JavaScript desarrollo | Sí | Sí |
Soporte de TypeScript | Sí | Sí |
Desarrollo basado en explorador | Número | Sí |
Desarrollo en IDE externo | Sí | Sí |
Usar en flujos de diálogo | Sí | Número |
Utilizar en entidades de bolsa compuesta | Número | Sí |
Parámetros de Entrada | Sí | Número |
Navegación programática a transiciones de acción | Sí | Número |
Llamar a servicios REST | Sí | Sí |
Leer de/escribir en variables de flujo de diálogo | Sí | Sí |
Almacenar valores temporalmente en contexto de resolución | Número | Sí |
Usar grupos de recursos/compatibilidad multilingüe | Sí | Sí |
Representar interfaces de usuario enriquecidas y peticiones de datos para interactuar con los usuarios | Sí | Sí |
Soporte de despliegue de contenedor de aptitudes | Sí | Sí |
Soporte de despliegue remoto | Sí | Sí |
Compatibilidad con depuración local (requiere NGROK u otros túneles) | Sí | Sí |
Eventos Personalizados | Número | Sí |
Soporte de acción de devolución | Sí | Sí |
Uso de grupos de recursos para CCS y EEH
Los componentes de flujo de diálogo personalizados y los manejadores de eventos de entidad que muestran mensajes de bot al usuario deben mostrar mensajes en los idiomas soportados por el asistente digital.
Hasta hace poco, no había una forma sencilla de utilizar grupos de recursos definidos en una aptitud a partir de componentes personalizados. Pero ahora hay una nueva interfaz de programación que le permite referir claves de grupos de recursos en su código. Hay dos restricciones conocidas que debe tener en cuenta:
-
El uso de cadenas de grupos de recursos está limitado a grupos de recursos sin parámetros o con parámetros posicionales. La nueva API aún no soporta los parámetros con nombre que se utilizan con los paquetes de mensajes de ICU.
-
La API produce una expresión que, cuando se devuelve como respuesta de bot, se sustituye por la cadena de grupo de mensajes de referencia para el idioma detectado.
Para llamar a la nueva API, utilice una de las siguientes llamadas de objeto de contexto:
let expression = context.translate('resource_bundle_key_name');
let expression = context.translate('resource_bundle_key_name', param1, param2);
La expresión se puede utilizar en respuestas de texto, como etiquetas de botón y en tarjetas mediante la clase MessageFactory
.
-
Ejemplo de manejador de eventos de entidades:
const messageModel = context.getMessageFactory(); //create a conversation message format text object that references a key name const message = messageModel.createTextMessage(context.translate('resource_bundle_key')); //display the message to the user keeping the turn, which means the composite bag entity //proceeds with the next bag item to resolve context.addMessage(message,true);
-
Ejemplo de flujo de diálogo personalizado:
const messageModel = context.getMessageFactory(); //create a conversation message format text object that references a key name const message = messageModel.createTextMessage(context.translate('resource_bundle_key')); //display the message to the user keeping the turn, which means the composite bag entity //proceeds with the next bag item to resolve context.reply(message); context.keepTurn(true); context.transition(); done();
Consulte también el artículo de TechExchange Uso de parámetros de entrada para transferir cadenas de grupos de recursos traducidas a componentes personalizados.
Cómo utilizar parámetros con nombre
A continuación, se muestra cómo acceder a parámetros con nombre en un grupo de recursos:
//Entity event handler sample
let expression = "${rb('key_name','param_name1,param_name2',"+value1+","+value2+")}";
let message = messageFactory.createTextMessage(expression);
context.addMessage(message,true);
//Custom dialog flow component sample
let expression = "${rb('key_name','param_name1,param_name2',"+value1+","+value2+")}";
let message = messageFactory.createTextMessage(expression);
context.reply(message);
Nuestra recomendación sobre paquetes de recursos y componentes personalizados
El uso de grupos de recursos en todas partes es un tema común en esta guía. Sin embargo, el uso de grupos de recursos almacenados en una aptitud crea un estrecho acoplamiento entre el componente de flujo de diálogo personalizado o el manejador de eventos y la aptitud. Si está de acuerdo con esta dependencia y valora la ventaja de tener cadenas de recursos gestionadas en un solo lugar más que evitar el problema del acoplamiento estricto, debe hacerlo. Para los manejadores de eventos, la posibilidad de reutilización es mínima de todos modos, por lo que no debe haber ninguna duda sobre el uso de cadenas de grupo de recursos en los manejadores de eventos de entidades en absoluto.
Para los componentes de flujo de diálogo personalizados que se reutilizan en diferentes aptitudes, la función de traducción también funcionará si las aptitudes tienen los nombres de clave de grupo de recursos requeridos por el componente personalizado agregado a su grupo de recursos.
Con una solución alternativa, puede evitar el acoplamiento estricto de componentes personalizados a una aptitud transfiriendo los mensajes leídos de un grupo de recursos como parámetros de entrada a un componente de flujo de diálogo personalizado.
¿Desea migrar a manejadores de eventos de entidad?
Si pasa de componentes de flujo de diálogo personalizados a manejadores de eventos de entidades, debe ser por un motivo específico, no solo porque se trata de una nueva tecnología. Cambiar likes por likes no mejora tus habilidades. Si no está satisfecho con el flujo de conversación actual y está considerando usar entidades de bolsa compuesta para reemplazar partes de la conversación de flujo de diálogo, esa es una buena razón para mover la lógica de código de los componentes de flujo de diálogo personalizados a los manejadores de eventos de entidades.
Mejores Prácticas al Migrar a Manejadores de Eventos de Entidad
Si decide mover la funcionalidad existente de los componentes del flujo de diálogo personalizado a los manejadores de eventos de entidades para mejorar el flujo de conversación, asegúrese de que no sólo está intentando imitar el comportamiento que ha implantado con el componente de flujo de diálogo personalizado y el componente Respuesta Común. En su lugar, comience a utilizar el componente Resolver entidades y utilice las funciones del manejador de eventos de entidades para implantar toda la validación y lógica necesarias para su caso de uso conversacional.