开发一个智能问答机器人

近期开发了一套基于天然语言处理的问答机器人,以前没有作过python,主要作asp.net,写这篇目的是给想要开发这类智能客服系统的朋友提供一个思路,项目已经上线,但在开发和设计过程当中仍然有不少问题没有获得解决,也指望和你们一同讨论学习。html

最终的上线效果: python

开发过程大概3阶段,第一阶段 完成基础一问一答功能;第二阶段 加入意图识别,能够进一步区分用户问题,特定意图好比工资查询,将会调用第三方接口;第三阶段 上下文处理,引导用户进行多轮问答;git

插一句微软认知服务是云端的较好解决方案,  BOT Framework平台集成了多种对接方式,无需本身开发。LUIS的配置和发布也很是方便,特别的若是使用场景真的很是简单(一问一答),能够仅用QnAMaker。github

but... 基于业务数据暴露和其余安全性考虑,有时须要将服务部署在本地(内网),我主要想说的就是本地开发搭建的问答服务。web

1 基础问答实现

1.1选型算法

可以作基础问答的开源项目很是多chatterbot,rasa_core等等。我选用的是chatterbot(0.7.6)json

1.2开发api

在搭建完开发环境后chatterbot能够直接使用,默认算法是编辑距离,因此理论上支持任何语言,包括中文。数组

我主要修改了chatterbot算法模块,适配器模块和输入输出模块,最终输出格式以下安全

{
    "text": "三方协议一式三方,三方盖完章后,学校,公司,学生本人各留一份。",
    "in_response_to": [{
        "text": "三方协议如何存档?",
        "created_at": "2017-11-24T15:11:06.500966",
        "occurrence": 4
    }],
    "created_at": "2017-11-24T15:11:06.500",
    "extra_data": {
        "userid": "1000058"
    },
    "question": "三方协议如何存档?",
    "oriquestion": "三方协议",
    "channel": "2",
    "suggestions": [
        ["三方协议如何存档?", 0.62],
        ["三方协议能够他人带签署领取吗?", 0.42],
        ["实习生三方协议上面部门怎么填写?", 0.4]
    ]
}

text答案,in_response_to上下文,extra_data附加信息(能够放用户身份标识等),question匹配到的问题,oriquestion用户输入问题,channel词库编号(支持多词库每一个词库可能有不一样的处理),感兴趣问题列表(匹配度稍低的问题)

chatterbot的adapter原本设计是能够放多个,每一个适配器完成本身的功能(解耦),但实际使用时(5000条问答),多适配器是很是缓慢的,因为每一个适配器都会循环处理或比对问题,因此建议只放一个adapter实现全部功能

'logic_adapters':['mybot.MyLogicAdapter']

算法

位于comparisons.py中默认的编辑距离算法或杰拉德类似系数算法,都是基于简单的文本比对,没法处理同义词近义词。这里咱们引入的word2vec算法

训练数据来自中文维基百科,加入了特定业务文档数据(仅73M,维基百科1.11G...)

使用jieba分词,gensim word2vec训练模型,特征向量400维,大概须要14小时(参考个人吃鸡电脑I7 7700 GTX1080)。

# 装载以前训练好的模型

custom_model = Word2Vec.load('data/custom.model')

用户输入先经过jieba分词,获得词和词频的数组,例如:查询个人薪资
查询 2
我 5
的 1
薪资 3
# 查询key在模型中向量
vec =custom_model['查询'] 

# 加权(模型中向量*jieba分词中权重)
sentvec = sentvec + vec * 2

把句子中词向量相加获得整个句子的向量。

再利用夹角余弦,与业务词库中的问题比较,获得最类似的问题匹配。

此方法,能够处理诸如,皇后->女人 这类的近义问题。从图上能够看到女人与皇后余弦夹角小于皇后与木头余弦夹角,结论为女人与皇后更类似。

 

因此最终的算法:编辑距离+word2vec。

2 意图识别

意图识别属于天然语言理解范围,主流机器学习算法支持向量机、决策树等分类方法。咱们使用意图识别主要用来分离出用户的查询意图,再调用对应的第三方接口将数据返回给用户,例如 北京今每天气?识别为天气意图,实体为北京。

2.1选型

咱们这里选用开源项目rasa_nlu(11.0.3),这是一个集意图识别,实体提取功能于一体的项目。能够生成以下的数据

{
  "intent": {
    "name": "weather",
    "confidence": 0.44477984330690684
  },
  "entities": [
    {
      "entity": "city",
      "value": "大连",
      "start": 0,
      "end": 2,
      "extractor": "ner_mitie"
    },
    {
      "entity": "date",
      "value": "后天",
      "start": 2,
      "end": 4,
      "extractor": "ner_mitie"
    }
  ],
  "intent_ranking": [
    {
      "name": "weather",
      "confidence": 0.44477984330690684
    },
    {
      "name": "bookhotel",
      "confidence": 0.37330751883981904
    },
    {
      "name": "map",
      "confidence": 0.18191263785327412
    }
  ],
  "text": "大连后每天气怎么样"
}

2.2开发

在实际使用中,有时可能仅须要提取实体,因此我额外作了一个流程,仅提取实体。

{
  "entities": [
    {
      "entity": "city",
      "value": "大连",
      "start": 0,
      "end": 2,
      "extractor": "ner_mitie"
    }
  ],
  "text": "大连天气怎么样"
}

2.3命名实体提取替换

项目最终使用"pipeline": ["tokenizer_jieba","ner_synonyms","intent_entity_featurizer_regex","intent_featurizer_mitie","intent_classifier_sklearn","ner_corenlp"]

