Amazon BedrockとSlackによるRAG(検索拡張生成)構成

記事タイトルとURLをコピーする

サーバーワークスの村上です。

10月といえば一番に思いつくのがNBAシーズンの開幕ですよね。今期も脳死で課金します。

さて、このブログはAmazon BedrockとSlackを組み合わせた一例を紹介する記事です。

結論

使用イメージ

まずは動画で見ていただくと伝わるかと思います。

  • Slackのアプリをメンションすることで動くようにしました
    • Slack Bolt for Pythonを使っています
  • リプライがきて、どのモデルを使うか聞かれます
    • Claude、Jurassic-2、Titanが選べるように設定しています
    • RAGモードではAmazon Kendraを使って弊社のホームページを基に回答を生成します

ちなみにサバノミソニは弊社のイベントの名前なのですが、この動画ではホームページからの情報を基に回答できていますね。

ちなみにちなみに、単純にClaude v2にサバノミソニを聞いてみると、サバノミソニとは、サバとミソの交雑種のことを指します。とのことで、知らない情報は当然ながら答えられないです。

構成

構成はシンプルで、Slack上でアプリをメンションすると、Lambda function URLにリクエストが飛ぶようになっています。RAGモードではLambdaの通信先としてAmazon Kendraも加わります。

まとめ:Amazon Bedrockを使う理由

単一のAPIから複数のモデルが使える

ご存じのとおり今や基盤モデルの種類は増加傾向にあり、しかも「どんなケースでもこれを選べば間違いない」みたいな最適解はないのが現状かと思います。

引用:https://github.com/Mooler0410/LLMsPracticalGuide

そのような状況なので、今後1つの組織が複数の基盤モデルを使うことも当たり前になるのではないかと推測しますが、Amazon Bedrockというサービスを通じて複数のモデルが使えるのはかなりの利点かと考えます。

今回構築したアプリでも簡単に複数の基盤モデルを使えるのでかなり便利でした。

他のAWSサービスとの統合

今AWSを使っているなら、生成系AIはAmazon Bedrockが第一の選択肢です。

理由は他のAWSサービスとの親和性で、

  • IAMでの権限管理
  • CloudTrailでの証跡管理
  • CloudWatchでのパフォーマンス監視やログ監視

上記のような、今すでにやっていることをそのまま踏襲できるからです。

CloudWatchでどのような情報が見れるかは以下のブログで紹介しています。

blog.serverworks.co.jp

インフラの管理が不要など

Amazon Bedrockだけに限った話ではないですが、以下のような利点もあります。

  • インフラの管理が不要
  • 情報がモデルプロバイダー側に再利用されない
  • 閉域環境で利用可能

前提

Amazon bedrockとは?

再掲ですが、以下のブログをご参照ください。

blog.serverworks.co.jp

RAG(検索拡張生成)とは?

こちらも以下のブログで概要を紹介しています。今回はAmazon Kendraを使っています。

blog.serverworks.co.jp

各論

RAGを実現するためAmazon Kendraを使用

Amazon Kendraはここまでで紹介してきたように検索ができるサービスです。

キーワード検索ではなくセマンティック検索が可能で、端的に言うと、文字面での検索ではなく意味を汲み取った検索をしてくれます。

以下の記事の例が分かりやすいですが、例えば「パソコン トラブル」と検索して「PCトラブル対処法」というページがちゃんとヒットします(パソコンとPCが同義であると判断できる)。

aws.amazon.com

今回はLangchainのAmazonKendraRetrieverを使いました。

python.langchain.com

SlackのトークンはSSM Parameter Storeに保存

Slackの機密情報はAWS Systems Manager Parameter Storeに保存し、Lambda extensionで取得しています。

docs.aws.amazon.com

取得はハンドラー関数の中で行う必要がある点に注意が必要です。ハンドラー外に処理を書くと400エラーが出てしまいます。

過去の会話履歴について

ブログ執筆時点では、会話履歴を保持するためにLangchainなどは使っておらず、Slackからのイベントに含まれる情報を少し整形して基盤モデルに渡しています。

prev_messagesというdictionaryに人の発言とAIの発言を格納してプロンプトに含めるようにしました。

Langchainなどの使用は今後やっていきますが、以下のような実装でも会話履歴を踏まえた回答はできました。

# 抜粋です
# Slackのスレッド履歴から人のポストとAIのポストを分別
history = app.client.conversations_replies(channel=channel, ts=thread_ts)
prev_messages = {}
for i in range(0,len(history["messages"])):
    history_message = history["messages"][i]["text"]
    user = history["messages"][i]["user"]
    if user != "<アプリのユーザー名>" :
        # メンションの文字列は不要なので削除
        history_message = history_message.replace("<アプリのユーザー名>", "")
        prev_messages[f"Human_{i}"] = history_message
   else:
       prev_messages[f"Assistant_{i}"] = history_message
                    
# 'Human_'で始まるkeyを取得。直近のkeyに対応するvalueがユーザーの最後の入力
max_human_key = max((key for key in prev_messages.keys() if key.startswith('Human_')), default=None)
if max_human_key:
    input_message = prev_messages[max_human_key]
    del prev_messages[max_human_key]

さいごに

単一のAPIからClaudeやJurassicなど複数の基盤モデルを使うことができ、かなり便利でした。

冒頭に記載したとおり、今AWSを使っているなら、生成系AIの選択肢としてはAmazon Bedrockが良いと思います。

是非まずはPoCをやってみましょう。サーバーワークスがご支援します。

村上博哉 (執筆記事の一覧)

2020年4月入社。機械学習が好きです。記事へのご意見など:hiroya.murakami@serverworks.co.jp