Integração de Código Personalizado e Backend
Aqui estão algumas melhores práticas para escrever código personalizado e fazer integração de backend para assistentes digitais.
No final de uma conversa, você precisa fazer algo com as informações coletadas de um usuário. Esse "algo" geralmente requer acesso a um serviço de backend para consultar dados ou dados persistentes para os quais você precisa criar componentes personalizados. Outro uso para componentes personalizados é incorporar lógica personalizada que lida com validações complexas ou outras funções do utilitário. O Oracle Digital Assistant suporta dois tipos de componentes personalizados:
- Componentes de fluxo de caixas de diálogo personalizadas (CCS)
- Handlers de eventos de entidade (EEH)
Durante a fase de planejamento e design do seu assistente digital, identifique os recursos de backend necessários e decida se as APIs disponíveis para ele são suficientes ou não.
- Como os assistentes digitais não são aplicativos web, as APIs existentes podem precisar ser otimizadas ou abstraídas por meio de uma camada de otimização para retornar apenas os dados e a quantidade de dados necessários em uma conversa do assistente digital.
- Se você não tiver serviços REST para a funcionalidade de backend para integração em uma conversa do assistente digital, será necessário projetar e acionar um projeto para criá-los.
Ao implementar sua integração de serviço de backend, você toma decisões sobre se deseja implantar componentes personalizados remotamente ou usar os contêineres de componentes incorporados nas habilidades do Oracle Digital Assistant.
Como a figura abaixo indica, a integração de backend é uma parte necessária da fase de planejamento e implementação.
Componentes do Fluxo de Caixa de Diálogo Personalizado
Com componentes de fluxo de caixas de diálogo personalizados, você pode gravar seus próprios componentes de interface do usuário que pode adicionar ao seu fluxo de caixas de diálogo para executar a lógica de código personalizado no contexto de uma conversa. Os casos de uso para gravar esses componentes incluem:
-
Consultar e gravar serviços de backend remoto por meio de serviços REST.
-
Soluções prontas para uso que lidam com todas as interações do usuário para uma tarefa específica, como solicitar feedback do usuário no final de uma conversa, registrar e relatar erros para um administrador, etc.
-
Suporta o gerenciamento de dados em matrizes de objetos salvas em uma variável de fluxo de caixas de diálogo.
Usar bons nomes para componentes e parâmetros de entrada
Não há um campo para fornecer descrições de componentes personalizados que expliquem o que eles fazem e quais informações devem ser passadas para eles. Portanto, as melhores maneiras de ajudar os desenvolvedores de habilidades com o uso do seu componente são usar bons nomes para os parâmetros de componente e entrada e escolher cuidadosamente as strings de ação que o seu componente retorna.
-
Os componentes YAML incorporados usam
System.<name>
como seu nome. Portanto, especialmente para fluxos de caixas de diálogo baseados em YAML, talvez você queira usarCustom.<name>
para revisores de habilidades para entender que é um componente personalizado ao qual o fluxo de caixas de diálogo faz referência. Ou você pode usar um espaço de nome para fornecer contexto. Para nossos componentes personalizados de amostra, geralmente usamosoracle.sample.<name>
para indicar que esses componentes não devem ser de qualidade de produção. -
Os parâmetros de entrada fornecem dados para o componente personalizado a ser processado. Em geral, os dados passados para um componente personalizado não são o valor real com o qual trabalhar, mas sim o nome de uma variável que contém os valores de dados a serem processados ou para a qual os dados consultados de um serviço remoto devem ser gravados. Observando os componentes incorporados, eles usam
variable
como o nome da propriedade para conter o nome da variável na qual o resultado do componente será gravado ou<name>Var
(por exemplo,nlpResultVar
) para indicar propriedades que fazem referência a um nome de referência da variável. Você pode melhorar ainda mais isso usando os postfixos_in
e_out
para indicar se uma variável se refere a uma variável que contém dados ou se está esperando dados do componente. -
As strings de ação são opcionais e podem ser usadas pelo desenvolvedor da habilidade para determinar o próximo estado do fluxo de caixas de diálogo para o qual navegar. O uso de
success
oufailure
como uma string de ação não fornece muito contexto; portanto, sugerimos o uso de algo comoorderSubmitted
,orderRejected
ouuserUnauthorized
.
Evite fazer suposições em seu código
A realidade é que muitas vezes o desenvolvedor de um componente personalizado também é o desenvolvedor de habilidades que o usa. Por esse motivo, muitos desenvolvedores simplificam seu trabalho com componentes personalizados, fazendo suposições sobre variáveis que estão presentes na habilidade. Assim, em vez de passar o nome de uma variável para o componente, eles se referem diretamente ao nome na lógica do componente personalizado. Não recomendamos isso porque essas suposições podem facilmente quebrar um componente personalizado. Recomendamos a definição de um contrato claro e completo entre o componente personalizado e as habilidades que o utilizam.
Biblioteca Think
Uma pergunta comum é sobre quantos componentes personalizados devem ser adicionados a um pacote de serviços de componentes personalizados. Em geral, é sempre uma boa ideia pensar em serviços de componentes personalizados, e os componentes que ele contém, como bibliotecas. Assim, todos os componentes que se relacionam a uma tarefa podem ser salvos em um único serviço de componente personalizado. No entanto, as recomendações precisam ser capazes de enfrentar a realidade. Portanto, a pergunta sobre como empacotar componentes personalizados precisa ser respondida com base no uso pretendido dos componentes personalizados.
-
A reutilização não é uma opção para muitos desenvolvedores de componentes personalizados. Quando componentes personalizados são desenvolvidos e usados em uma habilidade específica, faz sentido agrupar todos esses componentes em uma única implantação de serviço de componente personalizado. A exceção é para componentes que são realmente reutilizados em outras habilidades.
-
Implantações de contêiner de componentes incorporados são restritas pelo número de serviços de componentes personalizados por instância do Oracle Digital Assistant. Portanto, você desejará usar um único serviço de componente personalizado por habilidade ou procurar uma implantação remota de seus componentes personalizados.
-
Use a implantação remota de serviço de componente personalizado para o Kubernetes no Oracle Cloud Infrastructure, pelos seguintes motivos:
-
Não divulgar informações confidenciais contidas no código do componente personalizado. Os serviços de componentes personalizados implantados no contêiner incorporado podem ser baixados por qualquer pessoa que tenha acesso total à sua instância do Oracle Digital Assistant.
-
Melhor segmentação do seu código. Os componentes personalizados devem conter apenas o código necessário para interagir com o bot e chamar serviços REST. Todos os outros códigos devem ser armazenados em arquivos externos JavaScript (se estiver usando um contêiner incorporado) ou em camadas de integração (serviços REST). Os componentes personalizados incluem um código que faz o seguinte:
-
parâmetros de entrada de leitura
-
valores de variáveis de leitura/definição
-
tratar mensagens recebidas por um componente
-
renderizar a interface de usuário do componente personalizado
-
determinar a transição para um próximo estado
-
gerenciar estado do componente
-
acessar serviços REST
-
-
Para melhorar o desempenho. O contêiner incorporado para implementar componentes personalizados em habilidades usa funções da OCI, que têm um atraso de início a frio. Para evitar esse atraso, bem como o limite no número de serviços que podem ser implantados, uma implantação remota de componente personalizado fornece uma alternativa sem preocupações.
-
Para compartilhar componentes comuns. Embora nossa experiência seja que a reutilização não seja altamente classificada entre os desenvolvedores de componentes personalizados, faz sentido criar e implantar componentes personalizados comumente usados em um servidor remoto. Você pode ter componentes comuns para coisas como tratamento de erros e escalação, tratamento de autorização OAuth2 de 2 etapas e muito mais.
-
Como escrever mensagens de log
O logger padrão implementado para componentes personalizados é o logger da console. Você acessa o logger por meio de uma chamada para context.logger()
. Você pode usar as funções de log de chamadas disponíveis para o logger da console como ".info('…')
ou ".warn('…')
".
Observação: O uso de context.logger()
faz mais sentido ao implantar no contêiner incorporado, pois o contêiner incorporado sabe como exibir corretamente esses logs. Para componentes personalizados que você implanta externamente, é melhor usar outra biblioteca de logs, como log4js.
Gerenciar o Estado Interno do Seu Componente
Os componentes de fluxo de caixas de diálogo personalizados podem ter uma interação mais longa com um usuário antes da transição da navegação para um próximo estado de fluxo de caixas de diálogo. Para essa interação, você precisa se certificar de que o componente lida com seu estado interno para que ele possa distinguir entre uma chamada inicial e as chamadas subsequentes. Há duas opções para isso:
-
Adicione um token ao payload da mensagem de postback. Quando o componente personalizado renderiza uma interface de usuário na qual os usuários podem pressionar um item de ação, uma mensagem de postback é enviada de volta ao componente personalizado. O componente personalizado deve avaliar as mensagens de postback que recebe para determinar se esse postback é da interface do usuário que está sendo renderizado ou de outro componente. Para isso, ele pode verificar a mensagem de postback se ela contém um token que o componente personalizado adicionou ao renderizar o item de ação.
-
Usar uma variável de fluxo de caixas de diálogo. Se precisar gerenciar um estado mais complexo entre chamadas de componentes personalizados, por exemplo, para rastrear valores extraídos de mensagens do usuário, você poderá usar uma variável de fluxo de caixas de diálogo para isso. Os componentes personalizados podem criar variáveis de fluxo de caixas de diálogo no runtime em uma chamada para
context.variable('variable name', value)
. Se não existir uma variável do nome especificado, ela será criada. O objeto "valor" pode ser qualquer coisa que você precise controlar.
Validar Parâmetros de Entrada
Os parâmetros de entrada que você define para um componente personalizado precisam ser validados para ter conteúdo. Isso também se aplica a parâmetros definidos conforme necessário. Os seguintes casos precisam ser verificados:
-
O parâmetro de entrada tem um valor definido.
-
O valor não começa com
'$ {'
, pois isso indica uma expressão para ler o valor do parâmetro de entrada de uma variável ou que um objeto não foi resolvido corretamente no fluxo de caixas de diálogo.
Usar a Classe MessageFactory para Mensagens do Componente
Todas as respostas de bot que você envia de um componente personalizado devem usar a classe MessageFactory
. A classe MessageFactory
pode ser usada para criar o mesmo tipo de mensagens de usuário rich como o componente Resposta Comum, que inclui lista de valores, anexos, layouts de cartão e mensagens de texto.
Além disso, as mensagens definidas com a classe MessageFactory
são independentes de canal. Isso significa que você cria uma mensagem de componente único, que é convertida pelos conectores específicos do canal no formato exigido pelo respectivo canal do cliente.
Para acessar a classe MessageFactory
de um componente personalizado, use a seguinte referência:
let MessageFactory = context.MessageFactory();
A classe
MessageFactory
substitui a classe MessageModel
, que foi preterida. Ambas as classes têm a mesma finalidade geral, mas o MessageFactory
tem as seguintes vantagens:
- Ele suporta todos os tipos de mensagem e propriedades do Common Message Model (CMM), em vez de apenas um subconjunto.
- Sua implementação é baseada em classe, fornecendo getter limpo, setter e métodos de adição para alterar a definição da mensagem. O autocompletar código é ao usar Typescript e também em JavaScript quando as definições de tipo adequadas são incluídas na parte superior do processador de eventos ou componente personalizado.
- A implementação usa o padrão builder, que permite encadear um número de setter ou adicionar métodos, tornando o código mais legível e reduzindo o número de linhas que você tem que codificar
Lista de Verificação para Componentes Personalizados
- ☑ Certifique-se de que os serviços de backend sejam otimizados ou abstraídos para uso com habilidades.
- ☑ Os componentes personalizados só devem conter código relacionado ao bot. Todos os outros códigos devem ser movidos para classes ou bibliotecas de utilitários ou implantados como serviços REST individuais em um servidor remoto ou serviço de nuvem.
- ☑ Crie um contrato claro e completo entre os componentes personalizados e as habilidades nas quais eles são usados.
- ☑ Use componentes personalizados para avaliações complexas. Evite o Apache FreeMarker nesses casos.
- ☑ Gerencie o estado do componente para interações de usuário de várias solicitações.
- ☑ Valide todos os parâmetros de entrada do componente personalizado.
- ☑ Tratar erros retornando uma string de ação para o desenvolvedor da habilidade tratar problemas.
Saiba Mais
- Tutorial: Desenvolvimento de componentes personalizados para integração de backend
- Tutorial: Depuração de componente personalizado
- Limites de Contêiner Incorporados para Serviços de Componentes Personalizados
- Documentação do Bots Node SDK: MessageFactory código de amostra para várias respostas da IU
Handlers de Eventos de Entidade
Um handler de eventos de entidade é um tipo de componente personalizado que permite chamar o código do componente personalizado no contexto de resolução de entidades compostas. Os handlers de eventos de entidade são usados em conversas orientadas por modelo para interagir e validar a entrada do usuário e para chamar serviços de backend remoto para acesso de leitura e gravação. Ao contrário dos componentes personalizados do fluxo de caixas de diálogo, a chance de reutilização é mínima para um handler de eventos. É por isso que a implementação padrão do handler de eventos de entidade é para o contêiner de habilidades incorporado.
Adicionar Funcionalidade Ausente para Resolver Componentes de Entidades
Muitas das funcionalidades que podem ser definidas para o componente Resposta Comum, como botões globais para ajuda e cancelamento, não estão disponíveis para o componente Resolver Entidades por meio da configuração.
No entanto, você pode adicionar a funcionalidade ausente usando handlers de eventos de entidade. Isso permite que você aproveite a simplicidade do componente Resolver Entidades no fluxo de caixas de diálogo sem sacrificar a funcionalidade avançada.
Gerenciar Estado
As funções do handler de eventos de entidade são chamadas pelos componentes Resolver Entidades e Resposta Comum ao resolver uma entidade composta. Não há necessidade de rastrear qual item de bolsa precisa ser resolvido em seguida, pois tudo é feito para você.
Ainda assim, você pode querer salvar algumas informações para uso posterior. Para isso, você tem duas opções:
-
Propriedades de resolução de contexto são variáveis que você cria no objeto de contexto. As variáveis e seus valores existem até que a entidade composta seja resolvida ou você saia do estado do fluxo de caixas de diálogo que resolve uma entidade composta. O benefício de usar as propriedades de resolução de contexto é que não há nenhuma governança que você precise fazer.
- Para escrever, use:
context.setCustomProperty(name, value);
- Para leitura, use:
context.getCustomProperty(name);
- Para escrever, use:
-
Variáveis de fluxo da caixa de diálogo criadas no runtime ou no design time podem ser usadas para armazenar valores que você deseja persistir além da resolução da entidade composta. O conteúdo armazenado em variáveis do fluxo de caixas de diálogo pode ser acessado nos estados do fluxo de caixas de diálogo (somente para variáveis definidas no design time) e em outros handlers de eventos de entidade.
- Para escrever, use:
context.variable(name,value);
- Para leitura, use:
context.variable(name);
- Para escrever, use:
Como escrever mensagens de log
O logger padrão implementado para handlers de eventos de entidade é o logger de console.
Você acessa o logger por meio de uma chamada para context.logger()
.
Você pode usar as funções de log de chamadas disponíveis para o logger da console como .info('…')
ou .warn('…')
.
Exibindo Mensagens do Usuário
As mensagens personalizadas do usuário são exibidas por meio da função context.addMessage()
. Assim como acontece com os componentes de fluxo de caixas de diálogo personalizados, nossa recomendação é usar a classe MessageFactory
para criar mensagens independentes de canal, em vez de gerar payloads específicos de canal. Os processadores de eventos de entidade também suportam mensagens do tipo lista de valores, layout do cartão e anexo.
Lista de Verificação para Handlers de Eventos de Entidade
- ☑ Armazene valores temporários no contexto de resolução, a menos que seja necessário em um estado de fluxo de caixas de diálogo posterior.
- ☑ Use um único serviço de componente personalizado para todos os handlers de eventos de entidade usados em uma habilidade.
- ☑ Use a classe
MessageFactory
para que as mensagens sejam exibidas aos usuários.
Saiba Mais
- Vídeo do Oracle Digital Assistant Design Camp: Noções Básicas sobre Handlers de Eventos de Entidade
-
Tutorial: Desenvolvendo Handler de Eventos de Entidade no browser
- Tutorial: Desenvolvendo Handler de Eventos de Entidade no IDE externo
- Exemplo: Conversas orientadas por modelo usando EEH por exemplo de um relatório de despesas
- Documentação do Bots Node SDK: MessageFactory código de amostra para várias respostas da IU
- Documentação: Funções do handler de eventos de entidade (expostas no objeto de contexto)
Qual Componente Você Deve Usar?
Os handlers de eventos de entidade são para uso com entidades compostas, enquanto os componentes de fluxo de caixas de diálogo personalizados são usados no contexto de conversas em transição entre os estados do fluxo de caixas de diálogo. Em última análise, você provavelmente estará usando ambos. Se você estiver seguindo a recomendação de usar conversas orientadas por modelo, terá mais probabilidade de usar handlers de eventos de entidade do que componentes de fluxo de caixas de diálogo personalizados.
Do ponto de vista funcional, os componentes de fluxo de caixas de diálogo personalizados (CCS) e os Handlers de Eventos de Entidade (EEH) são muito semelhantes. A tabela abaixo compara os dois tipos de componentes personalizados.
Funcionalidade | CCS | EEH |
---|---|---|
Suporte ao módulo Node.js / desenvolvimento do JavaScript | Sim | Sim |
Suporte a TypeScript | Sim | Sim |
Desenvolvimento baseado em navegador | Não | Sim |
Desenvolvimento em IDE externo | Sim | Sim |
Usar em fluxos de caixas de diálogo | Sim | Não |
Usar em entidades compostas | Não | Sim |
Parâmetros de entrada | Sim | Não |
Navegação programática para transições de ação | Sim | Não |
Chamar serviços REST | Sim | Sim |
Ler de/gravar em variáveis do fluxo de caixas de diálogo | Sim | Sim |
Armazenar valores temporariamente no contexto de resolução | Não | Sim |
Usar pacotes de recursos/suporte a vários idiomas | Sim | Sim |
Renderize interfaces de usuário avançadas e prompts para interagir com usuários | Sim | Sim |
Suporte à implantação de contêineres de habilidades | Sim | Sim |
Suporte à implantação remota | Sim | Sim |
Suporte a depuração local (requer NGROK ou outros túneis) | Sim | Sim |
Eventos personalizados | Não | Sim |
Suporte à ação de contabilização retroativa | Sim | Sim |
Usando Pacotes de Recursos para CCS e EEH
Os componentes de fluxo de caixas de diálogo personalizados e os handlers de eventos de entidade que exibem mensagens de bot para o usuário devem exibir mensagens nos idiomas suportados pelo assistente digital.
Até recentemente, não havia uma maneira fácil de usar pacotes de recursos definidos em uma habilidade a partir de componentes personalizados. Mas agora há uma nova interface de programação que permite fazer referência a chaves de pacotes de recursos em seu código. Existem duas restrições conhecidas que você deve estar ciente:
-
O uso de strings de pacotes de recursos é limitado a pacotes de recursos sem parâmetros ou com parâmetros posicionais. Os parâmetros nomeados como usados com pacotes de mensagens da UTI ainda não são suportados pela nova API.
-
A API produz uma expressão que, quando retornada como resposta de bot, é substituída pela string de pacote de mensagens referenciada para o idioma detectado.
Para chamar a nova API, use uma das seguintes chamadas de objeto de contexto:
let expression = context.translate('resource_bundle_key_name');
let expression = context.translate('resource_bundle_key_name', param1, param2);
A expressão pode ser usada em respostas de texto, como labels de botão e em cartões usando a classe MessageFactory
.
-
Amostra do handler de eventos de entidade:
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);
-
Exemplo de fluxo de caixas de diálogo personalizadas:
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 também o artigo TechExchange Usar parâmetros de entrada para passar strings de pacotes de recursos traduzidas para componentes personalizados.
Como Usar Parâmetros Nomeados
Veja como acessar parâmetros nomeados em um pacote 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);
Nossa Recomendação Sobre Pacotes de Recursos e Componentes Personalizados
Usar pacotes de recursos em todos os lugares é um tema comum neste guia. No entanto, o uso de pacotes de recursos armazenados em uma habilidade cria um acoplamento estreito entre o componente de fluxo de caixas de diálogo personalizado ou o handler de eventos e a habilidade. Se você está bem com essa dependência e valoriza o benefício de ter cadeias de recursos gerenciadas em um único lugar mais do que evitar o problema do acoplamento apertado, você deve fazê-lo. Para manipuladores de eventos, a chance de reutilização é mínima de qualquer maneira, e é por isso que não deve haver dúvida sobre o uso de strings de pacotes de recursos em manipuladores de eventos de entidade.
Para componentes de fluxo de caixas de diálogo personalizados que são reutilizados em diferentes habilidades, a função de tradução também funcionará se as habilidades tiverem os nomes de chave do pacote de recursos exigidos pelo componente personalizado adicionado ao pacote de recursos.
Usando uma solução alternativa, você pode evitar o acoplamento rígido de componentes personalizados a uma habilidade, transmitindo as mensagens lidas de um pacote de recursos como parâmetros de entrada para um componente de fluxo de caixas de diálogo personalizado.
Você Deve Migrar para Handlers de Eventos de Entidade?
Se você passar de componentes de fluxo de caixas de diálogo personalizados para handlers de eventos de entidade, isso deve ser por um motivo específico, não apenas porque é uma nova tecnologia. Mudar likes por likes não melhora suas habilidades. Se você estiver insatisfeito com o fluxo de conversas atual e estiver considerando usar entidades compostas para substituir partes da conversa do fluxo de caixas de diálogo, esse é um bom motivo para mover a lógica do código dos componentes de fluxo de caixas de diálogo personalizados para os handlers de eventos de entidade.
Melhores Práticas ao Migrar para Handlers de Eventos de Entidade
Se você decidir mover a funcionalidade existente dos componentes de fluxo de caixas de diálogo personalizados para os processadores de eventos de entidade para melhorar o fluxo de conversas, certifique-se de não estar apenas tentando imitar o comportamento implementado com o componente de fluxo de caixas de diálogo personalizado e o componente Resposta Comum. Em vez disso, comece a usar o componente Resolver Entidades e use as funções do processador de eventos de entidade para implementar toda a validação e lógica necessárias para seu caso de uso de conversação.