作成手順
この『その2』では下の4~7まで。
- VPC(virtual private cloud)作成
- Aurora Serverless v2でPostgreSQL作成
- (ec2インスタンス作成<==不要だったので使わない(参考にメモとして残した)
- s3に読み込ますpdfをUploadする
- bedrockでknowledgebase vector storeを作る
- bedrockでllmアクセスできるようにする
- lambdaでknowledgebase vector storeとllmを使って質問の回答を得る
- Amplify Angular Webページに入力された質問をRESTでAPI Gateway経由でLambdaに送り
- AmplifyにAngular Webページに表示する(チャット形式)
s3にファイルをUploadする
s3にbucketを作成して、その下に7つのpdfファイルをUploadしました。
これだけです。
BedrockでVector store作成
- Bedrockページ左メニューの『Knowledge Bases』に入り
- 『Create』〜『Knowledge Base with vector store』
- 『Knowledge Base name』を入れる
- 私の場合。『MyKnowlegeBase–FP0H』とした
- IAM permissionsで『Create and use a new service role』を選択し、Service role nameはそのまま『AmazonBedrockExecutionRoleForKnowledgeBase_dylea』とした。
- 『Data source details』で『Amazon s3』を選択し『Next』
- 画面の左下の『Add data source』をします。
- Data sourceは1つのファイルで良いし、ディレクトリで良い。 ディレクトリの場合は、その下のファイル全てが対象になります。 ディレクトリを指定していると後ほど、Add documentで10個までファイルを追加できます。(ファイルはData sourceと同じディレクトリ内である必要があります)
- 今回はs3をData sourceにしていますが、Customで選択していると
- 直接ファイルをUploadできる(5MBまで。50MBまで拡大可能)
- Inlineで文字入力できる(制限は不明)
- Data source name ーーー『MyKnowledgeBase-FP0H-source』
- Data source location 『This AWS account』
- Parsing strategy 『Amazon Bedrock default parser』
- Chunk strategy size 500 overwrap 15%(私の場合はこうしましたが、300,20%でもいいと思います)
- 今回はs3をData sourceにしていますが、Customで選択していると
- Data sourceは4つ(計5つ)までで追加できるみたいです。
- Data sourceは1つのファイルで良いし、ディレクトリで良い。 ディレクトリの場合は、その下のファイル全てが対象になります。 ディレクトリを指定していると後ほど、Add documentで10個までファイルを追加できます。(ファイルはData sourceと同じディレクトリ内である必要があります)
- 『Next』
- Embedding model 『Cohere Multilingal v3』—1024次元
- このembedding modelはRequestしないと使用できない。Syncできない。
- Bedrock左メニューからFoundation modelの下のModel catalogをクリック
- Cohere multilingaulをクリック
- 画面上のEmbed Multilingaulのすぐ下に『Available to request』があるのでクリック
- ポップアップが開くので、『Request model access』をクリック
- 使いたいmodelを選択して、
- (Anthropic製を選択した場合は、会社名、業種、用途などを記入して)
- 『Submit』
- TitanなどはすぐにAccess grantedになったが、CohereとAnthropicはIn Progressのまま。3分くらいでCohereもAnthropicもAccess grantedになった。
- このembedding modelはRequestしないと使用できない。Syncできない。
- 『Use an existing vector store』とし
- Vector storeでAuroraを選択
- Amazon Aurora DB Cluster ARNはAurora DBのインスタンスの親のARNをコピペする
- Table nameは、スキーマ名.テーブル名で記入する。 『bedrock_knowledgebase.table_1』
- 『その1』で最後に作った2つ目のSecret ARNをコピペする。
- 暗号化はしていないのでKMS Keyは空白のまま
- Index filed mapping(CREATE TABLEで指定した通り)
- Vector field nameは、embedding
- Text field nameは、chunks
- Bedrock-managed metadata fieldは、metadata
- Custom metadataはテーブルに作っていないので空白のまま。
- Primary keyは、id
- 『Next』
- 『Create knowledge base』
- 『AmazonBedrokSecretPolicyForKnowledgeBase_dylea does not exit』というエラーが表示されたが、何故か次の日見たらKnowledgebaseが作成されていて、availableとなっていた。
- Knowledge baseに入り、Data sourceを選択して、『Sync』を実行。 (Sync completed for data source…)
- すると5~6分でCompleteとなり、Data source overviewの下のDocumentsに7つのファイル名の横にStatusとして『INDEXED』と表示されたら完成です。
実際テストしてみます。
- Data sourceからKnowledge baseに戻り、右上の『Test knowledge Base』をクリック
- まず、Knowledgebaseができているか確認するため、『Retrieval only: data sources』を選択
- 右下に入力フィールドがあるので、何か問い合わせてみます。
- PreviewにSoure chunksの初期値の5個の返答が表示されたら
Sourceの追加
MyKnowledgeBase-FP0Hに、pdfを追加していく。
- Bedrock画面の左メニューのKnowledge Basesを選択して
- ファイルを追加したいKnowledgebaseを選択する
- Data sourceを選択する
- Add document
- S3 locationはCurrent AWS accountとあひて、Browse s3でファイルを選択する。
- これはData sourceがs3の場合です。
- またファイルはData sourceのディレクトリ内になければなりません。
- 『Add』
*通常、Syncを実行したらData sourceで指定したディレクトリ内の全てのファイルが読み込まれる。 しかしその後ファイルを追加して、特定のファイルだけ読み込ます時にこのAdd documentを使用するのだと思います。
Lambdaからアクセス
retrieve_and_generate()
Lambdaで簡単に作るなら上記コマンドで試します。 その3以降もこのretrieve_and_generateを使います。
- Lambdaからアクセスするには、以下のコード。
- knowledeBaseIdはあなたのKnowledgebase IDに置き換えてください。
- service_nameでもわかるように、awsが用意してくれているRAG用のAgentを使います。
- これでeventのpromptに質問を入れてLambdaに渡すと簡単に答えを取得できます。
import json
import boto3
bedrock_client = boto3.client(service_name='bedrock-agent-runtime')
def lambda_handler(event, context):
try:
prompt = event.get('prompt')
response = bedrock_client.retrieve_and_generate(
input={"text": prompt},
retrieveAndGenerateConfiguration={
"type": 'KNOWLEDGE_BASE',
"knowledgeBaseConfiguration": {
"knowledgeBaseId": "NNI3CR9IKF",
"modelArn": "arn:aws:bedrock:ap-northeast-1::foundation-model/anthropic.claude-3-5-sonnet-20240620-v1:0",
},
},
)
text = response["output"]["text"]
print(text)
return {
'statusCode': 200,
'body': json.dumps({
'input_prompt': prompt,
'generated_text': text
})
}
except Exception as e:
return {
'statusCode': 500,
'body': json.dumps({
'error': str(e)
})
}
TestのEvent JSONには以下を作って、key2をpromptに変えて、質問を記述しています。 これでTestとすれば、以下のJSONがlambda_handlerにeventとして渡されるので、event.get(“prompt”)で質問を取り出せます。
{
"message": "大阪はどんなところですか",
"prompt": "Ethernetの使い方を教えて",
"key3": "value3"
}
参考 カスタマイズする場合
上記retrieve_and_generateは簡単ですが、精度を上げたかったりする場合には、Knowledgebaseからの取り出し方や、フィルタやLLMへの使い方も変わる場合があります。 その場合は、Knowledgebaseから取り出し、加工してLLMに渡すなど個別に実行する必要があります。 Knowledgebaseから取り出すだけの場合はretrieveで、LLMを実行するだけの場合はinvoke_modelで実行します。
retrieve (Knowledgebaseから取り出し)
- デバッグする際もKnowlodgebaseからの返信内容を確認しなければなりません。
- しかしprint(response)としても、途中で切れるし、7個指定しても2個しか表示されないし、とてもデバッグできる感じではありません。 しかもresponseの中身は{Dict[List{Dict}]}となっています。
- それを確認するために参考として7個のprint文を記入しています。
- 中身の確認は、result_list以下でちゃんと7個表示されました。 私の場合Chunkは500にしているので、長すぎるため先頭の100文字だけprintしています。
import json
import boto3
bedrock_client = boto3.client(service_name='bedrock-agent-runtime')
import pprint
def lambda_handler(event, context):
try:
prompt = {"text": event.get('prompt')}
response = bedrock_client.retrieve(
retrievalQuery=prompt,
knowledgeBaseId="NNI3CR9IKF",
retrievalConfiguration={
"vectorSearchConfiguration":{
"numberOfResults":7
}
}
)
print(type(response))
print(list(response.keys()))
print(type(response["retrievalResults"]))
print(type(response["retrievalResults"][0]))
print(len(response["retrievalResults"]))
print(list(response["retrievalResults"][0].keys()))
results_list = response["retrievalResults"]
print(f"\n全部で {len(results_list)} 件のデータがあります。\n")
for i, result in enumerate(results_list, 1):
print(f"\n--- 結果 {i}/{len(results_list)} ---")
# content内のtextとscoreを表示する例
content = result.get('content', {})
text = content.get('text', '')
score = result.get('score', 'N/A')
print(f"Score: {score}")
print(f"Text preview: {text[:100]}...") # 先頭100文字だけ表示
print("-" * 50) # 区切り線
return {
'statusCode': 200,
'body': json.dumps({
'input_prompt': prompt,
'generated_text': text
})
}
except Exception as e:
return {
'statusCode': 500,
'body': json.dumps({
'error': str(e)
})
}
Text Completion(invoke_model)
import json
import boto3
bedrock_client = boto3.client(service_name='bedrock-runtime')
def lambda_handler(event, context):
# 以下でevent["prompt"]の中身を書き換えている。
# あるバージョンでは先頭の\n\nHuman:と末尾の\n\nAssistant:が必要と書いてあったので一応メモっとく。
# prompt = event.get("prompt", "\n\nHuman:クリスマスについて小学生でもわかるように説明してください。\n\nAssistant:")
try:
model_id = 'anthropic.claude-3-5-sonnet-20240620-v1:0'
system_prompt = "必ず日本語で答えてください"
prompt=event.get("message")
messages = [{"role": "user", "content": prompt}]
max_tokens = 1000
body = json.dumps(
{
"anthropic_version": "bedrock-2023-05-31",
"max_tokens": max_tokens,
"system": system_prompt,
"messages": messages
}
)
response = bedrock_client.invoke_model(body=body, modelId=model_id)
# Decode the response body.
model_response = json.loads(response["body"].read())
# Extract and print the response text.
response_text = model_response["content"][0]["text"]
print(response_text)
return {
'statusCode': 200,
'body': json.dumps({
'input_prompt': prompt,
'generated_text': response_text
})
}
except Exception as e:
return {
'statusCode': 500,
'body': json.dumps({
'error': str(e)
})
}
TestのEvent JSONには以下を作って、key1をmessageに変えて、prompt(=質問する文字列)を記述しています。 これでTestとすれば、以下のJSONがlambda_handlerにeventとして渡されるので、event.get(“message”)で質問を取り出せます。
{
"message": "大阪はどんなところですか",
"key2": "value2",
"key3": "value3"
}
単純な質問でも返信に11秒強かかります。 しかしLambdaの初期Timeoutは3秒なのでタイムアウトエラーにならないように、Lambda関数のConfigurationでTimeoutを20秒に設定します。
使用可能モデル
- 東京リージョンでは『anthropic.claude-3-5-sonnet-20240620-v1:0』しか使えない。
- 最初はどこかのサンプルでanthropic.claude-3-5-sonnet-20240229-v1:0と記されてたので、これを使ってみたが、model ID on-demand throughput isn’t supported. となる。 もしかしたら常に最新のモデルIDを取得して記述しなければならないかもしれない。
- Amazon Bedrock でサポートされている基盤モデルに記載されている。
- Sonnet3.5 v2を使う場合。(2025/5現在)
- Amazon Bedrock でサポートされている基盤モデルでは、東京リージョンで3.5v2を使うのは『*』マークが記されている。 これは東京リージョンからus-west-2などのクロスリージョンを指定しないと使用できないという事。 Sonnet3.7は東京リージョンでは使えないので、Lambdaごとus-west-2で作成しないといけない。
- Bedrockで、us-west-2リージョンに切り替えて、Model catalogからそれらのモデルの使用申請(Modify model access)して、Access grantedになったら使用できる。
- その際、Lamdaは東京リージョンで起動して、以下のようにbedrock-runtimeにus-west-2を書き込むとSonnet3.7を使うことができる。
- bedrock_client = boto3.client(service_name=’bedrock-runtime’, region_name=’us-west-2′)
おしまい。 続きは『その3』へ。
その他
Aurora databaseの右にRecommendationsのカラムに3 Informationalとあったので開いてみると、1つがRead Onlyのインスタンスが存在しないとあり、それをクリックすると、Add at least another DB instance to the DB cluster to improve availability and performance.と書かれてあったので、『Apply』ボタンを押し追加。 Availableまで5分くらいかかった。

コメント