Microsoft Bot Framework, poza Bot Connectorem dostarcza także całkiem rozbudowany system zarządzania przepływem rozmowy z botem wymodelowany podobnie do przepływu między oknami, znanego z WinForms lub WPFa.
Podstawowymi elementami tego rozwiązania są tworzone przez użytkownika klasy opisujące dialogi. Dialog można określić jako fragment rozmowy realizujący konkretny cel – przykładowo dialog może obsługiwać wyświetlanie przycisków z menu do wyboru dla użytkownika lub też zbierać informacje od użytkownika na dany temat. To od wizji dewelopera zależy ile rzeczy będzie obsługiwał pojedynczy dialog, ja natomiast radzę powtarzające się rzeczy (np. pobranie daty i czasu, ich walidacja itd.) wydzielać do poddialogów, dzięki czemu zachowujemy przejrzystość kodu.
Dialogi w wykonaniu Bot Framework mają kilka cech charakterystycznych:
- Każdy dialog musi być oznaczony atrybutem Serializable – Bot Framework automatycznie zapamiętuje nie tylko w którym dialogu jesteśmy (czyli cały dialog stack), ale także stan poszczególnych dialogów, włączając w to wszystkie properties oraz pola klasy implementującej dialog. O ile do prostych zastosowań jest to w miarę ok, o tyle na dłuższą metę rozwiązanie tego w ten sposób sprawia ogromy ból, zwłaszcza jeśli zależy nam na czystości kodu oraz stosowaniu dependency injection.
- Konsekwencją powyższego jest konieczność „hackowania” tego systemu poprzez użycie Service Locatora (a tego nie lubimy) w ramach metody oznaczonej atrybutem OnDeserialized, co ogólnie jest dość słabą opcją…
- Zapomnijcie także o lambdach, Action i kilku innych wygodnych rzeczach, które nie dają się łatwo serializować – użycie jakiegokolwiek mechanizmu tego typu wysypie cały dialog stack.
- Do dialogów dostarczany jest tzw. kontekst dialogu. Niestety ten kontekst też staje się bolesny przy dłuższej przygodzie z dialogami, gdyż jest to rodzaj „superobiektu”, który ma bardzo dużą odpowiedzialność i naprawdę ciężko testować dialogi właśnie z racji ich dużej zależności od dostarczanego obiektu kontekstu.
- Przepływ kontroli w ramach dialogu musi zawsze kończyć się wywołanie na obiekcie kontekstu jednej z trzech operacji: Call – wywołującej inny dialog, Done – kończący obecny dialog i przekazujący wynik do dialogu nadrzędnego lub Wait – który oczekuje na nastepną wiadomość od użytkownika.
- Powyższe oznacza w szczególności, że jeśli nie wywołacie jednej z tych trzech metod (np. w wyniku nieobsłużonego wyjątku) to… tak, dialog stack się sypie :P
- Wersjonowanie dialog stacka to kolejny słaby punkt tego rozwiązania. Dlaczego? Otóż jeśli Bot Framework nie jest w stanie poprawnie zdeserializować dialog stacka (serializacja binarna wbudowana w .NET z wszystkimi jej wadami i zaletami) to… resetuje go powodując tym samym utratę stanu poszczególnych properties lub pól klasy. Co prowadzi nas do wniosku, żeby lepiej nie bazować na tym automatycznym mechanizmie i samemu zająć się zapisem i odczytem stanu w ramach danego dialogu, a więc domyślną serializację sprowadzamy do bycia wyłącznie wadą tego rozwiązania.
Czy więc dialogów da się używać? Tak, da się. Czy to jest przyjemne? No cóż… jak dla mnie nie bardzo, ale to raczej kwestia tego, że lubię tworzyć kompaktowy kod, który można ponownie używać w wielu miejscach. System dialogów Bot Buildera niestety w wielu wypadkach nie pozwala na użycie pełni możliwości C#.
Jakie mamy alternatywy? O tym w przyszłych wpisach :)
W następnych częściach…
… pokażę jak w praktyce używać systemu dialogów oraz jak zrobić te kilka hacków, które pozwalają go użyć zgodnie „ze sztuką”.
A później przejdziemy do sztucznej inteligencji w zastosowaniach związanych z chatbotami :)
Aby nie przegapić kolejnych wpisów zapraszam do śledzenia tego bloga, czy to przez kanał RSS, czy też poprzez stronę na Facebooku.
Dodaj komentarz