Chatboty i rozumienie języka naturalnego – integracja LUISa z Microsoft Bot Framework

W poprzednim artykule pt. Nasz pierwszy ChatBot pokazaliśmy jak stworzyć prostego chatbota, który posłuży jako dodatkowy kanał komunikacji z klientem. Zaimplementowaliśmy konwersację, która umożliwiała użytkownikowi zakup w naszym uproszczonym systemie sprzedażowym takich produktów jak: ubezpieczenie na dom, podróż czy samochód.

Linia dialogowa oparta była o tzw. button-focused flow, co oznacza, że użytkownik mógł wybierać jedynie między opcjami, które pojawiały się na ekranie.

Nie mógł posługiwać się językiem naturalnym, a więc wyrazić, czego oczekuje. Można powiedzieć, że naszemu rozwiązaniu brakowało “nutki” sztucznej inteligencji, która potrafiłaby zrozumieć użytkownika.
Nie oznacza to jednak, że jest to złe rozwiązanie. Przeciwnie, w kontekście nieustannie toczących się dyskusji nad tym, który sposób konwersacji jest lepszy, jedyną poprawną odpowiedzią pozostaje słynne “to zależy”.

Wspomniana “nutka” to jedno z wyzwań obszaru nauki nazywanego Natural Language Processing (NLP), na który składają się przede wszystkim: rozumienie mowy (speech recognition), generowanie języka naturalnego (natural language generation) i właśnie rozumienie języka naturalnego (natural language understanding).

W tym artykule pokażemy, jak w prosty sposób wewnątrz naszego chatbota użyć usługi interpretacji języka naturalnego LUIS, zbudowanej i rozwijanej przez Microsoft w ramach Cognitive Services.
Dla lepszego porównania wersji bez i z integracją zmiany wykonywane są na oddzielnym branchu luis.

 

luis.ai

Tworzymy intencje i encje

Pierwszym krokiem, jaki musimy zrobić jest stworzenie aplikacji w LUISie, co sprowadza się do określenia nazwy aplikacji i języka jaki ma być rozumiany.

integracja LUISa z Microsoft Bot FrameworkTworzenie nowej aplikacji na luis.ai

Jak widać na powyższym screenie, na liście prezentującej wspierane języki – brakuje polskiego. Jeśli komuś zależy na rozumieniu naszego języka, to sugerujemy zainteresować się rozwiązaniem Facebooka – wit.ai.

Ponieważ nasz bot jest międzynarodowy to porozumiewać się z nim będziemy za pomocą drugiego najpopularniejszego języka na świecie, czyli języka angielskiego.

Przed przejściem dalej konieczne jest zrozumienie dwóch podstawowych pojęć – intent oraz entity, które często przewijają się w obszarze NLU (Natural Language Understanding).

Intent to informacja o tym, co użytkownik chce zrobić pisząc dane zdanie (np. pozostając w obszarze ubezpieczeń może to być kupno nowego ubezpieczenia lub zgłoszenie szkody).

Entity używana jest jak zmienna w matematyce. Możemy dzięki niej przekazać ważną informację (np. rodzaj ubezpieczenia jaki chcemy kupić).

W naszym przypadku zdefiniowane zostały dwie intencje (BuyPolicy i RegisterClaim) oraz jedna encja (InsuranceType).

Podczas wprowadzania intencji należy podać około pięciu przykładów na to jak użytkownik może powiedzieć, że chce zrobić właśnie to. Dodatkowo, jeśli we wprowadzonej wypowiedzi występuje interesująca nas encja, powinniśmy ją oznaczyć.
Wszystko widoczne jest na poniższym screenie.

integracja LUISa z Microsoft Bot FrameworkPrzykładowy intent – BuyPolicy

Warto dodać, że w LUISie jest już kilka domen predefiniowanych, np. intencje i encje do zarządzania kalendarzem, automatyzacji domu, sterowania muzyką czy notatkami.

Więcej o tym jak zdefiniować, a następnie trenować naszą usługę dowiecie się po przeczytaniu dokumentacji.

