1. 程式人生 > >微軟認知服務應用祕籍 – 與機器人聊知識

微軟認知服務應用祕籍 – 與機器人聊知識

在本篇部落格中,我們將會學習到零程式碼情況下,如何利用已有的技術建立自己的知識問答系統,這種系統的可以廣泛適用於學校、企業、客服、政府公開資訊等領域,代替傳統的電話諮詢、電子郵件溝通等高人工負荷的方式。

建立知識庫

什麼叫QnA Maker?

知識庫,就是人們總結出的一些歷史知識的集合,儲存、索引以後,可以被方便的檢索出來供後人查詢/學習。QnA Maker是用於建立知識庫的工具,使用 QnA Maker,可以根據 FAQ(常見問題解答)文件或者 URL 和產品手冊等半結構化內容打造一項問題與解答服務。可以生成一個問題與解答模型,以便靈活地應對使用者查詢,即使用者不必輸入精確的查詢條件,而是提供以自然對話方式受訓的機器人來響應。

下圖中是知識庫與Bot Service的結合使用架構圖:

與"半結構化資料"並列的是"結構化資料"和"非結構化資料",其中結構化資料可以用關係式資料庫來解決,非結構化資料用搜索引擎技術來解決。實際上搜索引擎就是把散落在網際網路各個角落的非結構資訊變成半結構化或結構化資訊。

不同於搜尋引擎,本文介紹的基於半結構化資料的QnA系統實現方式,是基於小規模資料量的,比如Million級別,而搜尋引擎的技術要高階很多,因為要面對Billion級別的資料。但是從原理上講,大家可以管中窺豹可見一斑。

在Azure中申請QnA Maker服務

用MSA登入Azure門戶,點選"建立資源",然後點選"AI + Machine Learning":

在下圖中點選"檢視全部":

在下圖中點選"更多:"

在下圖中點選"QnA Maker":

在下圖中的有紅色*的輸入框中,輸入必要的資訊,比如在Name中輸入" SchoolQASystem":

點選"建立"後,稍等一會兒,會得到以下通知訊息:

小提示:可以點選"固定到儀表板",方便後續查詢。

至此,我們的QnA服務已經申請好了,下一步是建立知識庫,填寫資料。

在QnA Maker網站上建立知識庫

用Edge瀏覽器開啟https://www.qnamaker.ai,登入自己的MSA賬號。如果是第一進入該網站,你的My knowledge bases將會是空白頁,點選Create a knowledge base來建立自己的第一個知識庫:

小提示:這裡用的MSA賬號應該與申請認知服務的MSA賬號相同。

STEP 1我們已經做過了,現在在STEP 2中從下拉列表中選擇自己的相關資訊:

在STEP 3中填寫一個知識庫的名字,比如SchoolQASystemKB:

在STEP 5中點選"Create your KB"來建立知識庫:

小提示:STEP 4可以執行使用者通過提供一個靜態網頁或者一個固定格式的檔案,來自動提取問題和答案。

稍等一會兒,進入如下頁面:

我們以學校中常用的一些問答資訊為例,點選"+ Add QnA pair"填寫如下資料:

當然可以根據實際情況,填寫其它一些資訊。需要注意的是,每個Question需要有唯一的一個Answer來對應,而每個Answer可以有很多個Question,是N:1的關係。

小提示:以上資料均為虛構,請填寫符合自己學校實際情況的資料。

資料填寫的差不多了(一次填寫不完沒關係,可以以後修改),點選"Save and train"按鈕,稍等一會兒,點選那個"Test"按鈕,進行線上測試。在問題框中輸入"報銷"或者一個整句“醫療費如何報銷”,可以很快得到系統的回覆,如下圖就是測試結果:

此時也可以點選"Inspect"來看細節,比如Confidence score的值是79.75分,也可以在左側填寫更多的問題來對應這個答案,比如"看病報銷":

覺得滿意後,點選"PUBLISH"按鈕來發布這個知識庫:

稍等一會兒,得到如下資訊:

好啦!到目前為止,我們已經成功建立了第一個知識庫。

小提示:保留這個網頁或者請記住上圖中的資訊,一會兒我們還會用到它。

