Integración de backend y código personalizado
Aquí se ofrecen algunas 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 componentes personalizados es incorporar lógica personalizada que maneje validaciones complejas u otras funciones de utilidad. Oracle Digital Assistant admite dos tipos de componentes personalizados:
- Componentes personalizados del flujo de diálogo (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 son suficientes o no.
- Puesto que los asistentes digitales no son aplicaciones web, puede que sea necesario optimizar o abstraer las API existentes a través de 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 dispone de 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 del servicio de backend, puede tomar decisiones sobre si desplegar componentes personalizados de forma remota o utilizar los contenedores de componentes embebidos en las aptitudes de Oracle Digital Assistant.
Como se indica en la figura siguiente, 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. Entre los casos de uso para escribir estos componentes se incluyen:
-
Consulta y escritura de servicios de backend remotos mediante servicios REST.
-
Soluciones listas para usar que manejan todas las interacciones de los usuarios para una tarea específica, como solicitar comentarios de los usuarios al final de una conversación, registrar y notificar 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 los componentes personalizados que expliquen lo que hacen y la información que se les debe transmitir. Por lo tanto, las mejores formas de ayudar a los desarrolladores de aptitudes con el uso del 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 YAML incorporados 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 utilizamosoracle.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 que se debe procesar. A menudo, los datos transferidos a un componente personalizado no son el valor real con el que se va a trabajar, sino el nombre de una variable que contiene los valores de datos que se van a 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 las propiedades que hacen referencia a un nombre de referencia de variable. Puede mejorar aún más esto mediante las correcciones posteriores_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 las puede utilizar 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 recomendamos 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 también es el desarrollador de aptitudes que lo utiliza. Por este motivo, muchos desarrolladores simplifican su trabajo con componentes personalizados haciendo suposiciones sobre 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 tales 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.
Pensar en biblioteca
Una pregunta común es acerca de 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 que se relacionan 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, se debe responder a la pregunta sobre cómo empaquetar componentes personalizados 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 los componentes personalizados se desarrollan y utilizan 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 componentes que realmente se reutilizan en otras habilidades.
-
Los despliegues de contenedores de componentes embebidos están restringidos por el número de servicios de componentes personalizados por instancia de Oracle Digital Assistant. Por lo tanto, deseará utilizar un único servicio de componentes personalizados por aptitud o buscar un despliegue remoto de los componentes personalizados.
-
Utilice el despliegue de servicios de componentes personalizados remotos en Kubernetes en Oracle Cloud Infrastructure, por los siguientes motivos:
-
No revelar información confidencial contenida en el código de componente personalizado. Los servicios de componentes personalizados desplegados en el contenedor embebido los puede descargar cualquier persona que tenga acceso completo a la instancia de Oracle Digital Assistant.
-
Para implantar una mejor segmentación del código. Los componentes personalizados solo deben contener código que sea necesario para interactuar con el bot y llamar a 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 hace lo siguiente:
-
leer parámetros de entrada
-
valores de variable read/set
-
Gestionar los mensajes recibidos por un componente
-
Representar la interfaz de usuario del componente personalizado
-
determinar la transición a un siguiente estado
-
gestionar estado de componente
-
acceder a servicios REST
-
-
Mejorar el rendimiento. El contenedor integrado 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á altamente clasificada entre los desarrolladores de componentes personalizados, tiene sentido crear e implementar componentes personalizados de uso común en un servidor remoto. Es posible que tenga 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 despliega externamente, es mejor utilizar una biblioteca de registro diferente, como log4js.
Gestionar el estado interno del componente
Los componentes de flujo de diálogo personalizados pueden tener una interacción más larga con un usuario antes de que la navegación pase a un siguiente estado de 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. Existen 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 procede de la interfaz de usuario que está presentando o de otro componente. Para ello, puede comprobar el mensaje de devolución en cuanto a si contiene un token que el componente personalizado ha agregado al representar el elemento de acción.
-
Utilizar 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 una variable del nombre especificado no existe, se creará. El objeto "valor" puede ser cualquier cosa de la que necesite realizar un seguimiento.
Validar Parámetros de Entrada
Los parámetros de entrada que defina para un componente personalizado deben validarse para que tengan contenido. Esto también se aplica a los parámetros que defina como necesarios. Se deben comprobar 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 Respuesta común, que incluye 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 se crea un mensaje de componente único, que los conectores específicos del canal convierten en el formato requerido por el canal de cliente correspondiente.
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 la misma finalidad general, pero MessageFactory
tiene las siguientes ventajas:
- Soporta todos los tipos y propiedades de mensajes del modelo de mensajes común (CMM), en lugar de solo un subjuego.
- Su implantación se basa en clases, proporcionando un getter limpio, un setter y métodos de adición para cambiar la definición del mensaje. La finalización del código se realiza 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 el componente personalizado.
- La implantación utiliza el patrón de creador, que permite encadenar un número de setter o agregar métodos, haciendo que el código sea más legible y reduciendo 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 se abstraigan 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 utilidad, o se debe desplegar como servicios REST individuales en un servidor remoto o servicio en la nube.
- ☑ Cree un contrato claro y completo entre los componentes personalizados y las aptitudes en las que se utilizan.
- ☑ Uso de 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.
- ☑ Maneje 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: código de ejemplo MessageFactory para varias respuestas de la interfaz de usuario
Manejadores de eventos de entidades
Un manejador de eventos de entidades 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 basadas en modelos para interactuar y validar la entrada del usuario, 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
Muchas de las funcionalidades que se pueden definir para el componente Respuesta Común, como los botones globales de ayuda y cancelación, no están disponibles para el componente Resolver Entidades mediante la configuración.
Sin embargo, puede agregar funciones faltantes 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 llaman a las funciones del manejador de eventos de entidad al resolver una entidad de bolsa compuesta. No es necesario que realice un seguimiento de qué artículo de bolsa debe resolverse a continuación, ya que todo está hecho para usted.
Aún así, 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 resuelve la entidad de bolsa compuesta o se deja 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 hay limpieza que tenga que hacer.
- Para escritura, utilice:
context.setCustomProperty(name, value);
- Para leer, utilice:
context.getCustomProperty(name);
- Para escritura, 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 entidades.
- Para escritura, utilice:
context.variable(name,value);
- Para leer, utilice:
context.variable(name);
- Para escritura, 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, se recomienda utilizar la clase MessageFactory
para crear mensajes independientes del canal en lugar de generar cargas útiles específicas del canal. Los manejadores de eventos de entidades también admiten mensajes de tipo lista de valores, diseño de tarjeta y anexo.
Lista de comprobación para manejadores 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 componentes personalizados para todos los manejadores de eventos de entidades 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 de manejador de eventos de entidades en IDE externo
- Ejemplo: conversaciones basadas en modelos que utilizan EEH mediante un ejemplo de informe de gastos
- Documentación del SDK del nodo de bots: código de ejemplo MessageFactory 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 debe utilizar?
Los manejadores de eventos de entidades 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és usando ambos. Si sigue la recomendación de utilizar conversaciones basadas en modelos, será más probable que utilice manejadores de eventos de entidad que componentes de flujo de diálogo personalizados.
Desde un punto de vista funcional, los componentes de flujo de diálogo personalizados (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 |
---|---|---|
Soporte del módulo Node.js / desarrollo JavaScript | Sí | Sí |
Soporte de TypeScript | Sí | Sí |
Desarrollo basado en navegador | No | Sí |
Desarrollo en IDE externo | Sí | Sí |
Utilizar en flujos de diálogo | Sí | No |
Utilizar en entidades de bolsa compuesta | No | Sí |
Parámetros de entrada | Sí | No |
Navegación programática a transiciones de acción | Sí | No |
Llamar a servicios REST | Sí | Sí |
Leer desde/escribir en variables de flujo de diálogo | Sí | Sí |
Almacenar valores temporalmente en contexto de resolución | No | Sí |
Utilizar paquetes de recursos/soporte en varios idiomas | 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 | No | Sí |
Soporte de acción de devolución | Sí | Sí |
Uso de grupos de recursos para CCS y EEH
Los componentes personalizados del flujo de diálogo y los manejadores de eventos de entidades 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 que se definieran en una aptitud a partir de componentes personalizados. Pero ahora hay una nueva interfaz de programación que le permite referir claves de paquetes 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. Los parámetros con nombre utilizados con los paquetes de mensajes de ICU aún no son compatibles con la nueva API.
-
La API produce una expresión que, cuando se devuelve como respuesta de bot, se sustituye por la cadena de grupo de mensajes a la que se hace referencia para el idioma detectado.
Para llamar a la nueva API, utilice una de las siguientes llamadas a objetos 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 que utilizan la clase MessageFactory
.
-
Ejemplo de manejador de eventos de entidad:
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 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 puede 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 paquetes 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 acoplamiento estrecho 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 estrecho, debe hacerlo. En el caso de los manejadores de eventos, la posibilidad de reutilización es mínima, por lo que no debe haber ninguna duda sobre el uso de cadenas de grupos de recursos en los manejadores de eventos de entidades.
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.
Mediante una solución alternativa, puede evitar el acoplamiento estrecho 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.
¿Debería migrar a manejadores de eventos de entidades?
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 "me gusta" por "me gusta" no mejora tus habilidades. Si no está satisfecho con el flujo de conversación actual y está considerando el uso de entidades de bolsa compuesta para sustituir partes de la conversación de flujo de diálogo, ese es un buen motivo para mover la lógica de código de los componentes de flujo de diálogo personalizados a los manejadores de eventos de entidad.
Mejores prácticas al migrar a manejadores de eventos de entidades
Si decide mover la funcionalidad existente de los componentes de flujo de diálogo personalizados a los manejadores de eventos de entidad para mejorar el flujo de conversación, asegúrese de que no solo está intentando imitar el comportamiento que ha implantado con el componente de flujo de diálogo personalizado y el componente de respuesta común. En su lugar, empiece a utilizar el componente Resolve Entities y utilice las funciones del manejador de eventos de entidades para implantar toda la validación y la lógica necesarias para el caso de uso conversacional.