Watson으로 쉽게 만드는 카카오톡 ChatBot

이 포스팅을 시작으로 Watson Conversation과 카카오톡 api를 활용하여 ChatBot을 제작해 볼 예정입니다.

이 포스팅 시리즈는 일련의 Recipe으로 순서대로 따라하면 ChatBot을 개발할 수 있습니다.

만들어질 ChatBot은 “회의실 관리자”로 카카오톡 대화를 통해 회의실을 예약/취소/예약 알림 등의 기능을 수행할 수 있습니다.

## 이 포스팅과 관련된 글

## 이 포스팅과 연결된 글 목록

1. Watson Conversation 서비스로 대화 서비스 만들기

첫번 째 단계로 Watson Conversation 서비스를 활용하여 대화 서비스를 구축합니다. Watson Conversation으로 만드는 대화 서비스는 향후 Watson Conversation API를 통해 Application에서 RESTful API를 통해 사용 가능합니다.

1-1 Watson Conversation 서비스 개요

IBM Watson™ Conversation 서비스는 자연어를 이해하고 기계 학습(Machine learning)을 사용하여 고객과 소통할 때 사람이 하는 대화 방식으로 응답하는 어플리케이션을 만들 수 있도록 해줍니다. 예를 들어 아래와 같은 아키텍처의 어플리케이션을 설계할 수 있습니다.

conversation_arch_overview

  • 사용자는 여러 매체를 통해 어플리케이션과 소통할 수 있습니다. 이 포스팅에서는 웹 어플리케이션과 카카오톡이 사용자와 어플리케이션 사이의 매개체가 될 것입니다. 하지만 이 포스팅을 활용하여 Slack, 페이스북 메신저, Twilio 문자 메세징 서비스 등 많은 인터페이스를 연동할 수 있습니다. Watson STT(Speech To Text)와 TTS(Text To Speech) 추가로 활용하여 문자 대화가 아닌 음성 대화로 만들 수도 있습니다.
  • 어플리케이션은 사용자의 입력과 Watson Conversation Service 사이의 매개체가 됩니다. 카카오톡으로부터 input을 받아 Watson Conversation Service에 전달하고 Watson Conversation Service가 주는 답변을 카카오톡으로 다시 전달하는 역할을 하게 됩니다.
  • 어플리케이션은 또한 Back-end 시스템과 연동되어 필요한 경우 액션을 취해야 합니다. 이 예제에서는 회의실 예약 시스템과 연동하여 실제로 회의실을 예약하고 관리하게 될 것입니다.
  • 지원되는 언어 : 현재 지원되는 언어는 Brazilian Portuguese, English, French, Italian, Spanish, German, Traditional Chinese, Simplified Chinese, Dutch 입니다. 향후 한국어도 추가될 예정입니다.

1-2 Watson Conversation 서비스 사용 시작하기

Watson Conversation Service는 Bluemix를 통해 사용할 수 있습니다. Bluemix에 로그인 한 후 Catalog에서 Conversation 서비스를 작성합니다. 왼쪽 카테고리에서 Watson을 선택하면 서비스를 더 빨리 찾을 수 있습니다.

bluemix-catalog-watson-conversation

1-3 Watson Conversation 서비스로 대화 서비스 만들기

Watson Conversation 서비스는 별도의 툴을 제공합니다. 블루믹스 대쉬보드에서 위 단계에서 생성한 서비스를 클릭한 후 Launch tool 버튼을 클릭하여 툴로 이동합니다.

bluemix-service-dashboard

1) Workspace 만들기