下面我們有兩個選擇:

1)寫程式碼來訪問這個知識庫,提供介面供他人使用。

2)用微軟的另外一項技術 – 聊天機器人技術,以問答方式來提供訪問該知識庫的介面。這個內容我們在下一個大章節講述。

用程式碼訪問QnA知識庫

開啟利器VS2017,新建一個Windows Desktop WPF專案,給個名字叫QAClient:

在MainWindow.xaml中填寫如下XAML介面設計程式碼:

<Window x:Class="QAClient.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:QAClient"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="40"/>
        </Grid.RowDefinitions>
        <TextBox Name="tb_Dialog" Grid.Row="0"/>
        <Grid Grid.Row="1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="80"/>
            </Grid.ColumnDefinitions>
            <TextBox Name="tb_Question" MaxLines="1" Grid.Column="0"/>
            <Button Name="btn_Send" Content="Send" Grid.Column="1" Click="btn_Send_Click"/>
        </Grid>
    </Grid>
</Window>

在MainWindow.xaml.cs中新增按鈕事件處理函式:

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private async void btn_Send_Click(object sender, RoutedEventArgs e)
        {
            // send http post request to qa service
            Answers results = await QAServiceAgent.DoQuery(this.tb_Question.Text);
            if (results.answers != null && results.answers.Length > 0)
            {
                this.tb_Dialog.Text += "問:" + this.tb_Question.Text + "\r\n";
                this.tb_Dialog.Text += results.answers[0].ToString() + "\r\n";
            }
        }
}

在工程中新增QAServiceAgent.cs檔案,填寫以下內容:

using System;
using System.Diagnostics;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace QAClient
{
    class QAServiceAgent
    {
        const string Endpoint = "/knowledgebases/90690b7-dae-4e0d-bda9-16c05e0f163/generateAnswer";
        const string Host = "https://openmindqnamaker.azurewebsites.net/qnamaker";
        const string Key = "e7e3c51-dc5-4d65-aa3-8da1024c3e13";
        const string ContentType = "application/json";
        // {"question":"<Your question>"}

        public static async Task<Answers> DoQuery(string question)
        {
            try
            {
                using (HttpClient hc = new HttpClient())
                {
                    hc.DefaultRequestHeaders.Add("authorization", "EndpointKey " + Key);
                    string jsonBody = CreateJsonBodyElement(question);
                    StringContent content = new StringContent(jsonBody, Encoding.UTF8, ContentType);
                    string uri = Host + Endpoint;
                    HttpResponseMessage resp = await hc.PostAsync(uri, content);
                    string json = await resp.Content.ReadAsStringAsync();
                    var ro = Newtonsoft.Json.JsonConvert.DeserializeObject<Answers>(json);
                    return ro;
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
                return null;
            }
        }

        private static string CreateJsonBodyElement(string question)
        {
            string a = "{\"question\":\"" + question + "\"}";
            return a;
        }
    }
}

小提示:上面程式碼中的Endpoint和Key已經經過修改,是不可用的,請用你自己申請的資料來代替。

在工程中新增另外一個檔案Result.cs,用於反序列化JSON資料:

namespace QAClient
{
    public class Answers
    {
        public Answer[] answers { get; set; }
    }

    public class Answer
    {
        public string[] questions { get; set; }
        public string answer { get; set; }
        public float score { get; set; }
        public int id { get; set; }
        public string source { get; set; }
        public object[] metadata { get; set; }

        public override string ToString()
        {
            return string.Format("Answer: {0}, Score:{1}", answer, score);
        }
    }
}

程式碼完成!搓搓雙手,按Ctrl+F5走起一波!哇哦!好俊的介面:

在下方的輸入框中輸入"報銷"、"開學日期"、"補考"等問題,都會得到預定的答案。輸入"校長是誰"就沒有match到任何答案,因為我們沒有在資料中準備這個問題。

我們是用客戶端形式做了一個問答介面,當然也可以在網站上用REST API實現同樣的功能。同時,微軟提供了Bot Service,下一章我們看看如何在不寫任何程式碼的情況下,完成機器人與QnA服務的整合。

建立對話機器人服務

什麼是機器人服務?

機器人是使用者使用文字、圖形(卡片)或語音通過聊天的方式進行互動的應用。它可以是一個簡單的問答對話,也可以是一個複雜的機器人,允許使用者使用模式匹配、狀態跟蹤和與現有業務服務完美整合的人工智慧技術通過智慧的方式與服務進行互動。常見的機器人服務有以下幾類:

  • 商務/金融服務,如銀行提供的線上客服
  • 資訊服務,如政府部門的常用資訊問答服務
  • 產品服務,如企業提供的產品諮詢服務

總之,機器人服務就是用計算機代替人來完成一些具有標準化流程的人機對話服務。

微軟提供的機器人服務的概述在這個連結裡面,建立一個機器人服務和一般的軟體其實沒多大區別,也要經過以下幾個步驟然後再迭代:

計劃:確定需求,需要什麼型別的機器人服務

構建:選擇工具/語言/框架等等

測試:機器人其實知識介面,後端連線了一堆智慧服務,要通過機器人介面測試好所有功能

釋出:釋出的Azure上或者自己的Web伺服器上

連線:可以將機器人連線到以有的客戶端軟體上,方便使用者接入,比如Cortana、Skype等

評估:根據執行日誌獲得基本執行指標,如流量、延遲、故障等等,作為迭代的依據

建立對話機器人

用MSA登入Azure門戶,點選"建立資源":

小提示:此MSA賬號需要與前面的QnA服務的MSA賬號相同。

選擇"AI + Machine Learning",在右側選擇"Web App Bot":

在上圖中選擇Web App Bot,在右側彈出的視窗中點選"建立"按鈕,得到下圖:

在上圖中填寫必要的資訊,比如機器人名稱是"SchoolQnAWebBot",機器人模板要選擇"Question and Answer",可以關閉Application Insights來簡化過程。

小提示:記住要點選"選擇"按鈕,否則不生效。

最後點選"建立"按鈕,稍等一會兒,得到以下通知:

小提示:此時可以固定到儀表板,方便以後訪問。

連線知識庫

在儀表板上點選這個機器人,然後點選左側的"網路聊天測試":

在上圖中下方輸入"報銷",機器人傻傻的回了一句"you said 報銷"。因為這個機器人剛剛建立,還沒有連到上面建立的知識庫上,所以它並不知道如何回答你的問題。所以點選左側的"應用程式設定",看到一個嚇人的頁面,不要慌,鎮定地向下卷滾,直到看到QnA開頭的專案,一共有三個,如下圖:

這三個值本來是空的,我們需要用以前得到一個資訊來填寫:

把顏色對應的資訊填寫到空白處就可以了。填寫完畢後,點選最上方的"儲存"按鈕,稍等一會兒,這個Bot service會被重新編譯部署。等到部署完畢收到通知後,可以再測試一下,輸入"報銷"並回車,機器人就會給你返回知識庫中的答案:

WoW! 我們沒寫一行code,就完成了知識庫和機器人的連線,龍顏大悅,喝口燕窩銀耳湯,看看還有什麼好玩兒的!

連線已有應用

這個機器人雖然已經建立起來了,可是用什麼常見的客戶端來啟用這個機器人呢?

我們在下圖中點選左側那個"通道"看看:

很神奇的樣子,好像可以連線這麼多種客戶端!我們用Skype先試驗一下。點選Skype圖示,進入一個頁面,但是可以不管它,退回到"通道"頁面,可以看到下圖:

點選那個"Skype"文字連結(不是點選圖示),會另起一個網頁:

點選"Add to Contacts",如果機器上安裝了Skype UWP版(如下圖),就可以啟動它了。如果沒有安裝,剛才那個網頁會給你一個"Download Skype"的選項。

Skype啟動後,SchoolQnAWebBot會作為一個聯絡人出現在對話中,我們可以問它一些事情,如下圖所示,"報銷"、"補考"、"開學"等,機器人都可以回答。但是輸入比如"誰是校長"之類的不在知識庫裡的詞彙,機器人就只能裝傻充愣了。