Q&Aの作成には、AzureのQ&AサービスであるQnA Makerを使用し、Bot FrameworkとQnA Makerを連携する実装方法についても説明していきます。
○はじめに

前回に引き続きAzure Bot Servicesについて紹介します。今回は、前回作成したチャットボットを拡張してQ&Aに回答できる機能を追加していきます。
Q&Aの作成には、AzureのQ&AサービスであるQnA Makerを使用し、Bot FrameworkとQnA Makerを連携する実装方法についても説明していきます。
○QnA Makerを使ったナレッジベースを作ろう

まず始めにQnA Makerを使い、Q&Aのデータベースとなるナレッジベースを作成していきます。
○QnA Makerとは

QnA Makerとは、ある質問に対して必ず同じ回答を返すような、いわゆるQ&AやFAQといった種類のワークフローに特化したAzureのサービスです。
QnA Makerは、質問とその回答のセットからなるナレッジベースと呼ばれるデータベースの作成と、ユーザーからの任意の質問文を処理して適切な回答を導き出す自然言語処理エンジンを提供します。
また、Bot FrameworkのSDKではQnA Makerを扱うための拡張ライブラリが提供されているため、Bot Frameworkを使った実装にQnA Makerを統合することが容易に行なえるようになっています。
○QnAサービスの作成

ここからはQnA Makerのインスタンスに相当する、QnAサービスとナレッジベースの作成を行います。QnA Makerのサイトをブラウザで開き、右上の「Sign in」からAzureと同じ認証情報でログインします。ログイン後に画面上部の「Create a knowledge base」を選択するとQnAサービスとナレッジベースの作成画面が表示されます。まずは「STEP 1」の項目にある「Create a QnA service」を選択して、QnAサービスを作成していきます。

Azureポータルの画面に遷移してQnAサービスの新規作成画面が表示されたら、内容を入力していきます。「名前」と「アプリ名」には任意の名称を入力し、「サブスクリプション」、「リソースグループ」はお手持ちのものを選択します。
「価格レベル」ではQnAサービスの稼働環境であるCognitive Serviceのプランを選択します。今回はサンプルアプリのため、無料プランである「F0」を選択します。「Azure Search 価格レベル」では、ナレッジベースのデータ格納先であるAzure Searchのプランを選択します。こちらも無料プランの「F(3 Indexes)」を選択します。
「Azure Searchの場所」と「Webサイトの場所」では、Azure SearchとCognitive Serviceの配置場所を指定します。今回は東日本を選択しています。またアプリの監視サービスである「App Insights」は、サンプルアプリのためここではオフにします。

最後に「作成」ボタンを選択してQnA Makerの作成を開始します。しばらく待つとQnAサービスの作成が完了します。
○ナレッジベースの作成

続いて作成したQnAサービスとナレッジベースを接続します。
QnA Makerのサイトに戻り、「STEP 2」にある「Refresh」ボタンを選択して先程作成したQnA Makerを認識できるようにします。次に4つのプルダウンの内容を順に選択していきます。先ほど作成したQnAサービスと同じAzureのディレクトリとサブスクリプションを選択し、「Azure QnA service」のプルダウンで先程作成したQnAサービス名と同じものを選択します。最後に「Language」のプルダウンで、このナレッジベースが対応する言語を選択します。今回は日本語に対応できるように「Japanese」を選択します。

続いて「STEP 3」でナレッジベースに任意の名称を指定します。

「STEP 4」でナレッジベースのデータソースを指定していきます。QnA Makerでは、ナレッジベースのデータソースとしてWebページやTSVファイルなどを指定することができます。今回は、Azureの料金に関するFAQのWebページをナレッジベースとして使用します。WebページのURLである「https://azure.microsoft.com/ja-jp/pricing/faq/」を「URL」の部分に入力します。

最後に、「STEP 5」にある「Create your KB」のボタンを選択してナレッジベースの作成を開始します。

作成が完了し、ナレッジベースの編集画面が表示されれば成功です。この画面上から質問や回答の内容を編集することできます。

また画面右上にある「Test」ボタンを選択すると、ナレッジベースの挙動を確認することができます。画面下部にあるメッセージ入力フィールドに質問を入力すると、ナレッジベースから質問に対応した回答が返ってきます。

これでQnA Makerでナレッジベースを作成することができました。次はこのナレッジベースをチャットボットへ統合していきます。
○Bot FrameworkとQnA Makerを組み合わせたボットアプリケーションを作ろう

QnA Makerを使ってナレッジベースの作成ができたら、次はBot Frameworkからナレッジベースを使えるようにしてみましょう。ここでは前回の記事で作成したエコーボット用のBot Serviceを使って説明していきます。
○Bot Frameworkのソースコードのダウンロード

まずはエコーボットのソースコードをダウンロードします。AzureポータルからBot Serviceを開き、前回作成したBot Serviceを表示します。「ビルド」を選択すると「ボットのソースコードをダウンロードする」というボタンがあるので、ここからソースコードをダンロードすることができます。