以前使用MITIE做为命名实体提取,但MITIE须要本身训练,实际使用时训练语句过少,正确率偏低,改用corenlp,默认支持中文 我截取目标默承认以识别的实体类型
# DATE: type:日期  eg:明天
# LOCATION: type:地点 eg:齐齐哈尔
# MISC: type:其余 eg:怎么样
# MONEY: type:金额
# ORGANIZATION: type:组织
# PERCENT: type:百分比
# PERSON: type:人 eg:特朗普
# TIME: type:时间 eg:下午
# O: type:动词或其余 eg:查询
# COUNTRY: type:国家 eg:中国
# STATE_OR_PROVINCE: type:城市/省会 eg:北京
# CITY: type:城市 eg:西安

 

 

2.0补充

系统缺陷修复,使用rasa_nlu意图分类,基于sklearn-svmcv算法,可是分类后,各意图结果相加始终等于1,我以前的设想(后面有详细说明):设定一个阈值好比0.7,判断最高匹配度的意图是否大于阈值,若是大于则认为明确意图。但这基于问题是意图的前提,

我训练意图用了三个分类weather,bookhotel,map,但我没法将问答的5000个问题训练为other意图,因为5000个问答中涉及多领域,很是多的特征向量会对意图分类形成很大影响,使分类不许确。

目前的解决方案为在乎图识别前,加入一个二分类器,也基于sklearn的分类器,用于区分问题仍是意图,训练使用18000条生产环境用户问题和6000*3加权的意图问题(等量的训练数据)训练并比较准确率。

用户问题 标识(1意图0普通问题)
今每天气如何 1
我想预订北京的酒店 1
机器人的内部处理流程是怎样的 0
公司发展历程 0

 

 

 

 

 

生成pkl文件。将pkl文件放入指定位置,替换最准确算法。

当前最高为随机森林算法

******************* NB ********************

accuracy: 90.06%

******************* KNN ******************** 

accuracy: 87.50%

******************* LR ********************

accuracy: 90.91%

******************* RF ********************

accuracy: 96.31%

******************* DT ********************

accuracy: 95.17%

******************* SVM ********************

accuracy: 25.28%

******************* SVMCV ********************

accuracy: 93.75%

******************* GBDT ********************

accuracy: 87.78%

 

3 上下文

看了不少大神基于深度学习算法的帖子还有论文,感受实在力不从心... 这里使用模板配置的方式,引导用户完成上下文。

JSON数据格式

{
"rule": [{
"intent": "weather",
"entities": [
{"name":"city","type":"city","required":"true","prompts":["请问查询哪里的天气","想查询哪一个城市的天气"]},
{"name":"date","type":"date","required":"false","prompts":[]}
]
},
{
"intent": "bookhotel",
"entities": [
{"name":"city","type":"city","required":"true","prompts":["请问预订哪里","想预订哪一个城市"]},
{"name":"checkindata","type":"date","required":"true","prompts":["请问什么时候入住","预订酒店的时间"]},
{"name":"checkoutdata","type":"date","required":"false","prompts":[]}
]
},
{
"intent": "bookticket",
"entities": [
{"name":"fromcity","type":"city","required":"true","prompts":["请提供出发城市","从哪起飞"]},
{"name":"tocity","type":"city","required":"true","prompts":["请提供到达城市","到哪落地"]},
{"name":"date","type":"date","required":"true","prompts":["请问预订机票的时间","想预订哪天的机票"]}
]
}
]
}

这就是上下文的控制流程,主要代码逻辑控制,没有使用机器学习算法。

  

特别的,这里阈值很是的重要,阈值范围0~1,越小越容易被理解为意图,当为1时,等同于关键字匹配。

举个栗子,若是阈值设定很是小,用户的普通提问都会被理解为意图,不会进入chatterbot问答中,若是很是大,则难以进入意图识别,训练data 查询工资,若是用户输入“查询个人工资”可能也不会进入意图查询

阈值我使用梯度降低算法,拟合成二维曲线,找到最高点,0.74

 

后记

项目开发过程大概4个月(第一周,学习python基础语法,主要了解函数,变量赋值逻辑,web api实现,以后开始学习深度学习算法,主要从帖子、论文和视频,MIT、台大、Stanford的教学视频都很是好,能够在B站上看,选型时几乎试用了全部开源的QA项目,通常QA项目都须要训练,准备语料因此耗费了大量时间),独立开发,实际编码时间一个月,最后用asp.net mvc封装了这些接口,作了问答页面和简单的后台语料管理系统(我也想用python...来不及)

咱们业务问答5000多条,一共有3个实习生,配合我标注语料,编写测试集和验证集(真正的工做量在这)

最终正确率:68.4%(微软验证集正确率:81.7%)

 

chatterbot 项目主框架

https://github.com/gunthercox/ChatterBot

sklearn 意图问题分类

https://github.com/automl/auto-sklearn

rasa_nlu 意图识别模块

https://github.com/RasaHQ/rasa_nlu

gensim word2vec算法实现

https://github.com/RaRe-Technologies/gensim

word2vec,中文处理

https://github.com/zake7749/word2vec-tutorial

类似度比较-向量余弦夹角

https://github.com/kris2692/Vector-semantics

 

主要问题:

1.正确率过低:若是单用word2vec算法,正确率只有36.2%,单用编辑距离算法正确率59.8%,不知道为什么我写word2vec算法正确率如此低,一直没有找到缘由。

2.数据分散,用多种语言编写:整个项目一共三部分:chatterbot,rasa_nlu,mvc web,在修改意图时很是麻烦,在管理系统修改意图后,生成json文件,须要手工拷贝到rasa_nlu项目中,再使用cmd命令train,start server。

 

补充

开发一个智能问答机器人(优化篇)

相关文章
相关标签/搜索