Należy pamiętać, że to przede wszystkim od tych definicji i późniejszego trenowania zależy, jak dobrze usługa będzie rozumiała wypowiedzi człowieka. Podczas projektowania warto wziąć pod uwagę opisane tutaj najlepsze praktyki.

 

Trenowanie i publikacja

Po zdefiniowaniu intencji i encji, musimy oddać nasze definicje w ręce sztucznej inteligencji i dać jej się trochę pouczyć 🙂 Dzieje się to po naciśnięciu przycisku Train widocznego w prawym górnym rogu.
Jeśli wszystko skonfigurowane zostało poprawnie, dosłownie po chwili powinniśmy otrzymać komunikat o tym, że trenowanie zostało zakończone.

W tym momencie usługa jest już gotowa do publikacji. Podczas publikowania możemy wybrać środowisko (Staging/Production). My się nie boimy, więc jedziemy od razu na produkcję 🙂

integracja LUISa z Microsoft Bot Framework

Po chwili powinniśmy zostać przekierowani do ekranu, gdzie widoczny będzie adres URL, pod którym nasza usługa jest dostępna.

integracja LUISa z Microsoft Bot Framework

Klikając na zaznaczony URL otrzymamy endpoint gotowy do testów:

https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/<your_app_id>?subscription-key=<your_subscription_key>&timezoneOffset=-360&q=

Teraz możemy zacząć testy. Chcielibyśmy przetestować czy nasz LUIS poprawnie rozpoznaje zdanie I want to buy home insurance. Poniżej przedstawiony wynik udowadnia, że topScoringIntent oraz entity zostały zidentyfikowane poprawnie.

integracja LUISa z Microsoft Bot Framework

Teraz możemy przejść do działania od drugiej strony – integracji stworzonej usługi wewnątrz chatbota.

 

Integracja LUISa z Microsoft Bot Framework

Naszym celem jest zamiana pierwszego statycznego kroku (wybór pomiędzy dostępnymi opcjami), który aktualnie wygląda tak:

integracja LUISa z Microsoft Bot Framework 6 4

Chcemy dać użytkownikowi możliwość wyrażenia w naturalnym języku tego, co chciałby zrobić.

Precyzując, chcielibyśmy, aby użytkownik mógł wpisać: Hello, I want to buy home insurance. Bot powinien zrozumieć o co chodzi i przekierować użytkownika od razu do kupna konkretnego produktu (ewentualnie do wyboru produktu, jeśli nie został on wskazany w wypowiedzi). W powyższym przykładzie będzie to ubezpieczenie mieszkania/ domu.

Pierwszy krok jaki musimy wykonać, to wskazanie adresu usługi i skonfigurowanie bota tak, żeby zaczął korzystać z LUISa.

const recognizer = new builder.LuisRecognizer(process.env.LUIS_MODEL_URL);
bot.recognizer(recognizer);

Link do endpoint’a przechowywany jest w pliku .env, podobnie jak wszystkie inne zmienne środowiskowe wykorzystywane wewnątrz aplikacji.

Następnie należy delikatnie zmodyfikować pierwsze kroki naszego bota. Aktualnie zdefiniowane są one w funkcji getStartingSteps() i od razu wyświetlają podpowiedź, co użytkownik może zrobić:

function getStartingSteps() {
    return [
        function (session) {
            session.send('Hello in ASC LAB Insurance Agent Bot!');
            builder.Prompts.choice(
                session,
                'What do you want?',
                [IntentType.BUY_POLICY, IntentType.REGISTER_CLAIM],
                {
                    maxRetries: 3,
                    retryPrompt: 'Not a valid option'
                });
        },
        function (session, result) {
            [..]
        }
    ];
}

Jako, że chcemy te predefiniowane możliwe odpowiedzi zastąpić usługą rozpoznawania języka naturalnego, musimy je po prostu wyrzucić i zapytać użytkownika, co chciałby zrobić:

function getWelcomeSteps() {
    return [
        function (session) {
            session.send('Hello in ASC LAB Insurance Agent Bot!');
            session.send('What do you want?');
        }
    ];
}