ソースコードをダウンロードしたら、任意のディレクトリでzipファイルを解凍します。また、依存ライブラリをインストールするために以下のコマンドをターミナルで実行します。

Bot Serviceプロジェクトの依存ライブラリをインストールする

npm install

インストールが正常に完了すれば成功です。
○QnAサービスを公開する

次にQnAサービスを公開します。QnAサービスを公開することで、Bot ServiceからQnAサービスに対してアクセスすることができるようになります。
QnA Makerのサイトに戻り、先程作成したナレッジベースの画面上部から「PUBLISH」を選択し、さらに「Publish」ボタンを選択して公開を開始します。

公開が完了すると、QnAサービスの接続情報を取得することができるようになります。
○QnAサービスの接続情報を設定ファイルに追加する

QnAサービスが公開できたら、「SETTINGS」タブを選択して「Deployment details」の項目に表示されているサンプルリクエストから抜粋した内容を、Bot Serviceのプロジェクトの設定ファイルである「.env」ファイルに反映していきます。以下のリストのように、ファイルに「QnA・・・」から始まる設定を3行追加します。

設定情報ファイルにQnA Makerの接続情報を追加する(.env)

MicrosoftAppId=<設定済みの値>
MicrosoftAppPassword=<設定済みの値>
ScmType=None
QnAKnowledgebaseId=<ナレッジベースのID>・・・①
QnAEndpointHostName=<ナレッジベースのエンドポイントURL>・・・②
QnAEndpointKey=<ナレッジベースのエンドポイントキー>・・・③

「QnAKnowledgebaseId」の値にはナレッジベースIDというナレッジベースをAzure上で一意に識別するIDを設定します(①)。これは、ナレッジベースのURLの「kbid=」以降の値か、サンプルスクリプト内の「POST /knowledgebases/XXX/generateAnswer」という行に含まれる「XXX」部分の値を設定します。
「QnAEndpointHostName」にはナレッジベースが公開しているエンドポイントURLを設定します(②)。サンプルスクリプト内にある「Host: 」以降のURLを使用します。
「QnAEndpointKey」はナレッジベースが認証に使用するキー情報を設定します(③)。サンプルスクリプト内の「Authorization: EndpointKey 」以降の値を使用します。

「.env」ファイルが編集できたら、次はボットがQnAサービスにアクセスするようにコードを修正していきます。
○ボットからQnAサービスにアクセスする実装の追加

Bot Frameworkでは、ボットからQnAサービスへのアクセスを簡易化するライブラリが提供されています。まずはそのライブラリをプロジェクトに追加します。

QnA Makerを使用するためのライブラリをインストールする

npm install botbuilder-ai

ここで追加した「botbuilder-ai」は、Bot Frameworkの中核である「botbuilder」ライブラリの拡張ライブラリで、主にCognitive Serviceとボットとの連携に関連するコードが含まれています。QnA MakerはCongnitive Service内のサブサービスにあたるため、このライブラリを使用します。
ライブラリが追加されたら、次にコードを修正していきます。

ボットにQnA Makerのインスタンスを追加する(bot.js)

const { ActivityHandler } = require('botbuilder');
const { QnAMaker } = require('botbuilder-ai'); ・・・①

