Symptomate bot – tak nazywa się medyczny chatbot, nad którym pracujemy od kilku miesięcy. Symptomate analizuje objawy użytkownika, po czym prezentuje prawdopodobne dolegliwości. Zaczynając pracę nad Symptomate nie wiedzieliśmy, jakie problemy napotkamy po drodze. Ten tekst jest opisem naszych obserwacji i doświadczeń.
Bot to kolejny interfejs dla rozwiązań, nad którymi pracujemy w Infermedica. Naszym głównym produktem jest statystyczny silnik diagnostyczny. Silnik zbiera objawy, zadaje pytania diagnostyczne, a następnie podpowiada, jakie mogą być przyczyny naszego złego samopoczucia. Rozwiązanie korzysta z modelu probabilistycznego, który działa w oparciu o bazę wiedzy. Informacje w tej bazie są wprowadzane i weryfikowane przez lekarzy ekspertów. W kolejnym kroku stosujemy techniki machine learning, które stale podnoszą jakość bazy wiedzy.
Dostęp do silnika jest możliwy za pośrednictwem API. Klienci wykorzystują nasze API do budowy swoich własnych produktów. W ten sposób powstały np. aplikacje typu symptom checker oraz inteligentne formularze rejestracji dla pacjentów. Do tej pory, użytkownicy z całego świata wykonali ponad milion zapytań do API.
Symptomate również używa silnika diagnostycznego, a cała komunikacja z użytkownikiem odbywa się za pośrednictwem wiadomości tekstowych. Oto trzy spośród wyzwań, które napotkaliśmy podczas budowania chatbota.
1. Skalowalna architektura obsługująca wiadomości
W ostatnim czasie nastąpił zdecydowany wzrost zainteresowania botami. Można powiedzieć, że mamy do czynienia z nowym technologicznym trendem.
Rosnąca popularność botów utrudnia skuteczne prognozowanie ruchu, który będą generowali nasi użytkownicy. Teoretycznie, za pomocą takich platform jak Messenger, mamy dostęp do milionów odbiorców. Gwałtowny wzrost liczby użytkowników może nastąpić w dowolnym momencie, nawet jeśli dziś wydaje się to mało prawdopodobne. Gdy nasz chatbot jest niedostępny lub nie działa prawidłowo, użytkownicy mogą go zgłosić do operatora platformy. W takim wypadku grozi nam zamknięcie konta i dotkliwa utrata wiarygodności firmy.
Większość platform (w tym Messenger) wymaga wystawienia tzw. webhooka (sieciowego API). Platforma komunikuje się z webhookiem za każdym razem, gdy użytkownik pisze do bota. Obsługa wiadomości użytkownika polega na:
- interpretacji treści wiadomości (w odniesieniu do bieżącego stanu rozmowy),
- zmianie stanu rozmowy,
- wysłaniu odpowiedzi (choć nie zawsze).
Proces obsługi może wymagać kosztownych operacji. W naszym przypadku kosztowne okazały się wywołania API oraz usługa NLP (Natural Language Processing). Cykl opisany powyżej dobrze pasuje do wzorca nazywanego message broker. W tym modelu wiadomości użytkownika przechowujemy w kolejce komunikatów (message queue). Wiadomości z kolejki są przekazywane do procesów (workers), a te przetwarzają je dalej. Liczba procesów jest zmienna i zależy od obecnego zapotrzebowania.
1. Natychmiastowa obsługa zdarzeń. Serwer, który udostępnia webhook, powinien reagować jak najszybciej. Ten etap może sprowadzać się do przeniesienia wiadomości do kolejki, jednak jest bardzo ważny. Niektóre platformy nie tolerują opóźnień. Warto się zabezpieczyć, już na etapie projektu.
2. Stały proces przypisany do użytkownika. Użytkownik podczas trwania rozmowy powinien być obsługiwany przez ten sam proces. Taka implementacja gwarantuje obsługę wiadomości w kolejności, w jakiej zostały wysłane.
3. Load balancing. Kolejka zdarzeń powinna, w razie potrzeby, równoważyć liczbę użytkowników w procesach.
4. Propagacja. Powinniśmy przygotować się na sytuację, w której proces zakończy się wyjątkiem (szczególnie na etapie prototypowania). Kolejka musi być w stanie przenieść swoje zadania do innych procesów.
5. Pętla przetwarzania zdarzeń. Pętla, która przetwarza dane składa się z kilku kroków: pobrania wiadomości z kolejki, pobrania stanu rozmowy z danym użytkownikiem, obsługi wiadomości, zapisania zmienionego stanu i ewentualnej odpowiedzi.
6. Przechowywanie danych. Informacje o tym, w którym miejscu znajduje się rozmowa powinny być przechowywane w bazie danych. Dobra baza danych ma elastyczną strukturę i krótki czas dostępu (zapis i odczyt). Rozsądnym wyborem wydaje się baza typu NoSQL. Ze względu na prosty format danych wybraliśmy MongoDB.
Poddaliśmy analizie kilka pakietów implementujących kolejki. Pierwsze odkrycie: funkcja grupowania wiadomości (message groups) spełnia wymogi 2 i 3.
Zaskoczył nas również fakt, że najpopularniejsze pakiety (ActiveMQ i RabbitMQ) nie działają zgodnie z naszymi oczekiwaniami. Podczas testowania ActiveMQ nie udało się zmusić procesu kolejki do przekazywania użytkownika innemu procesowi. Sytuacja pojawiała się mimo tego, że w kolejkach nie występował stan równowagi. Naszym faworytem okazał się Apache Apollo. Przy minimalnej konfiguracji rozwiązanie spełnia wszystkie wymogi. Dociekliwym polecam przyjrzenie się burzliwej historii projektów związanych z obsługą kolejek.
2. Bot musi rozmawiać
Jeśli użytkownicy wolą klikać i przewijać, prawdopodobnie odwiedzą twoją responsywną stronę internetową. Jeśli wybrali Messengera – oczekują rozmowy. Zrób mały eksperyment. Wejdź na botlist.co, wybierz kategorię i rozpocznij rozmowę z losowo wybranymi botami. Jeśli nic się nie zmieniło, zobaczysz mnóstwo tabelek z przyciskami, źle wykadrowane zdjęcia itd. Wszystko w jednym malutkim oknie czatu.
Nie ma nic złego w korzystaniu z szablonów, które zawierają gotowe odpowiedzi. Takie rozwiązanie ma sens, gdy zadajemy proste pytania, chcemy nakierować użytkownika na trafne odpowiedzi i oczekujemy wybrania jednej z nich. W ten sposób unikamy wrażenia rozmowy z elektronicznym biurem obsługi klienta.
Przetwarzanie języka naturalnego
Jak wypłynąć na fali popularności chatbotów i przedstawić swój produkt jako inteligentny? Zastosuj choćby podstawowe techniki przetwarzania języka naturalnego (Natural Language Processing, NLP). Mimo że istnieją liczne badania i narzędzia związane z przetwarzaniem języka polskiego (por. CLIP), dzisiaj skupimy się wyłącznie na angielskim.
Użytkownicy mają pewne wyobrażenia na temat prowadzenia rozmów przez internet. Dotyczy to również rozmowy z botem, dlatego taka interakcja wymaga dobrego zaprojektowania. Warto przygotować możliwe przypadki użycia i prawdopodobne scenariusze rozmów. Spróbuj wypisać wszystkie możliwe intencje, które stoją za wiadomościami użytkowników. Zebrane w ten sposób intencje pozwolą ci lepiej spełnić oczekiwania użytkownika.
Zastanów się: o czym chce rozmawiać twój użytkownik? Co jest przedmiotem rozmowy? Czy ten przedmiot ma nazwę? Synonimy? Czy wystarczy wykryć frazy rzeczownikowe, czy sprawdzić również konstrukcje czasownikowe (boli mnie głowa)?
W naszym przypadku kluczowe okazało się rozumienie symptomów, które występują w tekście. Na rynku dostępne są wysokiej jakości narzędzia rozpoznające pojęcia kliniczne w tekście anglojęzycznym – np. Lexigram API. Opracowaliśmy jednak własne rozwiązanie, dostosowane do naszej bazy wiedzy i silnika diagnostycznego. Narzędzie jest dostępne jako endpoint w Infermedica API.
Język czatu
Język, którym posługują się użytkownicy chatów, pod wieloma względami odbiega od normy językowej. Szczególnie dotkliwe są literówki. Możemy udawać, że problem nie występuje, lub napisać własny korektor pisowni. Lepiej nie korzystać z gotowych korektorów dostępnych na zasadach open-source. Szybkość działania tych projektów może przyprawić o mdłości.
Przed użyciem każdego algorytmu lub implementacji warto przeprowadzić testy. Nie możesz sobie pozwolić na opóźnienia rzędu 200 ms na każde słowo użytkownika. Jeśli szukasz czegoś naprawdę szybkiego, polecam algorytm Symmetric Delete.
3. Nie unikniesz frustracji użytkowników
Wstępne testy pozbawiły nas złudzeń. Symptomate często nie rozumie wiadomości od użytkowników. Niestety, niewiele możemy z tym zrobić. Staramy się jednak przewidywać frustrację rozmówcy i łagodzić trudne sytuacje. Bot wysyła kontekstowe podpowiedzi i próbuje opisać jakich wiadomości się spodziewa. W wielu sytuacjach takie podejście pozwala zamienić kompletny brak zrozumienia na zrozumienie częściowe, co samo w sobie jest już sukcesem.
Skala problemu zależy od rozmiaru dziedziny. Jeśli bot wypisuje aktualne kursy walut, pozostaje mało miejsca na nieporozumienia. Naszą dziedziną są powszechne dolegliwości. Podczas rozmowy z użytkownikiem Symptomate rozpoznaje ponad 1400 symptomów oraz tysiące synonimów. Nadal jednak występują sytuacje, w których rozmówca podaje obserwacje, których nie ma w naszej bazie. Co do zasady jest to nieuniknione, bez względu na rozmiar bazy danych. Poza tym żaden system NLP nie jest doskonały, nasz również. Język pozwala na ogromną swobodę ekspresji. Część opisów znanych nam symptomów pozostanie niezrozumiana.
Analityka
Symptomate gromadzi podstawowe statystyki z każdej rozmowy (od momentu podania objawów do etapu przedstawienia prawdopodobnych diagnoz). Dane są anonimowe. Jedną ze zmiennych, którą śledzimy jest miara przewidywanej frustracji. Na podstawie tej zmiennej decydujemy, czy zboczyć ze standardowej ścieżki rozmowy. W takim przypadku bot wysyła kontekstowe wskazówki lub przyznaje się, że w tym momencie nie jest w stanie pomóc.
Częściowe zrozumienie
Zdarza się, że bot kompletnie nie rozumie opisu objawów. Pomocne stają się heurystyki. Gdy główny moduł NLP nic nie zrozumiał, próbujemy dopasowania heurystycznego. W tej sytuacji przyjmujemy (czasem błędne) założenie, że cała wiadomość użytkownika jest opisem dokładnie jednego objawu (główny moduł NLP może rozpoznać wiele). W tym celu stosujemy klasyczny model wektorowy. Działanie modelu polega na próbie dopasowania najbardziej podobnych fraz i zapytania rozmówcy, czy którąś z nich ma na myśli.
–
Jeśli chcesz się podzielić swoją opinią na temat budowania chatbotów lub masz pytania, napisz do mnie na [email protected].
Tekst ukazał się po raz pierwszy na blog.infermedica.com. Blog zawiera również inne artykuły związane ze sztuczną inteligencją, machine learning oraz NLP.
–
Dr inż. Adam Radziszewski
Data Scientist w Infermedica
Zajmuje się analizą dużych zbiorów danych, machine learning oraz przetwarzaniem języka naturalnego (NLP). Autor jednego z pierwszych medycznych chatbotów (Symptomate). Entuzjasta nowych technologii, praktyk, naukowiec. W wolnym czasie tworzy mroczną muzykę elektroniczną w zespole Orbicide i Uncarnate.