Teraz powinniśmy wskazać, którą ścieżkę (dialog) ma uruchamiać bot po wykryciu konkretnej intencji w wypowiedzi. W naszej usłudze skonfigurowaliśmy dwie intencje – BuyPolicy oraz RegisterClaim.

bot.dialog('buy-insurance', getBuyInsuranceSteps()).triggerAction({matches: 'BuyPolicy'});
bot.dialog('register-claim', getRegisterClaimSteps()).triggerAction({matches: 'RegisterClaim'});

Powyższy zapis oznacza, że jeśli LUIS wykryje intencje BuyPolicy, to uruchomiony zostanie dialog buy-insurance.

W pierwszych linijkach poniższego dialogu jest próba odczytania encji InsuranceType mówiącej o tym jakim ubezpieczeniem zainteresowany jest użytkownik.

Jeśli nie zostało to zawarte w wypowiedzi (ponieważ użytkownik napisał tylko I want to buy insurance, bez konkretnego wskazania), musimy zapytać o to bezpośrednio.

Jeśli jednak zostało to określone (I want to buy travel insurance) użytkownik jest przekierowywany do konkretnej ścieżki sprzedażowej.

function getBuyInsuranceSteps() {
    return [
        function (session, result, next) {
            session.send('Great! You want to buy new insurance. We try recognize what insurance do you need...');
            console.log(result);
            let intent = result.intent;
            let insuranceType = builder.EntityRecognizer.findEntity(intent.entities, 'InsuranceType');
            if (!insuranceType) {
                session.send('Unfortunately, you have not written yet what insurance you need.');
                next();
            } else {
                switch (insuranceType.entity) {
                    case 'home':
                        return redirectToProperDialog(session, 'home');
                    case 'travel':
                        return redirectToProperDialog(session, 'travel');
                    case 'farm':
                        return redirectToProperDialog(session, 'farm');
                    case 'car':
                        return redirectToProperDialog(session, 'car');
                    default:
                        session.send('Unfortunately, you have not written yet what insurance you need.');
                        next();
                }
            }

        },
        function (session) {
            builder.Prompts.choice(
                session,
                'What kind of insurance do you need?',
                [InsuranceType.Driver.name, InsuranceType.Home.name, InsuranceType.Farm.name, InsuranceType.Travel.name],
                {
                    maxRetries: 3,
                    retryPrompt: 'Not a valid option'
                });
        }
        [...]
    ];
}

Na poniższym GIFie widać przekierowanie do ścieżki, w której można kupić ubezpieczenie typu travel (literówka zrobiona została celowo, żeby sprawdzić jak poradzi sobie z nią LUIS).

integracja LUISa z Microsoft Bot Framework 7 1

Dla porównania, poniżej widać sytuację, w której użytkownik nie napisał jaki typ ubezpieczenia go interesuje.

integracja LUISa z Microsoft Bot Framework 8 1

Większość zmian, które powyżej zostały opisane można obejrzeć w tym commicie. Cały kod dostępny jest na branchu luis.

Na koniec warto pokazać jak wygląda rozmowa z chatbotem przeprowadzona od początku do końca:

image4 1

Podsumowanie

Dzięki kilku krokom udało się połączyć naszego chatbota z LUISem – usługą służącą do rozumienia języka naturalnego.

Doszliśmy do satysfakcjonującego nas momentu, gdzie wewnątrz chatbota kończy się cały proces sprzedaży ubezpieczenia udostępniany przez LAB Insurance Sales Portal, a nasz chatbot jest przynajmniej w minimalnym stopniu inteligentny – potrafi zrozumieć wypowiedź człowieka.

Wykorzystanie botów w komunikacji z klientami istotnie rośnie, a rynek stawia coraz wyższe wymagania przed projektantami takich rozwiązań.
W naszym Software House Altkom Software & Consulting zauważamy te trendy. Widzimy zalety interfejsów komunikacyjnych i rozumiemy powody biznesowe, dla których firmy coraz częściej oferują swoje produkty przez wirtualnych asystentów. Dowodem na to są powyższe eksperymenty i udostępnione przykłady.

Autor: Robert Witkowski, Senior Software Engineer, ASC LAB