Workspace는 어플리케이션이 사용하는 단위입니다. 하나의 Watson Conversation Service 인스턴스 안에 여러 Workspace를 생성할 수 있습니다.
Workspace는 다음과 같은 타입의 artifact로 이루어집니다.

  • Intent : Intent는 사용자가 하려는 말의 목적을 의미합니다. 따라서 우리는 서비스에서 제공하고자 하는 요청의 모든 타입을 Intent로 정의하게 됩니다. 예를들어 회의실 예약은 하나의 Intent가 될 수 있습니다. Watson Conversation에서 Intent를 지칭할 때에는 #을 prefix로 사용합니다. Intent를 정의할 때에는 사용자가 이 Intent를 목적으로 말을 할 때 사용할 가능성이 있는 최대한 많은 예시를 제공하는 것이 좋습니다. 예를 들어 회의실 예약이라는 Intent에는 “회의실 예약해주세요.”, “지금 빈 회의실이 있나요?” 등의 예시를 제공할 수 있습니다.
  • Entity : Entity는 Intent와 관련된 용어 또는 목적어를 의미합니다. Entity는 Intent에 대해 구체적인 문맥(Context)을 제공하는데에 쓰입니다. 예를 들어 회의실 예약이라는 Intent를 사용하기 위해서는 회의실 이라는 Entity를 정의할 수 있습니다. 회의실 Entity에는 실제로 보유중인 회의실 이름을 담으면 됩니다. 이렇게 Entity를 정의하면 사용자가 “진달래 회의실 지금 비어 있어?” 라고 했을 때 회의실 Entity의 값이 “진달래”로 리턴되게 됩니다.
  • Dialog : Dialog는 대화의 흐름을 분기하는 것으로 어플리케이션이 정의된 Intent와 Entity를 인식했을 때 어떠한 응답을 할 것인지를 정의합니다. 다시 말하면 사용자가 대화를 시도했을 때 이 대화의 Intent와 Entity를 파악한 후 어떠한 응답을 할 것인지를 정의합니다.

아래는 이 포스팅의 1-3에서 오픈한 Watson Conversation 툴의 첫번째 화면입니다.

conversation-tool

Create 버튼을 클릭하여 Workspace를 생성합니다. 이름을 입력하고 언어를 선택합니다. 추후 한국어가 지원될 예정이지만 현재에는 영어를 사용합니다.

conversation-create-workspace

Workspace를 생성하면 바로 생성한 workspace로 이동됩니다. 다시 돌아가려면 왼쪽 상단의 메뉴 아이콘을 클릭하여 나오는 메뉴에서 Back to workspaces 버튼을 누르면 됩니다.

2) Intent 만들기

Workspace의 모습입니다. 상단 메뉴를 보면 Intents, Entities, Dialog 3개의 메뉴가 있습니다. 위에서 설명한 것들을 이 3개의 메뉴를 통해서 할 수 있습니다.

conversation-create-intent

먼저 Intent를 생성해 봅니다. Create new 버튼을 클릭합니다.
첫번째 단계로 생성할 Intent는 2개입니다. 사용자의 인사를 받아들이는 #Greeting과 예약 요청의 시작을 받아들이는 #Reservation을 생성할 것입니다.
먼저 #Greeting을 아래 화면처럼 생성합니다.

conversation-intent-greeting

#Reservation을 생성합니다.

conversation-intent-reservation

두 Intent를 모두 생성하면 아래 화면과 비슷한 결과를 볼 수 있습니다.

conversation-intent-result

마지막으로 긍정적인 대답에 대한 Intent를 추가하겠습니다. Intent의 이름은 PositiveAnswer로 하고 값은 아래의 표를 참조하여 추가합니다. 이 Intent는 사용자의 대답에서 긍정의 의미가 있는 경우 추출하기 위함입니다.

예제
Absolutely
Of course
OK
Sure
Why not
Y
Yep
Yes

3) Entity 만들기

상단 메뉴에서 Entities를 클릭합니다.

conversation-entity-create

Entity는 내가 만드는 My entities와 시스템에 의해 만들어져 있는 System entities가 있습니다. 우리는 이 두가지 타입의 Entity를 모두 사용할 예정입니다.

먼저 회의실 엔티티를 생성합니다. Create new 버튼을 클릭하여 아래처럼 회의실 이름을 담은 Entity를 생성합니다. Value에는 각 시스템에서 사용할 회의실 이름, 동의어에는 사용자가 특정 회의실을 부를 때 사용할 수 있는 모든 단어를 추가해 줍니다.

conversation-entity-room

다음으로 System entities를 사용하도록 설정합니다. System entities는 날짜, 숫자, 통화 등을 핸들링 할때 매우 유용합니다. 회의실 예약시에는 날짜와 시간이 필요합니다. 따라서 이 두 Entity를 Enable합니다.

conversation-entity-system

4) Dialog 만들기

