【Azure】社内チャットでよく使われるteamsをインタフェースとしてRAGチャットボット構築してみた
はじめに
世の中の企業ではコミュニケーションツールとしてさまざまなツールが使われていますよね。
その中で今回ビジネスチャットとして約67%のシェア率を誇るMicrosoft Teamsをインタフェースとして利用したRAGのカスタマーチャットボットを構築しましたのでこちらの方法について詳しく記載いたします。
また、AWS環境やSlackをインタフェースとする際のRAGチャットボット構築に興味がある方はこちらの記事にて書いておりますのでぜひご覧ください!
RAGとは??
RAG(Retrieval-Augumented Generation)という手法をご存知でしょうか?
ChatGPTをはじめとする通常のLLM(Large Language Models)ではWeb上に公開されている、学習に利用されているデータからしか回答ができません。生成AIを企業で活用する際には、社内データに回答可能なチャットボットを構築したいというモチベーションが高く、その際にはRAGという技術が利用されます。
特に社内ドキュメントなど公になっていないデータを用いた回答を行いたい場合に関してはRAGが有効となります。
想定する読者
- RAGの理解ができているがインタフェースとしてteamsを利用したことのない人
- 普段AzureやTeamsを使用しており、自分もRAGチャットボットを構築したいという方
- RAGを使ったシステムの構築の仕方を知りたい方
この記事での到達目標
- TeamsをインタフェースとするRAGチャットボットの作成
構成
今回のシステムは以下の主要なコンポーネントで構成されています
Microsoft Teams
- ユーザーとシステムのインターフェースとして機能。
- ユーザーはTeams上で質問を送信し、システムからの回答を受け取る。
Azure Bot Service
- Teams からのメッセージを受け取り、質問を処理して適切なバックエンドサービスにルーティングする役割。
- Azure App Service を通じて、バックエンドの処理フローを制御します。
Azure App Service
- プロジェクトの中核となるロジックをホストする役割。
- Azure AI-Search を呼び出して、ユーザーの質問に関連する情報を検索。
- 検索結果を基に Azure OpenAI (GPT-4o) を活用して回答を生成。
- 最終的な回答を Azure Bot Service 経由でユーザーに返答を行う。
Azure Container Registry
- プロジェクトのアプリケーション(Docker コンテナイメージ)をホスティング。
- Azure App Service にコンテナ化したアプリケーションをデプロイするために使用される。
Azure AI-Search
- ユーザーの質問に関連する情報を検索するための検索サービス。
- データは Azure Storage Account に格納されている。
Azure Storage Account
- Azure AI-Search にて使用するデータソースとして機能。
- ここに格納されたデータを用いて回答を生成。
Azure OpenAI
- 検索結果を基にLLM(今回はGPT-4o)を使用して、回答を生成。
- AI-Searchの段階ではドキュメントベースの文章だったものを回答用に生成する。
今回使用するデータ
今回はオリジナルのデータを用いて回答していると判断するためにダミーデータを作成し使用しております。
また、作成に関してはGPTを使用しました、
作成したダミーデータ
# Dummy PC マニュアル
## 目次
1. **製品概要**
2. **セットアップ手順**
3. **基本操作**
4. **トラブルシューティング**
5. **サポート情報**
---
## 1. 製品概要
**Dummy PC**は、日常の作業やエンターテイメントを快適にサポートする高性能なPCです。以下は主な特徴です:
- **CPU**: Quad-core DummyChip 3.5GHz
- **メモリ**: 16GB DDR4
- **ストレージ**: 512GB SSD
- **ディスプレイ**: フルHD 15.6インチ
- **OS**: DummyOS 1.0
> 注意: 詳細な技術仕様については、製品同梱の技術仕様書をご参照ください。
>
---
## 2. セットアップ手順
### 2.1 内容物の確認
1. Dummy PC本体
2. ACアダプターと電源コード
3. ユーザーマニュアル
### 2.2 初期設定
1. **電源を接続**:
ACアダプターをPCに接続し、電源に差し込みます。
2. **電源を入れる**:
PCの右上にある電源ボタンを押して起動します。
3. **OSのセットアップ**:
初回起動時に表示されるガイドに従って、以下を設定します:
- 言語と地域
- Wi-Fi接続
- アカウント情報
4. **アップデートの確認**:
[設定] → [更新とセキュリティ]からシステムアップデートを確認してください。
---
## 3. 基本操作
### 3.1 電源管理
- **スリープモード**: スタートメニューから「スリープ」を選択。
- **シャットダウン**: スタートメニュー → 「電源」 → 「シャットダウン」を選択。
### 3.2 ファイル操作
- **新しいファイルを作成**:
1. デスクトップまたはフォルダーを右クリック。
2. 「新規作成」を選択し、必要なファイルタイプを選びます。
- **ファイルの削除**:ファイルを右クリックして「削除」を選択します。
### 3.3 インターネットブラウジング
1. スタートメニューから「Dummy Browser」を起動します。
2. アドレスバーにURLを入力し、「Enter」キーを押します。
---
## 4. トラブルシューティング
### 4.1 起動しない場合
1. **電源コードの確認**: ACアダプターが正しく接続されているか確認します。
2. **バッテリーの状態**: バッテリー残量があるか確認してください。
### 4.2 Wi-Fiに接続できない場合
1. **Wi-Fiスイッチの確認**: デバイス右側のWi-Fiスイッチがオンになっているか確認します。
2. **再起動**: PCとルーターを再起動してみてください。
### 4.3 サポートへの連絡が必要な場合
- Dummy PCサポートセンター: **0123-456-789**
- 営業時間: 平日 9:00~18:00
---
## 5. サポート情報
公式サイト: [www.dummypc.com](http://www.dummypc.com/)
FAQページ: www.dummypc.com/faq
ソフトウェアアップデート: www.dummypc.com/update
---
**注意**: このマニュアルは定期的に更新される可能性があります。最新版は公式サイトでご確認ください。
ロジックの作成
今回はPythonのFastAPIというフレームワークを用いて構築しました。
内容としてはTeams appに送られた質問を受け取り、AI-Searchにて関連する情報を検索。また、Azure OpenAIにてAI-Searchで検索された情報を元に回答文を作成し、再度Teams appに回答の情報を渡す処理をしています。
環境変数の説明
-
BOT_APP_ID
:Bot Serviceの管理画面にて確認できるID。ポータル上ではMicrosoft App IDとの表記。 -
BOT_APP_PASSWORD
:bot Service管理画面にて確認できるパスワード。ポータル上ではクライアントシークレットと表記。 -
AZURE_OPENAI_ENDPOINT
:Azure OpenAIのAPIにリクエストを送るためのエンドポイントを指定する。このエンドポイントは、Azure AI StudioのOpenAIで確認できます。 -
AZURE_OPENAI_API_KEY
:Azure OpenAI サービスを利用するための認証キー。このキーは、Azure AI Studioで取得します。 -
AZURE_SEARCH_ENDPOINT
:Azure AI-Search にアクセスするためのエンドポイントを指定します。このエンドポイントを使用して、検索クエリを送信し、結果を取得します。 -
AZURE_SEARCH_API_KEY
:Azure AI-Search を呼び出す際の認証に使用する。
コード全文
import os
from fastapi import FastAPI, Request
from botbuilder.core import BotFrameworkAdapter, BotFrameworkAdapterSettings, TurnContext
from botbuilder.schema import Activity, ActivityTypes,HeroCard, CardAction, Activity
from botbuilder.schema import HeroCard, CardAction, Attachment
import requests
import json
import re
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# 環境変数から設定を取得
AZURE_SEARCH_ENDPOINT = os.environ.get("AZURE_SEARCH_ENDPOINT")
AZURE_SEARCH_API_KEY = os.environ.get("AZURE_SEARCH_API_KEY")
AZURE_OPENAI_ENDPOINT = os.environ.get("AZURE_OPENAI_ENDPOINT")
AZURE_OPENAI_API_KEY = os.environ.get("AZURE_OPENAI_API_KEY")
BOT_APP_ID = os.environ.get("BOT_APP_ID")
BOT_APP_PASSWORD = os.environ.get("BOT_APP_PASSWORD")
# Bot Framework Adapter設定
bot_settings = BotFrameworkAdapterSettings(app_id=BOT_APP_ID, app_password=BOT_APP_PASSWORD)
adapter = BotFrameworkAdapter(bot_settings)
# FastAPIアプリケーション
app = FastAPI()
# ヘルスチェック
@app.get("/")
def health_check():
return {"status": "ok"}
# Teamsからのメッセージ処理エンドポイント
@app.post("/api/messages")
async def messages(request: Request):
body = await request.json()
activity = Activity().deserialize(body)
auth_header = request.headers.get("Authorization", "")
response = await adapter.process_activity(activity, auth_header, bot_logic)
return response
# メインロジック
async def bot_logic(turn_context: TurnContext):
if turn_context.activity.type == ActivityTypes.message:
user_query = turn_context.activity.text.strip()
# Azure Cognitive Searchでドキュメント検索
try:
search_url = f"{AZURE_SEARCH_ENDPOINT}/indexes/dummypcindex/docs/search?api-version=2021-04-30-Preview"
headers = {"Content-Type": "application/json", "api-key": AZURE_SEARCH_API_KEY}
payload = {
"search": user_query,
"top": 10,
"queryType": "full",
"searchMode": "any"
}
response = requests.post(search_url, headers=headers, json=payload)
response.raise_for_status()
search_results = response.json()
documents = []
for doc in search_results.get('value', []):
title = doc.get('title', 'タイトル不明')
uri = doc.get('url', 'URI不明')
excerpt = doc.get('content', '抜粋なし')
documents.append(f"タイトル: {title}\nURI: {uri}\n抜粋:\n{excerpt}")
context = "\n".join(documents)
except Exception as e:
await turn_context.send_activity(f"ドキュメント検索中にエラーが発生しました: {str(e)}")
return
if not context:
await turn_context.send_activity("関連する情報が見つかりませんでした。")
return
# Azure OpenAI Serviceで回答生成
try:
openai_url = AZURE_OPENAI_ENDPOINT
headers = {
"Content-Type": "application/json",
"api-key": AZURE_OPENAI_API_KEY
}
payload = {
"messages": [
{"role": "system", "content": "あなたはユーザーを助けるアシスタントです。追加情報から質問に答えてください"},
{"role": "user", "content": f"質問: {user_query}\n追加情報: {context}"}
],
"max_tokens": 500,
"temperature": 0.0
}
response = requests.post(openai_url, headers=headers, json=payload)
response.raise_for_status()
ai_response = response.json()
generated_answer = ai_response.get("choices", [{}])[0].get("message", {}).get("content", "回答生成に失敗しました。")
except Exception as e:
await turn_context.send_activity(f"回答生成中にエラーが発生しました: {str(e)}")
return
await turn_context.send_activity(generated_answer)
hero_card = HeroCard(
text="役に立ちましたか?",
buttons=[
CardAction(
type="imBack",
title="Yes",
value="Yes"
),
CardAction(
type="imBack",
title="No",
value="No"
)
]
)
# HeroCardをAttachmentとして送信
attachment = Attachment(
content_type="application/vnd.microsoft.card.hero",
content=hero_card
)
await turn_context.send_activity(
Activity(
type="message",
attachments=[attachment]
)
)
今回は回答生成の他に、回答が役に立ったかユーザにフィードバックをもらうことができるような実装にしております。
こちらは別途「役に立ちましたか Yes/No」のボタンカードを送信することによって実装しております。
RAGを実用化する際に本当に役に立っているか、そのデータ収集がとても大事になるため今回このような実装にしております。
Container Registryへのデプロイ
実際に作ったロジックをAzureにアップロードするためにContainer Registryのセットアップをしていきます。
- リージョンは「Canada Central」を指定
- 名前・サブスクリプション・リソースグループに関しては任意の物を入力
- Pricing planはStandardを指定
以上の条件にて作成しました。
詳しいセットアップ手順
検索バーにて「Container Registry」と入力すると出てきますのでこちらから作成画面に移ります。
作成に関してはリソースグループを管理しやすいように今回のプロジェクト用のものを指定、ユニークな名前を入力した以外はデフォルトのままで作成いたしました。
また、リージョンに関しては使用できないサービスがある可能性があるために今回「Canada Central」を使用しております。
また、作成しましたらAzure CLI経由で作成したコンテナをアップロードしておきます。
App Serviceのセットアップ
先ほどのContainer Registryに上げたコンテナをホスティングするためにApp Serviceにデプロイします。
- 名前・サブスクリプション・リソースグループ
- 「コンテナ指定」にて先ほど作成したContainer Registryを選択
- 価格プランに関してはBasic B1
以上のもの以外はデフォルトの値を指定しております。
詳しいセットアップ手順
Azure Portalのメニューから「Webアプリ作成」を選択、App Serviceのリソースを作成し、必要情報を入力していきます。
こちらは「インスタンスの詳細」にてコンテナを選択し、次ページのコンテナ選択項目で「Azure Container Registry」を選択、また先ほどアップロードしたコンテナを選択いたします。
今回、そのほかの選択肢に関してはデフォルトの物を使用しております。
Azure OpenAIの設定
こちらもAzure Portalからリソースの作成を行なっていきます。
- 名前・サブスクリプション・リソースグループは任意の物を入力
- PricePlan : Standard S0
- モデルに関しては4oを指定
- リージョンに関しては「Canada Cendral」を指定
以上の条件で作成いたしました。
詳しいセットアップ手順
Azure Portalの検索バーにて「Azure OpenAI」と検索し、リソースの作成をしていきます。
こちらでは前述の通りの条件を入力していきます。
また、作成が終わりましたらAzure AI Foundlyに移動しモデルをデプロイ(使用できる状態)していきます。
モデルに関しては今回GPT-4oを選択。制限などは任意の値を入力しモデルをデプロイします。
作成が終わりましたら、Azure AI Foundlyで見ることができるエンドポイントとAPIkeyをそれぞれ環境変数に設定していきます。
Azure Storage Accountの設定
今回は以下の条件で作成しております。
- パフォーマンス:Standard
- 冗長性(レプリケーション):LRS
- 匿名アクセス:有効
- アクセス層:ホット
詳しいセットアップ方法
検索バーにて「Stofage Account」と入力し、条件入力画面に移動します
同じように上記の条件のように情報を入力していきます。
また、リソースの作成が終わりましたら、コンテナを作成し実際にデータを追加していきます。
今回はダミー製品のデータを渡します。
Azure AI-Searchの作成
RAGの主要部分となる検索部分に関して作成していきます。
こちらは
- 名前・サブスクリプション・リソースグループh任意の物を入力
- 価格レベル:standard
- レプリカ×パーティション:1×1
以上の条件で作成いたしました。
詳しいセットアップ方法
検索バーにて「Search」と入力すると出てくる「Azure AI Search」を入力し、情報入力画面に移動していきます。
また、上記の条件で入力を進めていきます。
また、リソースの作成が終わりましたら、先ほどアップしたデータを使用してインデクサーの作成と、インデックスの作成も忘れずに行います。
こちらで作成されるエンドポイントとAPIkeyを環境変数に設定しておきます。
Azure Botのセットアップ
最後にボットの作成を行なっていきます。
こちらも名前・サブスクリプション・グループリソース以外はデフォルトのまま作成いたしました。
詳しいセットアップ方法
検索バーに「Azure Bot」と入力し、条件入力画面へいきます。
また、条件のように入力を進めていきます
また、終わりましたらリソース管理画面の「チャンネル」から今回インタフェースとして利用するTeamsを追加しておきます。
忘れずにIDとパスワードを環境変数に設定、またApp Serviceのエンドポイントを設定しておきます
また、ボットをTeamsにダウンロードするためのmanifestファイルを作成し、実際にTeamsにダウンロードします。
この際、manifestファイルはTeams Developer Portalを使用すると簡単に作成ができます。
このファイルをZIPに固め、Teamsアプリからインストールすることでアプリをダウンロードすることができます。
ここまでで構築が完了です
結果
実際に作成したアプリを動かしてみます。
アプリに「DummyPCの製品概要に関して教えて」と聞くと以下のような返答を受け取ることができました
上記のように実際の回答に付随して、どこから情報を参照しているのかを記述させることも可能です!
また、そのほかの質問で「初期設定の方法を教えて」と聞くと以下のような返答を受け取ることができました
ダミーPCは今回のために生成した架空の製品なので、実際に今回格納したダミーデータを用いて回答を生成していることが確認できます。
まとめ
RAGを使用することで今回のように、使い慣れたチャットアプリをインタフェースとした特定の情報に関わるカスタマーチャットボットを作成することができます。
今回はダミーデータを使用しましたが、実際にオープンにはなっていない社内情報などを使用すればその情報に基づいたカスタマーチャットを作成することも可能です
これにより、企業は顧客対応や内部サポートの効率化を図ることができるのではないでしょうか。
Discussion