[Microsoft Bot Framework] 상태저장을 위한 Bot State Service

우리가 카카오톡과 같은 메신저를 사용하다 보면 상대방의 질문에 즉시 답하지 못하고 몇 시간이 지난 후에 답을 주는 경우가 있다. 그렇다고 마지막 대화 내용을 놓치지 않고 답을 해줄 수 있다.  Bot 서비스도 역시 Bot이 사용자에게 질문을 던진다면 그 상태를 계속 유지해 줘야한다.

이런 상태 정보를 분리되고 공유된 공간이 아닌 메모리등의 로컬 자원에 의지를 하면 서비스를 확장하는데 문제가 생긴다. 즉, Bot도 기본적으로는 웹 서비스로 구현되기 때문에 서비스 확장에 대비해서 Stateless 로 구현되어야 한다. Microsoft Bot Framework는 이런 상태를 저장하는 공간을 Bot State Service로 제공한다.

State 저장소를 구분하기 위한 기본 정보

사용자와 Bot간의 메시지는 Activity라고 부르는데(Message 외에도 여러 타입이 있다) 다음과 같은 상태정보와 함께 움직인다. 이 값을 이용해서 특정 대화, 특정 사용자, 특정 대화에서 특정 사용자를 구분해 낼 수 있다. 이 3가지를 이용해서 각 Context에 맞는 데이터 저장소를 만들어서 저장 할 수 있다.

  • From: 어떤 채널(Skrype같은)에서 특정 사용자 아이디. 사용자 단위의 데이터를 저장 할 때.
  • Conversation: 특정 대화를 구분하는 ID. 대화에는 여러 User가 포함되어 있을 수 있다. 모든 사용자가 같이 공유할 데이터.
  • From + Conversation : 특정 대화에서 특정 사용자를 위한 저장공간 구분.

State 메서드

이 3가지 구분에 의해서 State를 저장하고 가져오는 State 메서드도 3가지로 구분이 된다. 저장되는 데이터는 32 kbyte 보다 작아야 한다.

  • 데이터 가져오기
    • GetUserData()
    • GetConversationData()
    • GetPrivateConversationData()
  • 데이터 저장
    • SetUserData()
    • SetConversationData()
    • SetPrivateConversationData()

IDialogContext.CoversationData

Bot State Service에 설명되어 있는 Bot State Service의 State Client 보다 IDialogContext 의 헬퍼 프로퍼티를 사용하면 편리하다.

IDialog를 사용하면 항상 IDialogContext가 따라다니는데 CoversationData, PrivateConversationData, UserData 이렇게 3개의 속성을 제공한다. 이 3개 속성에 구현된 IBotDataBag 메서드를 사용하면 쉽게 State를 관리할 수 있다.

[Serializable]
public class Stage2Dialog : IDialog<string>
{
   public async Task StartAsync(IDialogContext context)
   {
        // get state 
        KetBotState state = null;
        context.ConversationData.TryGetValue("KetBotState", out state);
        if (KetBotState == null) return;

        // save state
        context.ConversationData.SetValue("KetBotState", state);
   }
}

예제로서 PINKET Bot 에서는 3가지의 선택지를 사용자에게 물어보고 최종 질문을 찾는 과정에서 3가지 질문의 답변을 State에 저장하면서 대화가 진행되다가 최종 질문이 확인되면 3가지 질문에 대한 답을 조합해서 최종 답변을 찾아 사용자에게 전달한다.