Amazon KendraとAWS Lambdaを使い、RAGのRetrievalフェーズを試してみた
はじめに
Amazon KendraとAWS Lambdaを使って、Retrieval Augmented Generation(RAG)のうち、Retrievalフェーズを試してみました。
Amazon Kendraは、様々なデータソースから特定の情報を迅速に見つけ出すことができるエンタープライズ向けの検索サービスです。
ユーザーが質問やキーワードを入力すると、Kendraは自身のインデックスから関連性の高い情報を検索(Retrieval
)してユーザーに提供します。このプロセスは自然言語処理(NLP)技術を利用しており、質問の内容を理解し、最も関連性のある回答を提供することが可能です。
最近、社内の業務効率化などの目的で、AIの言語モデル(以降、LLM)を用いて社内情報を活用するための手法として、RAGがよく話題になっています。
RAGは、ユーザーのプロンプトに基づいて、外部データを参照し関連性のあるドキュメントを検索後、その情報とユーザーのプロンプトをLLMに渡すことで、質問への回答が生成されます。
これをAWSサービスで実現する場合、AWSドキュメントにも記載されていますが、検索(Retrieval
)フェーズは、Kendraで実現が可能です。
Amazon Kendraは、最適化されたKendra Retriever APIを提供し、RAG(Retrieval Augmented Generation)ワークフローのエンタープライズリトリーバーとしてAmazon Kendraの高精度セマンティックランカーを使用できるようにします。Kendra Retriever APIは、ユーザーの質問に最もセマンティックに関連し、RAGペイロードの品質を最大化するために最適化された粒度を持つ、エンタープライズコンテンツからの文章を検索して取得します。
今回は、いきなりRAGでのシステムを構築するのは、ハードルが高いので、検索(Retrieval
)のフェーズのみを試してみます。
構成
構成図は、下記のとおりです。
Kendraのデータソース(取り込み元)としては、ウェブサイトやS3バケットに保存したドキュメントなどが利用できます。今回は、ウェブサイトとしてAWS公式ドキュメントをデータソースとして使用し、その中から情報を検索します。
Kendraのインデックスを作成
インデックス名は、test
にします。
他は、アクセスコントロール設定は、デフォルトのままにします
検証用のDeveloper edition
を選択し、インデックスを作成します。30分程度かかりました。
データソースとして、S3バケットやウェブクローラーなどが選択できます。
今回は、ウェブクローラーv2.0にしました。
データソースは、日本語ですので、日本語を選択します。
今回は、KendraのAWSドキュメントを取り込みます。
- https://docs.aws.amazon.com/ja_jp/kendra/latest/dg/what-is-kendra.html
IAMロールは、新規作成します
他は、デフォルトのまま進めます。
Sync domains only
を選択します。
同期の頻度は、オンデマンドにします。後で、Sync now
で同期することを忘れないようにしましょう。
フィールドのマッピングは、デフォルトのまま進めます。
Sync now
で手動で同期します
同期が完了すれば、kendra側の設定は完了です。
Document countは、539でした。
左画面の[Search indexed content]から、[Settings]を日本語にしてから、検索してみます。
検索ワードをもとに、関連度順に検索結果できています。
Lambdaを作成
Lambdaを作成します。以下を参考に、IAMロールやBedrockを利用するためのBoto3ライブラリをアップロードしてください。
さらに、Kendraにリクエストを送信できるようにするため、LambdaのIAMロールには、AmazonKendraFullAccess
ポリシーをアタッチします。
コードは下記のとおりです。
import boto3 import json kendra = boto3.client('kendra') def lambda_handler(event, context): # クエリのテキストをハードコーディング(検索内容を記載) query_text = 's3バケット' # Kendra インデックス ID に置き換え index_id = '<IndexID>' response = kendra.retrieve( QueryText=query_text, IndexId=index_id, AttributeFilter={ "EqualsTo": { "Key": "_language_code", "Value": {"StringValue": "ja"}, }, }, ) # Kendra の応答から最初の3つの結果を抽出 results = response['ResultItems'][:3] if response['ResultItems'] else [] extracted_results = [] for item in results: content = item.get('Content') document_uri = item.get('DocumentURI') extracted_results.append({ 'Content': content, 'DocumentURI': document_uri, }) print("Kendra extracted_results:" + json.dumps(extracted_results, ensure_ascii=False)) return extracted_results
KendraのインデックスIDは、Kendraのコンソール画面から確認できます。
また、検索内容から、関連性の高い上位3つのドキュメントを抽出しました。(下記の3つです)
"翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。nS3 バケットからドキュメントを追加できます。nPDFnRSSnドキュメントは、次の場所からインデックスに直接追加場合に指定します。Amazon S3バケット。同じコールで最大 10 個のドキュメントを追加できます。S3 バケットを使用する場合は、IAMドキュメントを含むバケットにアクセスする権限を持つロール。RoleArn パラメータでロールを指定します。nを使用するBatchPutDocumentAPI を使用してからドキュメントを追加するAmazon S3バケットは削除できます。インデックスをバケットの内容と同期させるには、Amazon S3データソース。詳細については、次を参照してください。" "サンプルデータフォルダをダウンロードして抽出したら、Amazon S3 バケットに保存します。n重要nAmazon S3 バケットの名前はすべての AWS 全体で一意である必要があります。nS3 バケットを作成するには (コンソール)nS3 バケットを作成するには (AWS CLI)nS3 バケットにデータフォルダとメタデータフォルダを作成するnS3 バケットを作成した後、その中のフォルダにデータフォルダとメタデータフォルダを作成します。" "前提条件n使用する前にAmazon KendraS3 データソースにインデックスを付けるには、S3 で以下の変更を行い、AWSアカウント。nS3 では、次ののコストを追跡したりできます。nあなたの名前をコピーしましたAmazon S3バケット名n注記nバケットは、のコストを追跡したりできます。Amazon Kendraインデックスとインデックスには、ドキュメントを含むバケットにアクセスする権限が必要です。nS3 内および同じインデックスに使用する予定の他のデータソースでも、各ドキュメントが固有であることを確認しました。"
コンソールと同じ内容が抽出されていることを確認しました。
最後に
今回は、RAGのうちRetrievalのフェーズを、Kendraを使用して実装してみました
Lambdaのコードも思ったよりも少なく簡単に実装することができました、
また、次回では、Kendraで抽出した3つのドキュメントをもとに、次のGenerationフェーズ(LLMにプロンプトを渡し、質問に対する回答を生成する)を実装したいと思います。