챗봇 슬롯 채우기(Slot-Filling)

대화는 어떤 목적을 이루기 위한 대화(TOD, Task Oriented Dialog)가 있고 특별한 목적 없이 자신의 생각을 자유롭게 이야기 하는 소통을 목적으로 하는 대화(Chit-Chat Dialog)가 있습니다.

목적이 있는 대화의 경우에는 대화의 특징에 따라서 n개의 대화턴(Turn)으로 구성된 대화의 묶음으로 나눌 수 있는데 그것을 태스크(Task)라고 할 수 있습니다. 그리고 각 태스크는 또 n개의 액티비티(Activity)로 나눌 수 있습니다. 그리고 각각의 액티비티에는 태스크의 원활한 진행을 위해서 반드시 입력되어야 할 필요한 정보들이 있습니다.

이처럼 특정한 태스크의 발화(Utterance)에서 반드시 필요한 의미 있는 정보들을 슬롯(Slot)이라고 하고 이 슬롯을 채우는 것을 슬롯 필링(Slot Filling)이라고 합니다.

https://d2.naver.com/helloworld/2110494

그리고 이 슬롯을 채우기 위해서 거듭해서 질문을 하게되는데 이러한 것을 Follow-Up Question이라고 합니다. 아래의 그림과 같이 좌석을 예약할 때에 기본적으로 필요한 정보들이 있고 이러한 정보들이 입력되지 않으면 시스템은 이용자에게 질문을 통해 해당 정보를 얻게 됩니다.

https://d2.naver.com/helloworld/2110494

이런 과정을 수행하기 위해서는 개체명인식(NEG, Named Entity Recognition) 작업이 필요합니다.
해당 작업은 사용자가 입력한 텍스트를 사전에 정의된 몇가지 단어들… 예를 들어서 메뉴명, 지역명, 호텔명 등에 태깅하는 작업을 의미하고 이것은 비슷한 말로 엔티티 태깅(Entity Tagging)이라고도 합니다.

여기서 중요한 것은 기존에 정의된 태그 목록이라는 것입니다. 태그 목록은 기존에 범용적으로 사용되는 것도 있고 대화가 진행되는 특정한 도메인에서 활용되는 것도 있습니다.

이처럼 사용자가 입력한 단어들이 기존에 정의된 개체명에 포함되어 있는지를 살펴보고 없다면 필요한 정보를 다시 요구하는 방식으로 요청 정보를 채우게됩니다.

다음에 구현한 예제는 이러한 과정을 간단히 작성한 내용입니다. 주문상황을 가정하고 챗봇을 통해서 주문을 받아보는 방식을 생각해보겠습니다.
먼저 아래와 같이 슬롯을 정의합니다.

#Intent Slot 구성
slot_entity = { "주문": {"메뉴":None, "장소":None, "날짜":None},
                "예약": {"장소":None, "날짜":None},
                "날씨": {"장소":None, "시간":None}
              }

사용자가 입력된 텍스트가 “주문 부탁해”입니다. 챗봇 시스템이 먼저 파악해야 할 것이 있다면 텍스트를 입력한 사람이 어떤 의도로 이런 텍스트를 입력했는지를 알아내는 것입니다.

간단히는 ‘주문’이라는 키워드를 확인해서 대화의 의도를 파악할 수 있고 몇가지 ‘주문’ 상황에서 쓸 수 있는 문장들을 입력하고 유사도 검사를 통해서도 이용자의 의도를 파악할 수 있습니다. 최근에는 딥러닝을 활용해서 해당 문장이 어떤 의도인지 알아내기도 합니다. 딥러닝(LSTM)을 활용한 문장 유사도를 찾는 것은 예제로 구현되어 있으니 참고하시기 바랍니다.

입력한 문장 ‘햄버거 주문할께요’라는 단어가 ‘주문’이라는 의도를 가지고 있다는 것을 파악한 다음에 ‘햄버거 주문할께요’라는 입력 문장을 분석해서 예약에 필요한 정보들을 담고 있는지 확인해야합니다. 그러기 위해서 형태소 분석(Morphology Analysis) 과정이 필요합니다.

input_txt = '햄버거 주문할께요'
intent_code = '주문'

from konlpy.tag import Kkma
kkma = Kkma()
morpheme = kkma.pos(input_txt)
print(input_txt,'\n',morpheme)
# [('햄버거', 'NNG'), ('주문', 'NNG'), ('하', 'XSV'), ('ㄹ게요', 'EFN')]

입력된 문장의 형태소 분석을 통해서 ‘햄버거’,’주문’이라는 개체명(명사)을 찾아내었습니다. 이제 다음으로는 이런 개체명이 사전에 정의해둔 개체명과 일치하는 내용을 찾는 과정을 수행합니다. 입력된 단어 중에서 ‘햄버거’란 단어는 이미 메뉴 아이템에 사전으로 등록했기 때문에 ‘햄버거’는 menu_item이라고 인식합니다.

# 개체명
menu_item = ['피자','햄버거','치킨','떡볶이']
loc_item = ['세종','대전','공주']
date_item = ['지금','내일','모래']

# 개체명 태깅
for pos_tag in morpheme:
    if (pos_tag[1] in ['NNG', 'NNP']): #명사, 영어만 사용
        if pos_tag[0] in menu_item: #메뉴 item 검색
            slot_value["메뉴"] = pos_tag[0] 
        elif pos_tag[0] in loc_item: #장소 item 검색
            slot_value["장소"] = pos_tag[0] 
        elif pos_tag[0] in date_item: #날짜 item 검색
            slot_value["날짜"] = pos_tag[0] 
print (slot_entity.get(intent_code))

입력된 문장을 분석해본 결과 주문에 필요한 나머지 정보들 즉, ‘주소’ 정보와 ‘시간’ 정보는 입력되지 않았습니다. 챗봇 시스템은 빠진 두개의 정보를 입력할 것을 요청합니다. 이것을 Follow-Up Question이라고 합니다.

if(None in slot_value.values()): #빈 Slot 출력
    key_values = ""
    for key in slot_value.keys():
        if(slot_value[key] is None):
            key_values = key_values + key + ","
    output_data = key_values[:-1] + '를 입력해주세요.'
else:
    output_data = "주문이 완료 되었습니다."
            
print (output_data)
#메뉴,장소,날짜를 입력해주세요.

이러한 방법으로 주문에 필요한 모든 정보가 입력되면 챗봇 시스템은 주문 정보를 기반으로 실제로 요청한 내용들을 주문하게됩니다.

참고로 본 글을 작성하기 위해서 잘 정리된 아래의 두개 글을 참고했습니다. 관심이 있으신 분은 아래의 글을 검색해보시기 바랍니다.

REF
[Naver] 챗봇을 위한 대화는 어떻게 디자인할까
[KAKAO] 카카오 미니의 슬롯 태깅

“챗봇 슬롯 채우기(Slot-Filling)”에 대한 한개의 댓글

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 항목은 *(으)로 표시합니다