상위 메뉴에서 Dialog를 클릭하고 Create 버튼을 클릭합니다. 이 단계에서는 사용자와의 대화에서 Watson이 어떻게 대답할 것인지를 결정하고 분기하게 됩니다. Dialog는 Intent와 Entity를 사용하여 사용자 인풋을 분석하며 정보를 수집하고 유용한 대답을 하게 만듭니다. Dialog는 트리 형태를 가지는데 각 인텐트를 최상위 노드로 놓고 가지를 치며 적절한 대답을 할 수 있도록 유도하면 됩니다. 이 Recipe에서는 아래 그림처럼 4개의 최상위 노드를 만들 것이며 Reservation 노드가 가장 중요한 비즈니스 역할을 할 것입니다.

conversation-dialog-intents

노드를 생성하기 앞서 Dialog에서 사용하는 용어를 설명드리겠습니다.

  • 노드(Node) : 노드는 Dialog를 구성하는 요소입니다. 사용자와의 대화에서 1번의 상호작용을 의미합니다.
  • 컨디션(Condition) : 노드를 구성하는 요소로 사용자의 인풋 등을 바탕으로 조건에 맞는 경우 해당 내용을 응답합니다.
  • 응답(Response) : 노드를 구성하는 요소로 사용자의 인풋이 컨디션에 매치되면 활성화됩니다. 간단한 문자열을 리턴할 수도 있고 좀 더 복잡한 프로세스를 실행시킬 수도 있습니다.
  • 브랜치(Branch) : 사용자와의 대화를 의미한 일련의 Dialog Node를 브랜치라고 합니다. 사용자의 인풋이 기본 노드의 컨디션에 맞을 때 브랜치가 사용되게 됩니다.
  • 턴(Turn) : 사용자가 인풋을 하고 이에 응답하는 하나의 사이클을 턴이라고 합니다. 브랜치는 하나 이상의 턴을 가질 수 있습니다.
  • 기본 노드(Base node) : 브랜치의 최 상위 노드(첫 번째 노드)를 기본 노드라고 합니다.
  • 자식 노드(Child node) : 기본 노드가 아닌 노드를 자식 노드라고 합니다. 자식 노드는 이전 노드가 최종 응답을 주기 위해 더 많은 사용자 인풋 또는 프로세스를 필요로 할 때 사용됩니다.
  • 동기 노드 또는 자매 노드(Peer node or Sibling node) : 다른 노드의 대안책이 되는 노드입니다. 모든 기본 노드는 다른 기본 노드의 동기 노드입니다.
  • 노드 메뉴(Node menu) : 노드를 구성하느 요소로 노드를 지우거나 기능을 추가할 수 있도록 해줍니다.

노드를 작성할 때에는 SpEL(Spring Expression Language)을 사용합니다. 자세한 사용법은 Watson Conversation에서 사용하는 Expression Language를 참조하세요.

노드를 작성하는 법을 간단하게 설명하겠습니다.

다이얼로그 작성 화면에서 노드를 클릭하면 해당 노드의 우측과 아래측에 +버튼이 생깁니다. 이 버튼을 클릭하여 동기 노드 또는 자식 노드를 생성할 수 있습니다.
conversation-node-click

노드를 더블 클릭하면 해당 노드를 수정할 수 있습니다. Triggered by 필드는 이 노드를 사용할지 결정하는 Condition의 역할을 합니다. Fullfill with a response 필드는 Response를 작성하기 위한 필드입니다. 우측에 위치한 Jump to…버튼은 사용자의 인풋 없이도 다른 노드로 이동하기 위해 사용합니다. Response에 response condition을 추가하여 노드 안에서도 적절하게 응답을 분기할 수 있습니다. Response의 우측에 위치한 {…} 버튼을 클릭하면 Text 대신 응답할 Json을 직접 수정할 수 있습니다.

conversation-node-doubleclick

노드 작성법을 확인한 후 4개의 최상위 노드를 아래 정보를 참조하여 작성하십시오.

Index Triggered by Response Condition Response Jump to
1 conversation_start Welcome!
2 #Greeting Hi, what can I do for you?
Remove response variation
Hey, what can I do for you?
3 #Reservation
{
  "context": {
    "dates": null,
    "rooms": null,
    "times": null
  },
  "output": {}
}
    
3-1 Condition
4 anything_else I’m sorry, I don’t understand. Please try again.

#Reservation 노드에 아래 정보를 바탕으로 하위노드를 추가하십시오.

