聊天机器人中对话模板的高效匹配方法

/* 版权声明:可以任意转载,转载时请标明文章原始出处和作者信息 .*/

                                                     author: 张俊林,黄通文,薛会萍



 尽管深度学习目前在研发聊天机器人方面进行的如火如荼,但是这些技术距离真正实用还有不短的距离,在市面上你能看到的非常多的聊天机器人中,采用会话模板通过模板匹配来响应用户聊天应该是个主流方法,如果聊天对话内容非常多,采用简单粗暴的匹配效率是极低的,所以如何研发能够支持高效匹配的对话模板系统就非常必要。


|对话模板


  虽说目前人工智能热,NLP是人工智能中最重要的分枝之一,但是其实目前的NLP技术,就算把暴热的深度学习技术算进来,距离真正理解人的语言还有十万八千里距离,但是有时候你会有错觉,觉得好像它已经理解你的意思了啊,要不然怎么聊得这么High啊,比如下面的人和机器的对话:


我是人:你知道王思聪是谁吗

我是ChatBot:你问国民老公干嘛,你要跟他借钱吗?


看上去回答的够机智吧?难道这还没理解人的意思吗?所以说是错觉吗,其实只要在后台存储这么一个匹配模板就能做到上面的机智回答,而且可以确定的一点是,越是回答的有趣的答案,越可以肯定这是通过模板技术来做的,为啥呢?因为其它技术做不到真正理解人的话,更不要说回答的有趣了。


一句交互对话的模板由<Q,A>数据对构成,其中Q代表输入模板,A代表聊天机器人应该回答什么话,A可能不会是模板,而是就是应答的一句话,也可能是带着标签的模板,但是Q往往采用模板,因为这样覆盖率高,当然Q也完全可以是不带模板通配符的完整的一句话,但是一般而言模板居多,否则要穷举所有可能用户的问话基本不可能,通过加入*或者?这种通配符,可以用一个模板匹配更多的用户输入。当然,模板可以做得更复杂一些,按照复杂度不同,可能有下面几种类型的模板。


最简单的模板可能是这样的:


 Q:你贵姓?

 A:人家贵性女;


就是完整一句话作为一个模板;


稍微复杂些的模板长这样:


 Q:*喜欢*电影*是什么*

 A:我最喜欢的电影当然是《断背山》了,啥时候咱俩一起去看,帅哥~

 

这样,无论用户问的是下面哪句话,都能蹦出基情满满的回答:


   User A: 你能告我最喜欢的电影是什么吗?

   UserB:你最近喜欢的好电影是什么啊


很明显,这样能够一个模板匹配多种输入的情况。

 

如果再复杂一些,可以是带实体类别标签的模板:


Q:<PersonName>的生日是<Date>吗?

A:哥,我不敢认识<PersonName>.Value啊。

 

这样的模板等于把一些常见的实体变量抽象出来,否则带经常变化的人名地名日期等的句子模板是没法做的。如果有了上面的模板,就可以这么应答:


UserA:孙杨的生日是1232号吗?


聊天系统先上实体识别模块,把上面这句话转换成:


<PersonName>的生日是<Date>吗?


而且记住实体变量的值:<PersonName>.Value=孙杨;<Date>.Value=1232


这样发现对话模板库里面有一个匹配上的模板,于是就可以根据Q对应的A内容,把变量值填充进去,可以回答:


“哥,我不敢认识孙杨啊。”


因为这种类型的模板带实体变量的识别和值替换,所以看上去会显得智商高一点。



|简单高效的对话模板匹配


上面列举了常见的几种会话模板类型,如果模板数量少,那很好办,在用户输入内容后需要进行模板匹配,如果模板少,哪怕最简单的暴力匹配都不是啥问题,速度也不会太慢,但是如果模板数量巨大,比如几十万上百万,那么一个一个去暴力匹配这速度是不现实的,用户还以为你ChatBot休克了呢。所以现在的问题是,有什么高效的会话模板匹配方法吗?后面内容就是讲这个的。


下面介绍下我们在实际工作中的一个做法,这个没有参考相关资料,纯粹拍脑袋,所以不保证效率是最快的,不过一方面好在实现简单,手快的话就是几个小时的工作量,至于效率的话,我们测试过查找效率也是非常高的,基本都是几毫秒十几毫秒级别的,和Alice的模板查找速度比性能提升了12个数量级,大多数应用场合应该是够用的,所以分享出来供有需求同学参考。

 

首先,对于每个QA进行唯一编号,并对其Q部分,用切割点把Q切割成若干字符串片段,切割点有哪些呢?包括多字符通配符*和单字符通配符?符号,以及事先定义的实体标签(比如<PersonName><Address><Date>,<FilmName>等),这里实体标签既是切割点,也是需要记录的字符串片段,一身二用,而通配符只充当切割点。比如对于上面的三个例子:


1.*喜欢*电影*是什么*

会被切割为:

{你,喜欢,电影,是什么}

 

2.<PersonName>的生日是<Date>吗?

会被切割为:

{<PersonName>,的生日是,<Date>,吗?}

 

       3. 你贵姓?

      因为没有切割点,所以整个句子被当做一个片段,如下:

        {你贵姓?}

    然后,将这些被切割的字符串片段相同的合并后,形成了字符串字典:


    Diction={你,喜欢,电影,是什么, 你贵姓?, <PersonName>,的生日是,<Date>,吗?}


 根据这个字典,构建多模式匹配算法,我们实际用的是Wu_Manber算法,这个算法可以从用户输入句子中极快地将字典中包含的字符串片段全部扫描出来;

 

   第三步,根据第一步每个Q对应的编号及其被切割成的片段,建立内存倒排索引,Key是字符串片段内容或者其哈希值(因为有时候这个字符串片段可能是完整的一句话),Value是对应的Q编号序列,等价于一般意义搜索引擎的文档ID列表;


                                               1.运行逻辑图

有了以上基础设施,我们就可以来快速地进行模式匹配了(参考图1示意),假设用户输入NewQ,首先用Wu_Manber算法扫描NewQ,把其中包含的字典中的字符串片段都找出来,比如找出了A,B,C三个片段;使用A,B,C三个片段,从倒排索引中找出同时包含三个片段的模板集合QSet;现在有了用户输入NewQ和一个小的模板集合QSet,可以采用正则表达等传统的方式去进行模式匹配,找出其中某个模式或者一个模式也匹配不上。因为这个QSet相比原先整个模板集合来说,数据量是极小的,绝大多数时候只有一个或者几个,所以这个步骤不会太耗时间。


所以,综合上述过程,可以看出基本思路是:使用多模式匹配和倒排索引来快速找到一些候选的模板集合,这个模板集合大小相对原先整个模板集合来说相当小,然后在这个小集合上进行常规的模式匹配。


   瞧,大家觉得很神的对话一般都是这种方式蹦出来的,你觉得ChatBot理解了人的语言了吗?


猜你喜欢

转载自blog.csdn.net/malefactor/article/details/52166235
今日推荐