👁️🗨️
Slackで社内文書検索 4/4回(任意のLLMによる回答生成編)
開発の流れは以下の通りです。
開発の流れ
- Slack APIアプリの作成と設定
- Vertex AI Searchのアプリの作成とデータストアの自動更新
- Slackからのコマンドとメッセージの受信
- 任意のLLMによる回答生成
今回は任意のLLMによる回答生成について説明していきます。
Cloud Functionsのファンクションの作成やコードだけが見たい方はこちら
概要
今回の見出しが任意のLLMとなっているのは、コマンドによってLLMを指定して回答を生成するようにしているからです。コマンドは「Slackで社内文書検索 1/4回(Slack APIアプリの作成と設定編)」の記事で示しましたが、再度示しておきます。
コマンド | 説明 | 備考 |
/palm2 | 回答生成に使うLLMモデルを「PaLM2」にする。 | コマンドに続けて質問文を送る。 |
/gpt-3 | 回答生成に使うLLMモデルを「GPT-3.5」にする。 | コマンドに続けて質問文を送る。 |
/gpt-4 | 回答生成に使うLLMモデルを「GPT-4」にする。 | コマンドに続けて質問文を送る。 |
回答生成では、Vertex AI Searchのアプリを用いて、メッセージ(質問)に対する関連資料を検索し、任意のLLMモデルを使ってその資料の内容を参考に質問に関連する回答を生成します。
回答生成の処理の概要を以下に示します。
1. イベントを受け取る
ここではVertex AI Searchのアプリを使って、質問に関連のある資料を検索します。
今回はLangChainのRetrieversのGoogleVertexAISearchRetrieverを用いてVertex AI Searchの検索機能を実装しました。
GoogleVertexAISearchRetrieverを呼び出す際にたくさん引数を渡しますが、今回はmax_documentsに注目して説明します。その他の引数の説明についてはこちらをご覧ください。
max_documentsは検索結果として表示する資料の数を指定するものになります。今回は1にしていますが、データストアが大規模になるにつれ、関連資料が増えてくると考えられるので、将来的には複数の資料を引用して回答生成することも視野に入れています。
上記のresultには参考資料のURLやその資料の要約などが含まれていますが、要約の精度があまり良くなかったので、今回はURLのみを利用します。
また、documentではURLから資料の名前(例:○○.pdf)を取り出しています。
3. 資料をロードする
ここでは、PaLM2とGPT-3.5、GPT-4の3つのLLMで回答を生成します。
今回は、LangChainのChainsを用いて回答を生成します。回答生成の処理は以下のようになります。PaLM2ではStuff、GPT-3.5、GPT-4ではMap Reduceという方法をとります。
回答生成の処理
- PaLM2
PaLM2は試作段階であり、GPT-3.5やGPT-4に比べ、出力の大きさが小さい上に、クオリティも低い。(2023/10/30現在)
そのため、PaLM2はStuffDocumentsChainを用いて、テキストを参考に回答生成する簡単な処理になっています。
StuffDocumentsChainを用いた理由としては、StuffDocumentsChainはドキュメントを複数プロンプトに埋め込めるという特徴を持っているので、将来的に回答生成に利用する資料の容量が増えたときに対応が楽になるからです。
The stuff documents chain ("stuff" as in "to stuff" or "to fill") is the most straightforward of the document chains. It takes a list of documents, inserts them all into a prompt and passes that prompt to an LLM.This chain is well-suited for applications where documents are small and only a few are passed in for most calls.
以下にコードを示します。
今回ChatVertexAIのモデルはchat-bisonを用いましたが、目的に応じてモデルも変更できます。モデルの一覧は以下のサイトをご覧ください。
- GPT-3.5とGPT-4
GPT-3.5、GPT-4では回答生成に、load_summarize_chainを用います。
load_summarize_chainを用いることで、Map Reduceを簡単に実装できます。
処理の流れを簡単に説明します。まず、参考資料を分割して、それぞれの資料から回答生成に必要そうな情報を抽出します(下のコードのPROMPT)。次に、分割された資料から抽出した情報から回答生成を行います(下のコードのCOMBINE_PROMPT)。
以下にコードを示します。
回答生成と返信をするファンクション
以上の説明を踏まえてファンクションを作成します。
今回作成するファンクションの作成方法は前々回の記事と変わらないので、こちらを参照してください。ただし、前回の記事と異なる部分があります。その部分は以下に従ってください。
変更内容
- トリガー
- HTTPS
- 未認証の呼び出しを許可を選択
- トリガーの追加
- トリガーを追加を選択します。
- Pub/Subトリガーを選択します。
- イベントで「google.cloud.pubsub.topic.v1.messagePublished」を選択します。
- Cloud Pub/Sub トピックを選択してくださいで前回の記事で作成したトピックを選択します。
- トリガーを保存を選択します。
説明

- ランタイム環境変数
- 以下の4つを追加
- Slack APIのページに移動
- 作成したアプリを選択
- サイドバーのOAuth & Permissonsを選択
- OAuth Tokens for Your WorkspaceのBot User OAuth Tokenをコピー
- Slack APIのページに移動
- 作成したアプリを選択
- サイドバーのBasic Informationを選択
- App CredentialsのSigning SecretのShowを押す
- Slack APIのページに移動
- 作成したアプリを選択
- サイドバーのIncoming Webhooksを選択
- Webhook URLs for Your WorkspaceのWebhook URLから今回のSlack APIアプリのインストール先のチャンネルに対応したWebhook URLをコピーします。
名前 | 値 |
PROJECT_ID | Google Cloud のプロジェクトID |
BUCKET_ID | GCSのバケット名 (gs:// は不要) |
DATA_STORE_ID | Vertex AI SearchのアプリのデータストアのID |
OPENAI_API_KEY | OPENAIのAPIキー |
SLACK_BOT_TOKEN | アプリの認証に用いるトークン |
SLACK_SIGNNG_SECRET | リクエストの認証に用いるサイン |
WEBHOOK_URL | Slackのワークスペースのチャンネルに返信するのに用いる |
SLACK_BOT_TOKEN
SLACK_SIGNNG_SECRET
WEBHOOK_URL
- main.py
code
- requirements.txt
code
- エントリポイント
- send_slack_messageに変更
以上でファンクションの作成は終了です!
回答のクオリティについては、PaLM2はVertex AI Searchのアプリのデータストアの中の資料にない内容を質問するとハルシネーションが起きてしまいました。
また、PaLM2は出力の大きさが比較的小さいため、GPT-3.5やGPT-4に比べ、ざっくりとした回答になりました。
GPT-3.5、GPT-4に関しては、申し分ないクオリティの回答を生成する上に、私が行った実験の中ではハルシネーションは起こしませんでした。