Amazon S3 Vectors (1) : マネージメントコンソールでナレッジの作成と検索テストの実行
Amazon S3 Vectors (2) : Python スクリプトからベクトルデータの操作
Amazon S3 Vectors (3) : PDFに対するベクトル検索の実装とデータの一括削除サンプルスクリプト
いままで3回にわたってS3 Vectors を触ってきました。
この第4回では集大成、PDFに対する検索を実現するサンプルスクリプトを作っていきます。
さっそくやってみる
第3回の記事で、PDFの内容をチャンク単位で分割してベクトル化させるところまでを行いました。このためすでにS3 Vectors のインデックスにはPDFの中身が格納され、ベクトル検索が可能となっている状態です。
python put.py
49 個のベクトルを S3 Vectors に登録しました。
これを検索するスクリプトを`search.py`で作成していきます。
import boto3
import json
import sys
import argparse
# ======== CLI引数のパース ========
parser = argparse.ArgumentParser(description="S3 Vectors × Nova Lite RAG検索")
parser.add_argument("--query", required=True, help="検索クエリを指定してください")
args = parser.parse_args()
query = args.query
# ======== 設定 ========
region = "us-east-1"
bucket_name = "vectorbucket" # ← あなたのS3 Vectorバケット名
index_name = "vectorindex" # ← あなたのインデックス名
# ======== クライアント作成 ========
bedrock = boto3.client("bedrock-runtime", region_name=region)
s3vectors = boto3.client("s3vectors", region_name=region)
# ======== 1. クエリをベクトル化 ========
embed_response = bedrock.invoke_model(
modelId="amazon.titan-embed-text-v2:0",
body=json.dumps({"inputText": query})
)
embedding = json.loads(embed_response["body"].read())["embedding"]
# ======== 2. S3 Vectors で検索 ========
vector_response = s3vectors.query_vectors(
vectorBucketName=bucket_name,
indexName=index_name,
queryVector={"float32": embedding},
topK=3,
returnDistance=True,
returnMetadata=True
)
# ======== 3. 類似コンテキスト抽出 ========
contexts = [v["metadata"]["source_text"] for v in vector_response["vectors"]]
context_str = "\n---\n".join(contexts)
# ======== 4. プロンプト構築 ========
rag_prompt = f"""以下はPDFから抽出された情報です:
{context_str}
この情報に基づいて、次の質問に日本語で答えてください:
{query}
"""
# ======== 5. Nova Lite で推論 ========
llm_response = bedrock.invoke_model(
modelId="amazon.nova-lite-v1:0",
contentType="application/json",
accept="application/json",
body=json.dumps({
"messages": [
{
"role": "user",
"content": [
{ "text": rag_prompt }
]
}
],
"inferenceConfig": {
"maxTokens": 500,
"temperature": 0.7
}
})
)
# ======== 6. 結果表示 ========
result = json.loads(llm_response["body"].read())
print("\n🔎 回答:\n")
print(result["output"]["message"]["content"][0]["text"])
使い方
python search.py --query <質問文:例:個人情報の定義>
を実行すると以下の様な結果が戻ります。
🔎 回答:
個人情報の定義は、文書の中で以下のように説明されています:
> 個人に関する情報(個人情報、仮名加工情報、匿名加工情報及び個人関連情報。以下「個人情報等」という。)
具体的には、以下が含まれます:
1. **個人情報**:個人を特定できる情報。
2. **仮名加工情報**:個人を特定するための情報と結びつけることによって個人を特定できる状態に復元できる情報。
3. **匿名加工情報**:個人を特定するための情報と結びつけることによって個人を特定できる状態に復元することが相当困難な情報。
4. **個人関連情報**:個人情報等以外の情報であって、個人との結びつきが明らかに認められるもの。
これらの情報は、高度なデジタル技術を用いた方法により、個人の利益や公益のために活用される可能性があるため、その重要性と保護の必要性が強調されています。
解説
S3 Vectors にはチャンクに分割された文章とベクトル化された値が格納されています。質問文の検索を行うためにまずは質問文をベクトル化します。
embed_response = bedrock.invoke_model(
modelId="amazon.titan-embed-text-v2:0",
body=json.dumps({"inputText": query})
)
embedding = json.loads(embed_response["body"].read())["embedding"]
この時必ず、PDFをベクトル化したモデルと同じものを使う必要があります。
次にベクトル検索を行います。この時に結果を最大3つコサイン類似が近しい順で取り出します。
vector_response = s3vectors.query_vectors(
vectorBucketName=bucket_name,
indexName=index_name,
queryVector={"float32": embedding},
topK=3,
returnDistance=True,
returnMetadata=True
)
あとはその結果抽出されたテキストデータをもとにAmazon Nova Lite (これは埋め込みモデルとは別ベンダーのものでも全く問題ありません)を用いて自然な日本語での回答を作成します。
llm_response = bedrock.invoke_model(
modelId="amazon.nova-lite-v1:0",
contentType="application/json",
accept="application/json",
body=json.dumps({
"messages": [
{
"role": "user",
"content": [
{ "text": rag_prompt }
]
}
],
"inferenceConfig": {
"maxTokens": 500,
"temperature": 0.7
}
})
)