Integrando chatbot Rasa com outras aplicações

Já falamos aqui anteriormente sobre o Rasa. No artigo anterior fizemos um resumo geral e agora vamos aprofundar, focando especificamente na integração com outros sistemas, ou seja, como fazer o chatbot entender uma conversa e buscar informações em uma base de dados. Neste texto, vamos lembrar alguns termos que foram apresentados e que precisamos que estejam claros.  

Intenção (Intent): é o que o chatbot acha que você está querendo dizer. A partir de uma lista de exemplos que são treinados no chatbot é criado um modelo. Com esse modelo o Rasa vai tentar prever ou predizer o que o usuário está querendo falar.

Ação Personalizada (Custom Action): é possível escrever rotinas para fazer uma consulta num banco de dados, cálculos, relatórios, logs, enfim, qualquer coisa que possa ser feita num programa, e ainda acessar informações sobre a conversa, como interações anteriores com o chatbot. As ações personalizadas são escritas em Python.

Entidade (Entity): é uma parte variável da frase que pode ser considerada uma informação distinta. Isso parece confuso, então vamos dar um exemplo: Se tivermos uma intenção tipo “quais os hospitais em tal cidade?”, o “tal cidade” é uma entidade. Mesmo se a cidade fosse diferente de uma pergunta para outra, isolamos essa informação e fazemos uma busca para os hospitais da cidade especificada. 

Do mesmo jeito, uma frase do tipo “quais as minhas reuniões para tal dia?”, esse “tal dia” seria uma entidade. Uma entidade pode ter vários formatos. No caso do “tal dia” pode ser “quais as minhas reuniões para a próxima quarta”, “quais as minhas reuniões para o dia 10 de setembro”, ou ainda “quais as minhas reuniões para amanhã”. Em todos esses casos a entidade “data” é extraída da frase, e passada para uma ação personalizada para recuperar as informações daquele dia.

Slot: Não tem uma palavra específica no português, mas seria “ranhura” ou “fresta”. Imagine uma caixinha de correspondência que tem uma fresta por onde você pode passar uma folha de papel com um texto escrito. No Rasa, slots são usados para guardar informações no decorrer da conversa, que podem ser consultadas depois. Essas informações são guardadas nestas caixinha ou slots. Na programação tradicional o equivalente seriam as variáveis. Uma variável tem um nome e um valor, e um slot, do mesmo jeito, tem um nome e um conteúdo. Um slot pode ser de dois tipos básicos: um valor que não interfere no fluxo da conversa (que pode guardar qualquer tipo de informação); ou um valor que pode alterar o fluxo da conversa.

Como assim “interfere no fluxo da conversa”?

Se temos um slot com o sexo do usuário, quando ele (ou ela) escrever “como vai?”, podemos desviar uma conversa de acordo com o conteúdo desse slot, mostrando respostas diferentes para cada caso. Se for um homem mostramos “Eu vou bem, e o senhor, como está?” e se for uma mulher respondemos “Eu vou bem, e a senhora, como está?”. Dentro do tipo que interfere no fluxo da conversa, temos tipos específicos de slot: podemos ter slots numéricos, de texto, lógicos (tipo verdadeiro ou falso) ou categóricos (onde temos uma opção dentro de uma lista de possibilidades). Um exemplo de slot categórico seria sexo: masculino, feminino ou não informado.

Mas um detalhe, mesmo sendo do tipo que interfere no fluxo da conversa, somente conseguimos analisar o conteúdo do slot quando se trata de um slot categórico. Para os outros tipos só sabemos se tem algo no slot, ou se está vazio.

Podemos alterar o conteúdo de um slot de várias formas: preencher automaticamente com a informação extraída de uma entidade com o mesmo nome, mandar diretamente um valor para um slot através de uma API, ou alterar dentro de uma ação personalizada.

Observe que podemos usar a mesma entidade para preencher vários slots! Vamos supor que seja para calcular a área de um retângulo, onde área é igual a altura vezes a largura. Uma entidade “comprimento” pode ser ora a altura, ora a largura. E qual valor dependerá da conversa em si.

Resposta (ou Response): É uma frase que o chatbot irá responder para o usuário. Pode ser só um texto ou pode conter slots no meio da frase. Por exemplo, se temos uma frase de bom dia, e um slot contendo o nome do usuário, podemos colocar essa informação no meio da frase e falar “Bom dia, João” ou “Bom dia, Paulo”. Podemos cadastrar várias frases diferentes, e neste caso, o chatbot irá escolher aleatoriamente uma das respostas, e com isso tornamos as conversas mais humanas e menos fixas.

Respostas também podem conter botões. Definimos os botões, o que deve aparecer no botão, e se o usuário clicar em um desses botões será enviada a frase programada no botão para o chatbot.

