こんにちは!ACSD松崎です。
前回の記事では、Llama HubのConfluence RoaderをGoogle Colab上で動かしましたが、 今回はそこで得た学びを活かしてConfluenceの内容に基づき回答してくれるSlack Botを作ろうと思います。
作成するアプリケーションの概要
- Slack Botの実装には、Bolt for Pythonを使います
- Slack Botのホスティングですが、今回はVMの上でDockerコンテナをDaemonとして動かす方式を採用します
- PWなどの秘匿情報は
.env
にて保持し、docker composeのenvironment
でDockerコンテナに渡します
- PWなどの秘匿情報は
- SlackBot ⇔ Slack Server間の通信はSocket Modeで実行します ※セキュリティ担保のため
アプリのデモ
予め以下のConfluenceページをConfluence Cloud上に用意します。
上記のページの情報をSlack Botに質問すると、ページに記載の情報を元にした回答が得られます。
作成手順
「作成するアプリケーションの概要」に記載の方針を元にSlack Botを作成した際のSlack Appの設定とソースコードを以下に記載します。
Slack Appの設定
OAuth & Permissions
->Bot Token Scopes
に以下を登録app_mentions:read
chat:write
- Event Subscriptions に
app_mention
を登録
Slack Botの実装コード
app.py
import json import os import openai from llama_hub.confluence.base import ConfluenceReader from llama_index import GPTVectorStoreIndex from slack_bolt import App from slack_bolt.adapter.socket_mode import SocketModeHandler # 環境変数から必要なConfig値を取得 # * Confluence Roaderの動作に際し別途CONFLUENCE_USERNAMEと # CONFLUENCE_PASSWORD をexportする必要があるので注意 app = App(token=os.environ["SLACK_BOT_TOKEN"]) openai.api_key = os.environ["OPENAI_API_KEY"] slack_bot_id = os.environ["SLACK_BOT_ID"] openai.api_key = os.environ["OPENAI_API_KEY"] @app.event("app_mention") def handle_mention(event, say): # Debug print(json.dumps(event,indent=2)) # event[text]には、メンションが含まれているので、メンションを削除する input_message = remove_slack_id_from_text(event["text"], slack_bot_id) channel = event["channel"] user_slack_id = event["user"] print("user_slack_id =>" + user_slack_id) thread_ts = event["ts"] channel = event["channel"] answer = query_engine.query(input_message) # say()の第1引数に渡せるよう、 # llama_index.response.schema.Response -> str にキャスト answer_str = str(answer) say(text=answer_str, thread_ts=thread_ts, channel=channel) # slack_idと\nは捨てる def remove_slack_id_from_text(text, slack_id): return text.replace(f"<@{slack_id}>\n", "") # アプリを起動 if __name__ == "__main__": # 読み込ませるConfluence Spaceとページの指定 base_url = "https://example.com/wiki" reader = ConfluenceReader(base_url=base_url) page_ids = [xxxxxx] # Confluenceページの取得とvector index化 print("Start to get Cofuence Doc") documents = reader.load_data(page_ids=page_ids) print("Start indexing") index = GPTVectorStoreIndex.from_documents(documents) # Query Engineの生成 print("Genarate Query Engine") query_engine = index.as_query_engine() # ソケットモードでSlack Appを開始 SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"]).start()
Dockerコンテナの定義
Dockerfile
FROM python:3.8-slim-buster WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . CMD [ "python", "./app.py" ]
compose.yaml
version: '3.8' services: python-gpt: build: . environment: - SLACK_BOT_TOKEN=${SLACK_BOT_TOKEN} - SLACK_APP_TOKEN=${SLACK_APP_TOKEN} - SLACK_BOT_ID=${SLACK_BOT_ID} - OPENAI_API_KEY=${OPENAI_API_KEY} - CONFLUENCE_USERNAME=${CONFLUENCE_USERNAME} - CONFLUENCE_PASSWORD=${CONFLUENCE_PASSWORD}
.env
SLACK_BOT_TOKEN=xoxb-xxx SLACK_APP_TOKEN=xapp-xxx SLACK_BOT_ID=xxx OPENAI_API_KEY=sk-xxx CONFLUENCE_USERNAME=matsuzaki@example.com CONFLUENCE_PASSWORD=xxx
requirements.txt
slack-bolt==1.18.0 slack-sdk==3.21.3 langchain==0.0.284 llama-hub==0.0.27 llama-index==0.8.22 nltk==3.8.1 openai==0.28.0
今後改良したい点
今回は、プロトタイプ目的でとりあえず動くことを目指しましたが、 今後以下の点を改良したいと考えています。
- GPT3.5ではなくGPT4を使う
- Confluenceページの取得&インデックス作成処理は、Dockerの外で行い、Dockerには永続化されたindexを起動時に渡すようにする
- queryの回答の際に、引用元のConfluenceページのURLを回答に含める
終わりに
ドキュメントを元に回答するBotは活用範囲が広くて良さそうですね! プライベートでNotionを使っているので、Notion対応verも別途作ってみたいと思いました。