class EchoBot extends ActivityHandler {
constructor() {
super();

// QnAMakerのインスタンスをボットクラスに追加する ・・・②
this.qnaMaker = new QnAMaker({
knowledgeBaseId: process.env.QnAKnowledgebaseId,
endpointKey: process.env.QnAEndpointKey,
host: process.env.QnAEndpointHostName
});

// ボットがメッセージを受信した時のイベントハンドラー
this.onMessage(async (context, next) => {

// 受信したメッセージをQnAサービスに送信する・・・③
const qnaResults = await this.qnaMaker.getAnswers(context);

// 質問に対応する回答が存在すれば回答を返却する・・・④
if (qnaResults[0]) {
await context.sendActivity(qnaResults[0].answer);

// 回答が存在しない場合のメッセージを返却する
} else {
await context.sendActivity('回答が見つかりませんでした。');
}

await next();
});

・・・省略・・・

先程追加した「botbuilder-ai」ライブラリから、QnAサービス用のクラスをインポートします(①)。そのクラスを、ボットのコンストラクタ内でインスタンス化します(②)。インスタンス化する際の引数には、「.env」ファイルに設定したQnAサービスに関する設定情報を使用しています。このインスタンスの「getAnswers」メソッドは、引数に設定した質問内容でQnAサービスに質問を送信します(③)。質問内容に対応する回答がQnAサービス上にあった場合、戻り値に回答内容が含まれるので、それをクライアントに返却するようにします(④)。QnAサービスへの質問の送信と回答の受信を、ボットの「onMessage」イベントハンドラー内で行うことで、クライアントがメッセージを送信するたびに処理が実行されるようになります。
○Bot Framework Emulatorによるローカル環境での動作確認

コードの修正が完了したら、ボットをローカル環境で起動して動作確認を行いましょう。ターミナルを開き、プロジェクトのルートディレクトリで以下のコマンドを実行します。

ボットをローカル環境で起動する

npm start

コマンド実行後、「restify listening to http://[::]:3978」のようなメッセージが表示されていれば起動は成功です。ボットは、Webサービスとしてlocalhostの任意のポート(デフォルトでは3978ポート)で起動しています。このボットに対して動作確認を行うために、Azure Bot Serviceでは「Bot Framework Emulator」というクライアントエミュレーターを、ボット開発の支援ツールとして提供しています。エミュレーターのダウンロードページよりご自身の環境にあった最新版のインストーラーを選択してインストールをしてください。
インストール後、エミュレーターを起動すると以下のようなWelcome画面が表示されます。「Open Bot」ボタンを選択して、接続したいボットの情報を入力していきます。

ダイアログが表示されたら、ボットの接続情報を入力していきます。「Bot URL」には、ボットのURLを入力します。ローカルでボットを起動している場合は、原則「http://localhost:3978/api/messages」と入力します。「Microsoft App ID」と「Microsoft App password」には、「.env」ファイルに記載されている同名の設定値をそれぞれ入力します。

接続情報を入力したら「Connect」ボタンを選択します。するとタブが切り替わり、ボットとのチャット画面が表示されます。画面の左半分がチャットのメッセージ表示画面で、右半分にその他の情報が表示されます。右下部には、エミュレーターのログが表示されています。このログ画面とチャット画面に、ボットとの接続時にボットから送信される「Hello and welcome!」というメッセージが表示されていれば接続に成功です。

チャット画面下部からメッセージを入力してみましょう。回答を得られそうなメッセージや反対にヒットしないメッセージなどを送信してみて、ボットの動作確認を行います。

いくつかメッセージを送信して、ボットが期待する動作をしていることを確認します。ボットをローカル環境で実行し、Bot Framework Emulatorで動作確認が行えることで、素早いデバッグを行うことが可能になることが分かるかと思います。
○修正したソースコードをAzure上に公開しよう

最後に、ここまでローカル環境で修正してきたボットアプリケーションをAzure上のBot Serviceに反映していきます。なお、ボットアプリケーションをローカルマシンからAzure上にデプロイするには、Azure CLIが必要になるのでインストールされていない場合は事前にインストールをして下さい。

ソースコードをAzureにデプロイする際は、zipファイル形式でアップロードする必要があります。ボットアプリケーションのプロジェクトのルートディレクトリ上で、全てのファイルを選択した状態でzipファイルに圧縮します。

ここまで準備ができたら、ターミナルを開き、Azure CLIを使ってアプリケーションをAzureにデプロイします。

ローカルで開発したボットアプリケーションをAzureにデプロイする

# Azureにログインする・・・①
az login

# デフォルトのサブスクリプションを設定する・・・②
az account set --subscription "<サブスクリプションID>"

# アプリケーションのzipファイルをAzureにデプロイする・・・③
az webapp deployment source config-zip --resource-group "<リソースグループ名>" --name "<Bot Serviceの名称>" --src <zipファイルのパス>

まずはAzure CLIをAzureにログインさせる必要があります(①)。コマンドを実行すると、Webブラウザ上で認証情報の入力が求められるので、これまで使用してきたものと同じAzureアカウントでログインします。ログインに成功すると、ターミナル上に「You have logged in.・・・」といったメッセージが出力されます。
次にAzure CLIのデフォルトのサブスクリプションを設定します(②)。Bot Serviceを作成したものと同じサブスクリプションを設定します。サブスクリプションIDが分からない場合は、Azureポータルの「サブスクリプション」メニューから調べるか、「az account list」コマンドで表示される「id」の値から取得することができます。
最後に、アプリケーションのzipファイルをデプロイするコマンドを実行します。デプロイ先となるBot Serviceの名称と、そのリソースグループ名、そしてzipファイルのパスをコマンドの引数に設定します。デプロイが終了するとターミナルにjsonが出力されるので、「complete」の値が「true」となっていることを確認します。
なお、このコマンドの実行には10分程度かかる場合があるので注意して下さい。

デプロイが完了したら、前回の記事で設定したSlackチャネルを使って動作確認をしてみましょう。Slackを開き、ボット用のチャンネルから質問を送信してみます。

図のように、質問に応じた回答が得られればAzureへのデプロイは成功となります。
○まとめ

今回は、QnA Makerを使ったQ&Aのナレッジベースの構築と、Bot Frameworkとの連携方法について説明しました。QnA Makerを使うことで、既存のドキュメントを有効活用して簡単にQ&Aのしくみを構築することができることが分かったかと思います。
次回は、リアルタイムWebサービスを実現するAzure SignalR Serviceについて紹介する予定です。

WINGSプロジェクト 秋葉龍一著/山田祥寛監修<WINGSプロジェクトについて>テクニカル執筆プロジェクト(代表山田祥寛)。海外記事の翻訳から、主にWeb開発分野の書籍・雑誌/Web記事の執筆、講演等を幅広く手がける。一緒に執筆をできる有志を募集中