AWS Bedrock のナレッジベースを使ったRAGを検証

# はじめに
　これまで、個人的な実験として、Google Colab を使ったマルチモーダルの実験（[Google AI Gemini APIを使ってマルチモーダルを体験してみた](https://qiita.com/tech-nami/items/27c483c1d412a5284a38)）や、ファインチューニングの実験（[Google AI Gemini APIを使ってファインチューニングを実施してみた](https://qiita.com/tech-nami/items/bf8aa1602123e0e44a37)）、仕事では、Azure の Document Intelligence を用いた RAG システムの PoC 等を行ってきておりましたが、AWS でも AI を検証してみたく、この度 Bedrock を使っての RAG について調べてみました。他の記事なども参考にしつつ、自分なりに色々実験してみましたので、ご参考にしていただけると嬉しいです。（今回は [GoogleColabでPythonを使ってクラス成績を可視化してみた](https://qiita.com/tech-nami/items/55507c0b5781d60ca687)で使った Excel のシートを RAG として読み込ませようと思います）

# Bedrock とは
　まずは Bedrock について簡単に説明します。Bedrock は、AWS において生成AIアプリケーションを構築・スケールするためのフルマネージドサービスです。様々な基盤モデル（FM）を利用でき、テキスト生成、画像生成、チャットボット作成など、多岐にわたるAI機能を提供します。

参考：Bedrock の初期画面
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/8e7b90cc-202c-4928-80c4-2a1075d4634a.png" width=100%>

# RAG とは
　RAG（Retrieval-Augmented Generation：検索拡張生成）は、大規模言語モデル（LLM）の性能を向上させるための技術の一つです。LLMは膨大なデータで学習していますが、特定の情報や最新情報については知識が不足している場合があり、誤った情報を回答する（ハルシネーション）ことがあります。RAGは、LLMが質問に答える前に外部のデータベースや知識ベースから関連情報を検索し、その情報を基に応答を生成することで、より正確で信頼性の高い回答を可能にします。

# ナレッジベースとは
　AWS Bedrock のナレッジベースは、生成 AI アプリケーションにおける検索拡張生成 (RAG) のワークフロー全体を効率化するためのフルマネージド機能です。
　後述しますが、私が触ってみた感想としては、RAG データの保管元（S3等）の指定や、検索データベース(Aurora等）の利用が簡単にできる様になっており、大変便利だなと感じました。

# ナレッジベースを使った RAG 検証の準備
　早速ですが、ナレッジベースを使って RAG を検証してみましょう。
①RAG 用の対象文書の準備
　まずは RAG の情報元を格納するため、対象文書を用意し、対象文書を S3 に保存します。
　（対象文書は、PDF、JPEG、Word、Excel、PDF文書などを適宜用意してください）
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/3fbaa670-7da1-4732-92da-16d462c4bf0d.png" width=100%>
　「パケット作成」をクリックします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/07e074e0-4fb5-4967-8e2f-7cc6a82136ce.png" width=100%>
　パケット名を入力します。（その他の項目はデフォルトのまま）
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/cf55a0e8-72a2-4109-b8c1-321d7feb1c68.png" width=100%>
　「パケットを作成」をクリックします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/c892aaa6-f536-4f2a-bba9-a9dc72e0ee52.png" width=100%>

 これで S3 のパケットが作成されました。続けて S3 に RAG の対象文書を格納します。
　パケットの名前（上記例では rag-test-1234567890）をクリックします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/d3f4238e-1410-4acd-b0e2-3da78726e273.png" width=100%>

 「アップロード」をクリックします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/4e8d3378-1669-4cee-94b9-8bcaa9077b4b.png" width=100%>

 「ファイルを追加」をクリックします。
　ファイルを指定するダイアログが出てきますので、RAG 対象文書を指定します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/a3d05a80-0a70-4bf3-987d-2bb0223efe32.png" width=100%>

　ローカルのデスクトップ等からファイルを選択して、「アップロード」をクリックします。
　ファイルを指定するダイアログが出てきますので、RAG 対象文書を指定します。
　アップロードが完了すると、
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/4b4638b5-40ac-46d3-be96-b2be5526ee8a.png" width=100%>
　のようなメッセージが表示されます。
　これで、RAG 対象文書の準備ができました。いよいよ Bedrock の設定です。

②Bedrock ナレッジベースの設定
　Bedrock の ナレッジベースの準備を行います。
　Bedrock の初期画面より、「ナレッジベース」を選択します。
 
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/8f1bb0a8-e1c3-4250-867a-c4e1dd8869ea.png" width=100%>

　続けて、「Create」→「Knowledge Base with vector store」を選択します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/cecbaf74-1799-4bd9-8950-f1daec025cf8.png" width=100%>

　ここからは、ウィザード的な画面になり、次のステップを実施していきます。
　ステップ 1：ナレッジベースの詳細を入力
　ステップ 2：データソースを設定
　ステップ 3：埋め込みモデルを選択し、ベクトルストアを設定する
　ステップ 4：確認して作成

　ステップ１では「ナレッジベース名」や「データソース（S3）」なども自動入力してくれているので、そのまま「次へ」で大丈夫です。

　ステップ２では「データソース名」などは自動入力してくれているので、①でファイルをアップロードした S3 のバケットを選択します。「S3を参照」で、バケット選択画面が表示されます。
 
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/5f28b838-0e53-4859-b086-48e2035ca196.png" width=100%>

　S3 のバケットを選択（チェック）して、「選択」でバケット選択が完了します。
 
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/8286c61c-a39b-4333-a6f4-1d462eb9e97e.png" width=100%>

　なお、このデータソースは、最大５つまで設定できると記載されていますので、複数の場所にあるS3バケットを指定できる様です。
　また、S3 以外に、「Web Crawler - Preview」という選択肢もあり、Webクロールして RAG データとして使うこともできるようです。（これは追って調べてみたいと思います）

　また、データソース毎に、そのデータソースの「Parsing strategy（解析戦略）」と、「チャンキング戦略」が選択できます。（今回はいずれもデフォルトを使っています）
 　＋αの料金を払うことで、より精度の高い RAG を構築できそうです。ので、こちらも調べてみたいと思います。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/8ca8da3a-ad35-4c52-aa12-cb9c8ee9e40e.png" width=100%>

　なお、チャンキングについては、下記の選択肢があります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/78c6dfcc-99a1-4db0-a104-54853caa4975.png" width=100%>

　ステップ３では、「埋め込みモデル」と「ベクトルストア」を選択します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/d924654c-e967-4f24-96d6-ed49300d9dae.png" width=100%>

　「モデルを選択」では、日本語対応であり、精度も高いということで、今回は「Cohere」の「Embed Multilingual V3」を選択しています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/45b71114-9e7a-4d16-a971-df369920a0a3.png" width=100%>

　「ベクトルストア」では、デフォルトの「Amazon OpenSearch Serverless」を選択しています。（Auroraも含めて、Serverless の時代を感じます）
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/db5fe397-ccb6-4780-8527-c360e27b7f03.png" width=100%>
※OpenSearch Serverless より、Aurora Serverless の方が安価なようです。

　ステップ４は、確認だけですので、確認の上「ナレッジベースを作成」を行います。
 
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/b160a793-bb51-4bc2-bf6a-82fbf76e9532.png" width=100%>

　かなり時間がかかりますので、しばらく休憩するのがお薦めです。^^
　（私の環境では、10分程度で完了しました）

　③いよいよ ナレッジベース で問い合わせを実施！
　　ナレッジベースが作成されると、次の画面になりますので「モデルを選択」します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/3b7ae08d-9979-418e-affb-40c4745cb77a.png" width=100%>

　ここで、モデルのリストが表示されますが、モデルが有効になっていません！
　「アクセスをリクエスト」リンクを押して、モデルを有効にする必要があります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/1cac8757-2ce8-4021-a9e2-e84a8b532d54.png" width=100%>

　使いたいモデルを選択して、有効化するのですが、今回は「すべてのモデルを選択する」としています。 

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/9f93c558-8015-40bf-b9ab-0b60db5b4198.png" width=100%>

　下記の様なリストが表示されますので、一番下の行まで行き「次へ」としてください。
 　（今回の画面コピーでは「次へ」が見えてませんのでご了承ください）

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/963903ba-e940-4caf-9ed3-d971aa9d119f.png" width=100%>

　続けて確認画面が表示されるので「送信」を押すと有効化ができます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/cbf98312-648f-4e67-b83e-a8d356772ada.png" width=100%>

 　モデル選択画面に戻ると、モデルが選択可能になっていますので、モデルを選択して「適用」してください。
  
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/eefb5b21-32d1-429c-83aa-e99732c98bc3.png" width=100%>

　※ここで、「3.推論」のところで、「推論プロファイル」というのを選択しています。
 　モデルによっては、
  
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/5e7e5d41-1ad3-4bd4-ac51-d8dae6385187.png" width=80%>

 のように、「オンデマンド」が選択できるのですが、私の環境でオンデマンドを使うと、

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/42f93060-8e7b-4647-b245-a8a8f175d0e4.png" width=40%>

 の様なエラーとなってしまいました。
　「オンデマンド」の方が安価で利用ができそうなのですが、「推論プロファイル」の方が、リクエスト制限などによる不具合を少なくできると判断しました。
　（こちらはもう少し調べてみようと思います）

　続いて、データソースの同期を行います。まずは「データソースに移動」を押してください。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/e46f1cc9-d6c2-4e33-9e37-81edd92ecc3e.png" width=100%>

　すると画面の中央あたりに、データソースが表示されるので、以前に作成したデータソースを選択（チェックボックスをチェック）します。

 <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/f5952222-03a8-480e-8150-93a61d7665b6.png" width=60%>

　下の様に同期ボタンなどが表示されるので「同期」ボタンを押します。
　（同期は忘れがちなので、もしうまくいかないな、と思ったときは「同期」を疑ってみてください）
 
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/5f87d32f-8b2e-485d-922f-87d852972480.png" width=60%>

　少しの間、下記が表示されます。（RAG に入れるデータの量により時間が変わりますが、少量であれば数秒～１分以内で終わります）
 
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/bd28e450-45b8-4540-b978-56a0e480715d.png" width=60%>

　同期が終わると、下記の様な画面になり、いよいよ確認ができる状態になりました。
 
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/e0dc122c-8bc2-41b2-933a-c7d2035934c8.png" width=100%>

# ナレッジベースを使って RAG を検証
　早速 RAG の精度がどのようなものか検証してみましょう。
　今回入力したのは、以前に使ったテストデータですので、それに対して質問してみました。

　まずは簡単な質問から実施してみましょう。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/007e143b-a40d-4cd1-b4b4-ae2fd7e52007.png" width=60%>

　名前が呼び捨てですが^^;、なかなか調子が良いので、少し難しめな質問をしてみました。
 
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/32824aba-e3f5-4394-8328-477a08b51d9f.png" width=60%>

　・・・修正前の記事で正解と書いてしまったのですが、平均点はちょっと違ってました。
　原因を調べようと思い、「ソースの詳細を表示」してみたところ、

　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/6324065d-8bbb-475b-b009-8721d31a0934.png" width=60%>

　の様にチャンクが２つに分かれてしまっていることが判りました。
　平均点は全体が見れないと算出できないので、これが原因ではと考え、ナレッジベースのチャンクの設定を「チャンクなし」の様に変えて、再作成してみました。
 
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/c1b4934b-7195-4d20-bae7-b657ab701d4f.png" width=80%>

　この結果、下記の様にソースチャンクを１つにすることはできました。

　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/3df1c7e5-1d43-45d1-b90e-e1505a3fbaf2.png" width=60%>

　そして平均点も正解！と言いたいところですが、どういうわけか平均点は、
 
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/5763fd3b-66cb-477a-ba57-2add416eef2b.png" width=60%>

　となり、Excelで計算した平均値（56.8）とは異なる結果となりました。
　（こちらについても、継続して検証をしてみようと思っております）
　なお、データ全体に対する質問については難しかったですが、

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822494/bce619ee-4f37-48df-b1fc-90c50067f6f3.png" width=60%>

　のような行に対する質問などについてはすべて正解が得られました。

# コストについて
　気になるコストについてですが、正直なところ、予想よりも少なかった感じです。
　今回、当初 OpenSearch Service を使っていたのですが、それが一番大きく、とはいえ 3 ドル程度、ちょっと高くなるかもと考えて、途中から Aurora Serverless を使ったので、それが概ね 1 ドルちょっとでした。
　他の AI 系リソースは、今回の検証程度であれば、ほぼ無視できる金額でした。
　実は今月末まで、無料枠が適用されているので、そのおかげかもしれませんが、ご参考まで。
　たまに AWS セミナーなどで、アンケートに答えると xx USD 分のクレジットが配布されたりしますので、それを使えば検証には十分な感じです。
 （注：クレジットはあくまで、AWS の提供するサービスの範囲となります。今回利用した Anthropic などの他ベンダのサービスは Marketplaceの料金となり、実費となりますのでご注意ください）

# まとめ
　今回は「AWS で Bedrock の ナレッジベース を使って RAG を検証」というテーマで、以前に [GoogleColabでPythonを使ってクラス成績を可視化してみた](https://qiita.com/tech-nami/items/55507c0b5781d60ca687)で使った Excel のシートを RAG として読み込ませてみました。
　ちょっとうまくいかない部分もありましたが、概ね良い結果が得られました。
　今回検証をしながら、色々なモデルや RAG データの格納先が選択できること、データソースもいろいろ変えられることがわかりましたので、いろいろ面白い使い方がありそうなので、これらも続けて実施していきたいと思います。
　さらに、エージェントやフローについても引き続き試してみたいと思います。