Index Triggered by Response Condition Response Jump to
3-1 NOT $user
{
  "context": {
    "user": {
      "id": "hjjo\\@kr.ibm.com",
      "name": "HyeonJeong Jo",
      "email": "hjjo\\@kr.ibm.com",
      "phone": "01031229436"
    }
  },
  "output": {}
}
    
3-2 Condition
3-2 $user
{
  "context": {
    "dates": "< ? @sys-date?:$dates ?>",
    "rooms": "< ? @Room?:$rooms ?>",
    "times": "< ? @sys-time?:$times ?>"
  },
  "output": {}
}
    
3-2-1 Condition
3-2-1 NOT $dates
{
  "context": {
    "repeat": 1
  },
  "output": {
    "text": {
      "values": [
        "When do you want to have a meeting?"
      ],
      "selection_policy": "sequential"
    }
  }
}
    
3-2-1-1 @sys-date 3-2 Condition
3-2-1-2 true I’m sorry. Please tell me the dates that you want to book a room. For example, you can say in format “mm/dd/yyyy”
3-2-1-2-1 @sys-date 3-2 Condition
3-2-1-2-2 $repeat < 3
{
  "context": {
    "repeat": "< ? $repeat + 1 ?>"
  },
  "output": {}
}
    
3-2-1-2 Condition
3-2-1-2-3 true I’m sorry. I can’t understand you. Please start again.
3-2-2 NOT $times
{
  "context": {
    "repeat": 1
  },
  "output": {
    "text": {
      "values": [
        "What time do you prefer?"
      ],
      "selection_policy": "sequential"
    }
  }
}
    
3-2-2-1 @sys-time 3-2 Condition
3-2-2-2 true I’m sorry. Please tell me the times. You can tell me like this. “From 13:00 To 14:00”
3-2-2-2-1 @sys-time 3-2 Condition
3-2-2-2-2 $repeat < 3
{
  "context": {
    "repeat": "< ? $repeat + 1 ?>"
  },
  "output": {}
}
    
3-2-2-2 Condition
3-2-2-2-3 true I’m sorry. I can’t understand you. Please start again.
3-2-3 true
{
  "context": {
    "action": {
      "command": "check-availability",
      "dates": "$dates",
      "times": "$times"
    }
  },
  "output": {
    "text": {
      "values": [
        "$user.name, OK I will check the availabilty of room. $dates, $times, $rooms"
      ],
      "selection_policy": "sequential"
    }
  }
}
    
3-2-3-1 #PositiveAnswer
{
  "context": {
    "action": {
      "dates": "$dates",
      "times": "$times",
      "command": "confirm-reservation"
    }
  },
  "output": {
    "text": {
      "values": [
        "OK. < ? context.room ?> at < ? context.times.get(0).value ?>, < ? context.dates ?> is reserved for you."
      ],
      "selection_policy": "sequential"
    }
  }
}
    
3-2-3-2 true
{
  "context": {
    "action": null
  },
  "output": {
    "text": {
      "values": [
        "Canceled. please start again."
      ],
      "selection_policy": "sequential"
    }
  }
}
    
3-3 true I’m sorry. You’re not a registered user in our system.

Watson Conversation에서 #, $, @은 각각 Intent, Context, Entity를 지칭하는 Short Expression 입니다. 따라서, 해당 문자의 String값을 사용하고 싶다면 Escape를 위해 \\를 사용합니다.

5) Workspace Import 하기

위의 스텝을 통해 완성된 Workspace 또는 직접 제작한 Workspace를 그대로 사용하고 싶다면 이 단계는 스킵해도 됩니다.

링크에서 training폴더 아래 있는 workspace-tutorial1.json 파일을 다운로드 합니다.

Worspace 화면에서 Create 버튼 우측에 있는 Import 아이콘을 클릭합니다.
conversation-import

위에서 다운로드한 파일을 선택하면 자동으로 Workspace가 생성됩니다.

1-4 내가 만든 서비스 테스트 해보기

상단 우측에 있는 메세지 아이콘을 클릭하면 지금까지 만든 다이얼로그를 테스트할 수 있습니다.
conversation-try-icon

아래처럼 회의실을 예약하는 대화를 테스트하십시오.
conversation-try-test

이어지는 단계는

[Watson으로 쉽게 만드는 카카오톡 ChatBot] 2. 내가 만든 채팅 서비스를 어플리케이션에서 사용하기

입니다.