用户输入
来源可以是web、微信、微博、等等一切类似平台
用户输入类型应该以文字为主
文字
语音
语音可以通过API识别为文字。在不同平台可能有不同的语音识别解决方案,例如在微信中可以考虑使用腾讯的服务。
或者使用其他第三方服务,下面列出的可能服务来自于Uberi
- CMU Sphinx
- Google Speech Recognition
- Wit.ai
- Microsoft Bing Voice Recognition
- api.ai
- Houndify API
- IBM Speech to Text
其他
其他可能用户输入包括但不限于,图片,地点(坐标),文件,视频,URL(文本的一种)
文字处理
文字处理的基本流程是
- 中文分词
- 实体识别
- 意图判断
中文分词 Chinese Word segmentation
因为要做实体识别,中文分词可能是比较必要的部分
可以考虑的服务有jieba,stanford segmenter,pullword,或者其他免费、收费服务
实体识别 Named Entity Recognition
stanford ner对于中文只有三种类型实体的判断,人物,地点,时间
为了精确,考虑自己添加其他实体识别类型,例如:
- 电话号码,手机,固话,400/800
- 价格,例如xx元
- 电子邮件
- 网址
- 年龄
- 数字
可以参考wit.ai和api.ai的实体类型
还有其他更模糊的实体,例如
- 要搜索的条目
- 要翻译的英文单词
意图判断 Intent Detection / Prediction
我想吐槽一下,这两年虽然关于Dialogue和QA的论文不少,但是很多都太“学术化”的感觉。
如果用那些文章的方法搭建起来,别说用,我觉得可能想达到wit.ai或者api.ai的水平都不行。
这一部分可能是整个流程最难的部分,倒是也不是说真的最难,关键是没有很好的现成的工具可以用~~
如果我们暂且把意图分解为两部分:命令,非命令
一般来说,目的就是尽可能的提高命令的recall,而不是precision,这也是大部分机器人的做法。
简单来说,就是用户问“我想要看天气”,我们返回天气,如果用户说“我讨厌天气预报”,我们可能还是会返回天气。
即便这句话的语义完全不应该返回天气,但是为了高recall,而且因为语义分析(相似度)完全没有好办法。
这个precision和recall的问题是一个难点,还有工程上考虑上下文是一个难点
一个朴素的想法是,像wit.ai那样把一个场景(story)分开,如果在这个场景中,
所有场景的关键词匹配阈值都改变(在某个场景中,则增加这个场景的匹配可能性)。
如果没在场景中,则所有的匹配关键词阈值还是原来那样。
流程类似:
- 用户输入语句S
- S是否Exactly Match某条命令?
- S是否Prefectly Match某条命令
- S是否Regex Match某条命令
- 如果是,则确定是这条命令
- 在所有的命令库中计算所有命令和S的距离(语义相似度)并排序
- 如果用户的上下文在某个场景(story)中,则相关场景的得分提高
- 如果距离得分最高的命令大于某个阈值,则确定是这条命令
- 如果现在依然没匹配到某条命令,则闲聊(chichat)
在不考虑命令的语义相似度是否准确的情况下,还有其他工程上的难点。
考虑是否构造一个类似于AIML的语言,能尽可能的提高效率。
这款语言应该定义好Exactly match,包括Regexp match,应该能定义好Story、Enity。
考虑XML或者JSON实现,当然你们都知道我不喜欢XML。
例如:
1、模糊匹配如“北京的天气怎么样?”这种命令
如果系统判断用户在weather这个story中,那么匹配“深圳呢?”这个命令的可能性也将大幅提高
[
{
"pattern": [
"{sys.location}{sys.date}天气怎么样?",
"{sys.location}的温度"
],
"mode": "normal",
"story": "weather",
"must_have": [
"sys.location"
],
"action": "get_weather({sys.location}, {sys.date || today})"
},
{
"pattern": [
"{sys.location}呢?"
],
"mode": "normal",
"story": "weather",,
"must_have": [
"sys.location"
],
"action": "get_weather({sys.location}, {today})"
},
{
"pattern": [
"{sys.date}呢?"
],
"mode": "normal",
"story": "weather",,
"must_have": [
"story.sys.location"
],
"action": "get_weather({story.sys.location}, {sys.date})"
}
]
运行如下:
- Q 北京今天天气怎么样?
- A 匹配出sys.location是北京,sys.date是今天
- Q 深圳的温度
- A 匹配出sys.location是深圳,sys.date没有,默认是今天
- Q 广州呢?
- A 匹配到了sys.location,当前的story是weather,返回温度查询
- Q 明天呢?
- A 匹配到了sys.date,查询当前的story是weather,当前story下存在sys.location(广州),返回温度
2、命令式,不模糊的翻译英文,任何以“翻译:”,“翻译 ”等开头的就将被匹配
[
{
"pattern": [
"翻译(\s+|,|:|:)([a-zA-Z0-9-\s]+)"
],
"mode": "regex",
"story": "translate_english",
action: "translate_english({$2})"
}
]
命令的语义相似度判断:
编辑距离
Levenshtein Distance
基于wordnet
Synets Similarity
Jaccard Similarity
基于2vec
Mean of Word2Vec
Doc2Vec
其他
TreeLSTM
然而上面这些语义相似度判断基本上都一个鸟样,实际用起来其实和编辑距离没太大区别,蠢死了~~