Formulário (Form em Inglês): definimos um ou mais slots obrigatórios, e então o formulário age como se fosse uma “trava” na conversa, permitindo apenas que o usuário siga adiante caso todos esses slots estejam preenchidos. Podem ser preenchidos com qualquer texto que o usuário digitar, ou a partir de entidades extraídas de diálogos que o usuário escrever. Formulários são programados em Python, assim como ações personalizadas. Devemos ter frases resposta específicas para solicitar cada um dos slots que ainda não foram preenchidos.

Vamos ver um exemplo disso: se temos uma conversa que vai mostrar quais são os hospitais da minha cidade, eu não posso prosseguir na conversa até que o slot contendo o nome da cidade esteja preenchido. Neste caso, o formulário vai olhar o slot, e se não estiver preenchido, vai disparar a frase “Em que cidade?” e esperar a pessoa digitar o nome da cidade.

Podemos validar o nome da cidade dentro do formulário, e caso não seja um nome válido, pedimos novamente. Somente depois que o usuário digitar uma cidade válida é que seguimos e fazemos a consulta num banco de dados para mostrar quais os hospitais cadastrados para aquela cidade.

Estória (ou Story): é a cola que junta todos esses pedaços. É uma sequência de intenções, respostas, formulários ou ações do chatbot que vai dar forma à conversa. A forma mais simples de uma estória é uma intenção e uma resposta, que vai criar o seguinte comportamento: se o usuário digitar determinada coisa, responde com tal coisa. 

Estórias mais complexas usam ações personalizadas e formulários para enriquecer a experiência do usuário. Todas essas informações ficam distribuídas em vários arquivos. Temos o arquivo de configuração, config.yml, onde ficam os parâmetros de treinamento, e qual a sequência de módulos que serão usados para interpretar o texto e treinar o modelo.

Temos o domain.yml contendo uma lista de todas as ações (ações personalizadas e respostas do chatbot), intenções, entidades e slots, além de todos os textos de respostas que o chatbot deve mostrar. Dentro de uma pasta chamada data colocamos as estórias e as frases de exemplo para o treinamento do chatbot, sendo que temos a opção de organizar melhor os arquivos, colocando em duas subpastas: data/core (para as estórias) e data/nlu (para as frases de exemplo).

Na Viceri desenvolvemos uma ferramenta para administrar o chatbot com mais facilidade, permitindo que através de uma aplicação web, você consiga gerenciar todas essas informações.

Depois de conhecer estes termos, nos próximos artigos vamos entrar mais nos detalhes da programação e dar exemplos mais detalhados de como se encaixa tudo isso.

Ficou interessado em saber mais sobre o assunto? O time da Viceri tem especialistas que podem ajudar você a encontrar as respostas que precisa. Entre em contato com a gente!

Formatos de dados necessários para treinar seu chatbot

Antes de começar a ler este artigo, é importante que você esteja familiarizado com alguns termos e explicações que demos em outros textos anteriormente. Por isso, leia também Integrando chatbot Rasa com outras aplicações e RASA: Conheça o software em python utilizado para criação de chatbots.

Neste artigo vamos começar a examinar os formatos de dados necessários para você treinar seu chatbot. Basicamente, o treino vai pegar informações de NLU (que é a compreensão de linguagem natural – Natural Language Understanding), dados de estórias (fluxos de conversa), e o arquivo de domínio (respostas do chatbot e organização das conversas) e vai aplicar o processo definido no arquivo de configuração. Então temos:

NLU + Estórias + Domínio -> Config -> Modelo

O RASA espera que os arquivos estejam organizados da seguinte forma: Domain.yml e config.yml na pasta “raiz”. NLU e estórias (com extensão .md) na subpasta “data”. Você também pode criar duas subpastas dentro de “data” (chamados “core” e “nlu”) e colocar os arquivos dentro das respectivas subpastas. Caso não for fazer isso, o arquivo com NLU deve se chamar nlu.md e o arquivo de estórias, story.md.

Se você separar nas subpastas “data/nlu” e “data/core”, pode dividir os exemplos e estórias por assunto e separar em vários arquivos, com qualquer nome desde que estejam nas pastas corretas.

Os arquivos Domain e Config são no formato yml e os arquivo de exemplo (nlu) e estórias (core) são no formato md (de markdown). Numa versão próxima do RASA provavelmente todos os arquivos serão no formato yml, mas aqui vamos ver o formato atual, md.

Para você começar com um conjunto de arquivos base, pode executar o comando “rasa init”, mas cuidado: isto vai limpar dados que já existirem na pasta onde você executar o comando.

O arquivo domain.yml

