두번째 포스트까지는 기본 챗봇을 만들 수 있는 방법을 알려드렸습니다.
이번 포스트는 두번째 포스트를 기반으로 챗봇을 조금이나마 한단계 업그레이드 할 수 있는 단계로
반드시, 따라하지 않으셔도 됩니다.
챗봇에서는 slot filling(슬롯 채우기)라는 기능이 있습니다. 슬롯 채우기는 몇개의 정보를 알아내어야 챗봇이 답을 줄 수 있을 때, 그 몇개의 정보(slot)들을 다 채워 넣는 것(filling)으로 모든 슬롯이 다 채워질때까지 질문을 하는 것입니다
챗봇은 슬롯에 필요한 정보들을 다 채우면 사용자가 원하는 정보를 출력해 줄수 있습니다.
rasa 에는 3가지 정도의 슬롯 필링이 있다고 알고 있는데요
오늘은 그 중 하나인 action.py 파일을 활용하여 슬롯 채우기를 실행 할 수 있는 방법을 하려고 합니다.
굳이 이 방법을 사용하지 않고 {---}(---) 방법을 사용하여 간단하게 슬롯 채우기는 할 수 있는 방법이 있지만,
그것은 단순히 입력한 단어를 채워서 보여주는 것에 지나지 않기에
사용자가 원하는 정보를 출력하지 않는다는 점에 있어서 제대로된 슬롯 채우기가 아니라는 생각에 구현하지는 않았습니다.
RASA 챗봇은 action server를 통해 actions 파일에 작성한 코드를 바탕으로 유저들에게 필요한 정보를 취할 때까지 답변을 요청하고 그 정보를 취하면, 사용자가 원하는 정보를 출력해줍니다.
위 이미지는 실제로 RASA 액션 서버가 돌아가는 과정인데요. 이 액션 서버를 통해 RASA 챗봇은 로컬 서버와 통신을 하며 action 서버에 있는 정보를 바탕으로 슬롯 채우기를 실시하는 것입니다.
하지만, 개인적으로 이 구조를 이해하고 어느정도 거의 완벽히 구현하는데 약 1주일 정도의 시간이 걸렷네요...
actions 파일을 완벽하게 이해하기 위해서는 아래의 링크를 참고하여 슬롯 채우기 관련 코드를 작성해주시면 돼요!
https://rasa.com/docs/rasa/core/forms/
다행히도 RASA 챗봇 개발 버전은 프레임 워크 기반으로 코드가 구성이 되어있기 때문에, RASA 홈페이지와 깃헙(github)에 공유가 되어있는 코드들을 잘 비교해가면서 천천히 코드를 치다보면 쉽게 하실 수 있을거에요 코드는 아래 링크!
https://github.com/RasaHQ/rasa-demo/blob/master/demo/actions.py
우선, actions.py 파일을 열어서 코드를 칩니다.
자세한 내용은 아래 코드블럭 내에 기록이 되어 있으므로, 코드 블록 내에 설명을 참고해주시면 될것 같아요
## 아래 함수들을 import 해줍니다.
## 해당 함수들은 rasa 에서 챗봇을 구동하는데 필수적이라고 생각하는 함수들을 넣어둔 것이며
## 어떤 기능을 구현하는지에 따라서 필요한 함수들을 기입하고 구현해주시면됩니다.
## 초기 생성 파일들을 열어보시면 필요한 함수들이 주석처리(#) 가 되어 있습니다.
from rasa_sdk.forms import FormAction
from rasa_sdk import Action, Tracker
from typing import Any, Dict, List, Text, Union, Optional
from rasa_sdk.executor import CollectingDispatcher
import logging
import json
from rasa_sdk.events import (SlotSet,UserUtteranceReverted,ConversationPaused,EventType,ActionExecuted,UserUttered)
logger = logging.getLogger(__name__)
## 우선 클래스를 만들어 줍니다
class SalesForm(FormAction):
"""Collects sales information and adds it to the spreadsheet"""
# 그리고 도메인에서 form 칸에 기입할 해당 form 의 이름을 정해줍니다.
# 참고로 ->, Dict, List[] 같은 것들은 typing 함수로 인해 사용할 수 있는 것입니다.
# 파이썬에서는 자바의 특징을 빌려와 함수가 특정 형식으로 동작되다는 것을 미리 선언해주는
# 함수입니다.
def name(self) -> Text:
return "sales_form"
# @ 는 파이썬의 데코레이터(?) 으로 위에 작성한 name 함수를 끌어와 사용하겠다는 표시입니다.
@staticmethod
# 슬롯 채우기를 하는데 필요한 엔티티 그룹을 적어줍니다.
def required_slots(tracker) -> List[Text]:
return["job_function","use_case","budget","person_name","company","business_email"]
# 이제 실제로 슬롯 채우기를 하기 위해 맵핑 함수를 작성해주는 부분입니다.
# action 파일은 민감한 부부임으로 조심해서 작성해주어야 하는 부분입니다.
def slot_mappings(self) -> Dict[Text, Union[Dict, List[Dict]]]:
'''A dictionary to map required slots to
- an extracted entity
- intent : value pairs
- a whloe message
or a list of them, where a first match will be picked'''
# 이부분에서는 맵핑을 할때 어떤 엔티티를 참고할지를 정해주는 부분인데요
# from_entity는 인텐트 내 엔티티 그룹이 단어로 되어있을 사용해주는 부분
# from_text는 인텐트 내 엔티티 그룹이 문장 내에 있을때 사용해주는 부분 입니다.
return {
"job_function": self.from_entity(entity="job_function"),
"use_case": [self.from_entity(entity="use_case"),
self.from_text(intent='inform')],
"budget": self.from_entity(entity="budget"),
"person_name": self.from_entity(entity="person_name"),
"company": [self.from_entity(entity="company"),
self.from_text(intent="inform")],
"business_email": self.from_entity(entity="business_email")}
# 이 부분은 원하는 정보가 안들어왔을 때, 챗봇이 답을 요청하기 위해
# 어떤 것을 표시해줄 지 결정해주는 부분입니다.
# 제일 중요한 것이 메일이기에 메일을 설정해주었지만, 한번 설정하면 다른 것들이
# 채워질때까지 질문을 합니다
# 이 부분에 대해서는 저도 아직 이해가 미약한 편이라, 만약에 틀린점이 있다면
# 댓글로 부탁드릴게요
def validate_business_email(self, value, dispatcher, tracker, domain) -> Dict[Text, Any]:
"""Check to see if an email entity was actually picked up by duckling."""
if any(tracker.get_latest_entity_values("business_email")):
# entity was picked up, validate slot
return {"business_email": value}
else:
# no entity was picked up, we want to ask again
dispatcher.utter_message(template="utter_ask_business_email")
return {"business_email": None}
# 이 부분은 실제로 슬롯 채우기를 마쳤을 때 어떤 아웃풋을 내놓을지 설정하는 구간입니다.
# 이부분에 사용자가 출력하고자 하는 메시지를 적어놓으면 그에 맞게 출력이 됩니다.
def submit(self,dispatcher: CollectingDispatcher,tracker: Tracker,domain: Dict[Text, Any]) -> List[Dict]:
dispatcher.utter_message("Thanks for getting in touch, we'll contact you soon")
return []
그 다음, 도메인 파일 내에 slots, form, 어떤 엔티티들이 들어가는지 설정해주고,
intent 와 response부분에 사용할 인텐트와 슬롯 채우기 완료를 위해 챗봇이 정보를 요청할때 어떤 말을 할지 기입해줍니다.
그 다음에는, NLU 파일에 들어가 inform 이라는 인텐트에 들어갈 엔티티들을 작성해줍니다
위에 [ -- ]( --) 는 []는 엔티티들이며 ( )는 []의 엔티티들이 어떤 그룹에 속하는지를 표시해주는 것입니다. 위 코드에서 slot mapping 함수에 기록한 엔티티들은 ( ) 안의 엔티티들을 모두 포괄하는 그룹을 나타내는 것입니다.
그 후에는 Stories 파일에 해당 부분을 추가할 수 있도록 설정해줍니다.
그리고, Config 파일에 core 에서 처리할 때, 어떤 방식으로 처리할 지 설정합니다.
슬롯 채우기를 위해 필요한 policy 를 설정해줍니다.
그 다음, Endpoint 파일 을 열어서 action을 운용할 서버를 엽니다.
주석(#) 처리가 되어 있으므로 걸려있는 주석(#)를 그냥 풀어주시면 됩니다.
CMD 창을 열어 프로젝트가 설치되어있는 경로로 들어가 rasa run actions 명령어를 실행해 action 서버를 실행시킵니다.
서버를 구동하는데 이상이 없으면 위와 같은상태로 서버가 정상적으로 오픈이 됩니다.
그 후, rasa train 을 한 후 shell 을 열고 챗봇이 잘 작동이 되는지 확인합니다.
개인적으로 이 부분이 rasa 챗봇을 구동하는 데 있어서 가장 어려운 부분이라고 생각합니다.
그리고 actions 파일이 민감한 파일이다보니 코드가 조금만 어긋나도 에러가 잘 나고는 합니다..
저도 이부분을 해결하느냐고 많은 시간을 사용했던 것 같은데요 ㅠㅠㅠ
일부 에러는 제 블로그에 에러칸에 가시면 해결 할 수 있지만 그 외 발생하는 많은 에러들은 rasa cmd 창에 뜨는 에러 메시지를 잘 체크하고 구글링 또는 rasa forum 을 통해 검색해서 해결하시는 것이 가장 좋은 방법입니다
rasa 포룸 링크는 아래 내용을 참고해주세요
여기까지가 Rasa 를 활용한 챗봇을 구현하는 방법이었습니다.
제가 작성한 코드는 깃헙에 올린 후에 링크를 공유할 수 있도록 할게요!
그 외에도 더 이어지는 과정이 있지만, 챗봇을 구현하는데 있어서는 크게 중요하지 않은 부분이라고
생각하여 따로 기록하지는 않았습니다!
이로써 챗봇 구현하는 프로젝트는 마치도록 하겠습니다.
'데이터 엔지니어링 프로젝트 및 인강 > 2. RASA chatbot Project' 카테고리의 다른 글
RASA 오픈소스 를 통해 간단한 챗봇 구축하고 훈련하기 03 (0) | 2020.03.06 |
---|---|
RASA 오픈소스 를 통해 간단한 챗봇 구축하고 훈련하기 02 (0) | 2020.03.06 |
RASA 오픈소스 를 통해 간단한 챗봇 구축하고 훈련하기 01 (0) | 2020.03.04 |
화장품 챗봇 설계 - 프로젝트 챗봇 시나리오 설계 (0) | 2020.02.17 |
챗봇에 대한 간단한 개념 등 정리 - 프로젝트 전 사전 스터디4 (0) | 2020.02.14 |