[NLP]如何打造一个Chatbot

134 阅读3分钟

AB,早上好,吃早饭没!

B:早!刚吃!

A:周末过得如何?

B:还不错,去了深圳湾骑单车。你呢?

A:我比较宅,就在家里宅着。

B:哈哈,宅着也挺好,出门都是看人的。

A:哈哈,我上班去了。

B:恩,好的,再见。

A:再见



上述模拟了一个简单的会话场景,当然我们需要实现的打招呼机器人并没有那么复杂,如果真要实现上述对话,那么涉及的技术将远远不是本文就能介绍完的。

我们可以抽象一下上述对话,上述对话其实就只有3个动作:打招呼、闲聊和再见。

这3个动作在自然语言处理中成为‘意图(intent)’。意图往往表示着将要实行某一系列的行为。在这里我们定义3个意图:greet,chat,goodbye。

虽然有了意图,那我们又该如何判断是那个意图呢?这里我们直接通过关键字是判别,比如当提到‘早’的时候往往就意味着是在打招呼(greet),而提到‘再见’就显然表示是再见(goodbye)了,而除此之外的,我们都归结为闲聊(chat)。

意图识别的代码如下:


if '早' in message:

    intent='greet'

elif '再见' in message:

    intent='goodbye'

else:

    intent='chat'

有了意图,就可以对意图作出相应的反馈策略了。


greet:

  '早上好'

goodbye:

  '再见'

chat:

   ‘听起来很有趣的样子’



好了,到这里我们想要打造的聊天机器人的雏形就出来了。首先接收用户的输入,然后根据用户的输入判定意图,之后根据相应的意图生成对应的回答。这样就完成了一次会话过程。伪代码可以表示如下:


input_string=""#输入



intent_object=intent(input_string)#意图识别



response=policy(intent_object)#回复生成



print(response)#返回用户



chatbot开发

理清楚了具体的对话流程,下面就可以开始着手对我们的聊天机器人进行开发了。这里我们用到的rasa框架,rasa中用领域(domain)对会话进行区分,每一个领域下面有不同的意图,意图是由实体进行区分的,每一个意图对应着一个会话动作。

安装:


pip install rasa_core

git clone https://github.com/RasaHQ/rasa_core.git

cd rasa_core

pip install -r requirements.txt

python setup.py install

在完成安装之后可以运行helloworld示例来检验是否正常安装成功:


python examples/hello_world/run.py

Bot loaded. Type hello and press enter :

hello

hey there!

当‘hey there!’的回复之后就是安装成功了。安装成功之后就利用hello_world示例项目实现上文提到的打招呼机器人。

定义领域、意图和动作


#创建文件common_domain.yml,复制如下代码

intents:#定义意图

 - greet - goodbye - chat

entities:

 - action

templates:#表示对于相应的意图采取什么样的回复

  utter_greet:

    - "hello!"  utter_goodbye:

    - "byebye :("  utter_chat:

    - "It seems like funny!"

actions:

  - utter_greet  - utter_goodbye  - utter_chat

实现会话逻辑


from __future__ import absolute_import

from __future__ import division

from __future__ import print_function

from __future__ import unicode_literals



import logging



import numpy as np



from rasa_core import utils

from rasa_core.actions.action import ACTION_LISTEN_NAME

from rasa_core.agent import Agent

from rasa_core.channels.console import ConsoleInputChannel

from rasa_core.domain import TemplateDomain

from rasa_core.interpreter import NaturalLanguageInterpreter

from rasa_core.policies import Policy

from rasa_core.tracker_store import InMemoryTrackerStore



logger = logging.getLogger(__name__)



class CommonPolicy(Policy):

    def predict_action_probabilities(self, tracker, domain):

        # type: (DialogueStateTracker, Domain) -> List[float]

    #将对应的意图与动作绑定

        responses = {

            "greet": 2,

            "goodbye": 3,

            "chat": 4,

        }



        if tracker.latest_action_name == ACTION_LISTEN_NAME:

            key = tracker.latest_message.intent["name"]

            action = responses[key] if key in responses else 4

            return utils.one_hot(action, domain.num_actions)

        else:

            return np.zeros(domain.num_actions)



class HelloInterpreter(NaturalLanguageInterpreter):

    def parse(self, message):

        # intent = "greet" if 'hello' in message else "default"

        global intent

    #进行意图识别

        if 'hello' in message:

            intent='greet'

        elif 'goodbye' in message:

            intent='goodbye'

        else:

            intent='chat'

        return {

            "text": message,

            "intent": {"name": intent, "confidence": 1.0},

            "entities": []

        }



def run_hello_world(serve_forever=True):

    default_domain = TemplateDomain.load("./common_domain.yml")#加载多个domain怎么办

    agent = Agent(default_domain,

                  policies=[CommonPolicy()],

                  interpreter=HelloInterpreter(),

                  tracker_store=InMemoryTrackerStore(default_domain))



    if serve_forever:

        # Attach the commandline input to the controller to handle all

        # incoming messages from that channel

        agent.handle_channel(ConsoleInputChannel())



    return agent