关于搭建问答系统的流程细节

用户输入

来源可以是web、微信、微博、等等一切类似平台

用户输入类型应该以文字为主

文字

语音

语音可以通过API识别为文字。在不同平台可能有不同的语音识别解决方案,例如在微信中可以考虑使用腾讯的服务。

或者使用其他第三方服务,下面列出的可能服务来自于Uberi

其他

其他可能用户输入包括但不限于,图片,地点(座标),文件,视频,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

然而上面这些语义相似度判断基本上都一个鸟样,实际用起来其实和编辑距离没太大区别,蠢死了~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章