關於搭建問答系統的流程細節

用戶輸入

來源可以是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

然而上面這些語義相似度判斷基本上都一個鳥樣,實際用起來其實和編輯距離沒太大區別,蠢死了~~

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