O arquivo domain é dividido em várias “seções”: Declaração de intenções; Declaração de ações; Declaração de entidades; Declaração de slots; Respostas do chatbot; Dados sobre seção do usuário.

Veja os exemplos de cada seção

Cada seção começa com uma linha com o nome da seção seguido de dois pontos. Vamos ver um exemplo da seção de intenções:

intents:
– saudação
– despedida
– feliz
– triste

Observe que cada nome de intenção começa com um – e um espaço. Isto tem de ser obrigatoriamente dessa forma. Todas as intenções que for usar nas conversas devem estar relacionadas aqui. Logo mais vamos ver melhor como define uma intenção, mas por enquanto basta saber que uma intenção é composta de um nome e vários exemplos. Aqui colocamos o NOME. Deve estar escrita exatamente da mesma forma que no arquivo NLU.

Para nomes de ações, intenções, slots e entidades, recomenda-se usar apenas as 26 letras do alfabeto (sem acentos) e números de 0 a 9 e o underscore (símbolo do sublinhado), sempre começando com uma letra. Use nomes que têm a ver com o assunto, como procura_hospital, escolher_filmes e assim por diante. Não há limite para o comprimento do nome, mas nomes compridos demais podem dificultar na hora de digitar o nome.

Depois de listar todas as intenções, vamos colocar as ações, que podem ser ações personalizadas ou então respostas do chatbot.

Um exemplo da seção de ações está abaixo:

actions:
– utter_saudacao
– utter_despedida
– utter_alegrar
– action_busca_hospital

Temos o nome da seção “action”, seguido de dois pontos, e cada uma das ações na sua linha, começando com hífen seguido de espaço. Repare como separamos as palavras com sublinhado (_). Os nomes não podem conter espaços, então use o sublinhado (_) para separar as palavras. Não junte tudo (comoAlgumaLinguagensDeProgramacaoFazem), e dê nomes que tem a ver com o que a ação faz.

Por padrão, uma resposta do chatbot começa com “utter” que quer dizer “falar” ou “expressar”. Pronuncia-se “a-ter”. A pronúncia correta é essencial. Se você for falar “u-ter” com qualquer estrangeiro, ele não vai entender do que está falando e provavelmente achar engraçado. Existem alguns nomes “padrões” para utter que veremos quando formos falar a respeito de formulários.

Assim como uma resposta do chatbot começa com “utter”, uma ação personalizada por padrão começa com “action”.

Depois de listar todas as ações do seu projeto, vamos definir as entidades e os slots.

Veja um exemplo de seção de entidades:

entities:
– grupo
– cor
– cidade

Entidades são informações que serão extraídas de frase. Um exemplo seria extrair a cor da frase “Estou procurando uma caixa verde”.

Na parte onde formos falar de NLU (exemplos para o chatbot) falaremos mais sobre entidades. Por enquanto, basta saber que você atribui um nome a uma entidade. Se não tiver nenhuma entidade a ser extraída de frases, não é necessário ter uma seção de entidades no domain.

Depois de declarar entidades, deve declarar os slots. Caso queira que o slot seja preenchido automaticamente por uma entidade, basta defini-lo com o mesmo nome.

Um exemplo de seção de slots:

slots:
nome:
type: unfeaturized
perfil:
type: categorical
values:
– anonimo
– basico
– vip
descricao:
type: unfeaturized

Na hora de declarar os slots, você precisa informar o tipo, que pode ser:

Text: irá guardar uma informação texto;
Boolean: irá guardar uma informação verdadeiro/falso;
Categorical: irá guardar a seleção entre uma lista de possibilidades (sexo masculino, feminino ou não informado);
Float: irá guardar uma informação numérica;
List: irá guardar uma lista de valores;
Unfeaturized: este é o ÚNICO tipo que não influencia no fluxo da conversa.

Para todos os tipos exceto unfeaturized, boolean e categorical, só é possível saber que há um valor no slot, mas não comparar com outros valores. O unfeaturized, por definição, não influencia no andamento da conversa. É possível verificar o valor de um slot categórico ou boolean e influenciar no andamento da conversa.

No domain também declaramos formulários da mesma forma:

forms:
– registro_form

A Viceri desenvolveu uma ferramenta que você pode usar para criar estes arquivos automaticamente, sem se preocupar com a formatação das informações. Basta preencher os exemplos com as frases que o chatbot irá falar, montar as conversas de uma forma interativa, e a partir de um painel administrativo solicitar para treinar um modelo.

Nos próximos artigos continuaremos vendo como declarar respostas ao usuário no arquivo domain.yml, e como são formatados os arquivos de exemplos (NLU) e estórias. Gostou?

Confira nossos próximos posts ou fale agora com o time da Viceri. Estamos sempre prontos para auxiliar você sempre que precisar.