BedrockナレッジベースでAurora Serverlessを使用する際の設定注意点

2024年12月6月、Amazon Bedrock Knowledge Baseで用いるAmazon Auroraをクイック作成できるようになりました！

https://aws.amazon.com/jp/about-aws/whats-new/2024/12/amazon-aurora-quick-create-vector-store-bedrock-knowledge-bases/

ナレッジベースの作成画面から数クリックで自動デプロイできるようになり、ナレッジベースを構築するハードルが非常に下がったと言えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/930e52ee-b09c-f23c-0b72-b3cd24286e97.png)

また、作成されるのはAurora Serverless v2です。

11月20日にAurora Serverless v2(以下、Auroraと記述)が0個のAuroraキャパシティユニット(ACL)へのスケーリングがサポートされるようになりました。
これによって、DBを使用していない期間のコストを抑制することができるようになりました。

https://aws.amazon.com/jp/about-aws/whats-new/2024/11/amazon-aurora-serverless-v2-scaling-zero-capacity/

ただ、1点だけ注意点があります。
それは、<font color="red">**ナレッジベースの作成画面からAuroraを作成すると、ゼロスケーリングに対応していないエンジンバージョンのAuroraが作成される**</font>ことです。

実際に作成されたインスタンスの最小ACUを確認すると、0.5になっていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/613e946f-56ca-a42c-0ad9-a60abb394b0d.png)

また、このクイック作成を用いると、デフォルトVPC上に作成されてしまうため、セキュリティの観点からもあまり良くありません。

自動作成された際のセキュリティグループは以下のルールが用いられていました。最小権限とはなんだったのか、結構ガバガバですよね…

インバウンドルール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/962bba92-8001-be65-a496-bdbd034dd4da.png)

アウトバウンドルール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/6d093e1f-ece2-6d1a-c70a-e49e2ae9ad28.png)

したがって、ゼロスケーリングに対応したRAGを構築するためには、**別途自分でAuroraを作成する**必要があります。

ただ、それを実際行うにあたってどのように設定するのが適切なのかわからなかったため、実際に試して纏めてみました！

# 実際にやってみた！
構成図としては以下の感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/75a09c51-ff58-e4fa-8887-687806647d9c.png)

手順としては、
- VPCを作成する
- セキュリティグループを作成する
- DBサブネットグループを作成する
- Aurora Serverless v2を作成する
- Secrets ManagerにAurora接続の認証情報を登録する
- Auroraクラスターの設定を行う
- S3を作成し、検証で使用するドキュメントを格納する
- ナレッジベースを作成する

という流れになります。

## VPCを作成する
今回はVPC内にAurora Serverless v2だけを配置する想定なので、サブネットはプライベートなものだけ作成すればOKです。
ただし、Aurora Serverlessの使用上、マルチAZにする必要があるため、**プライベートサブネットは2つ以上作成**しましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/c0e5edc1-884d-b076-e232-afd7fc0b9ef3.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/0c0286dc-9454-aa8a-324d-f55caddd6cb6.png)

## セキュリティグループを作成する
以下のインバウンドルールを設定します。
- プロトコル：TCP
- ポート範囲：5432
- ソース：このセキュリティグループ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/6488a011-9e6e-f6a8-30d3-0f917576cae7.png)


## DBサブネットグループを作成する
Aurora ServerlessをVPCへ配置する際に、DBサブネットグループが必要になります。
先ほど作成したVPC上で作成していきましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/7052a3f7-e811-5177-2eac-5f417d29011b.png)

サブネットも先ほど作成した2つのプライベートサブネットを指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/9a65415a-aca5-aa1f-39c1-746becceb5b7.png)

## Aurora Serverless v2を作成する
ゼロスケーリングに対応したAuroraをナレッジベースで使用したい場合は、以下の条件に従って作成する必要があるとのことです。
- Aurora PostgreSQL DBクラスターのバージョン：
    - 16.3以降のすべてのバージョン
    - 15.7以降のバージョン
    - 14.12以降のバージョン
    - 13.15以降のバージョン
- `pgvector` の拡張機能のバージョン
    - 0.5.0以降
- RDS Data APIの有効化
- AWS Secrets Managerで管理されるユーザー情報によるDB接続

また、詳しい手順に関しては、公式ドキュメントに纏められていました。

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.VectorDB.html
***
まず、RDSコンソールを開いてデータベースを作成していきます。
作成方法は「標準作成」、エンジンのオプションは「Aurora (PostgreSQL Compatible)」です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/6c9f4d08-da07-8b3b-e9cc-daf96a04c168.png)

エンジンバージョンは「16.4」を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/1814a9e7-d8d1-16a3-f21f-60660896369f.png)

テンプレートは「開発/テスト」を設定し、DBクラスター識別子には任意の名前を指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/0a50dddb-cb89-ef1f-2b06-7c6d20b261e4.png)

認証情報管理は「AWS Secrets Managerで管理」を選択します。
これを設定しないとナレッジベースで使えないそうです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/9263af15-6b50-0693-3fe8-560bf6924482.png)

そしてインスタンスの設定で、「Serverless v2」を選択します。
ゼロスケーリングに対応したバージョンを使用していれば、容量の範囲で「0」が指定できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/37d6bd34-2859-6af5-9027-c0aadb80cb53.png)

※対応していないバージョンを選択した場合、0.5が最小となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/f32f2cd5-ea1d-fa5e-272a-a820c762165e.png)

Auroraレプリカの作成は、今回は不要です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/ec00114d-eb3b-d6e9-7772-7a7d21ccc7e8.png)

続いて接続関連の設定です。先ほど作成したVPCやサブネットグループを指定していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/73785e5e-66c1-cd9c-1507-a206e9d1c04b.png)

そして、パブリックアクセスはオフに設定します。AZも指定なしです。
セキュリティグループは先ほど作成したものを使用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/ea0c7612-4fb5-d62a-a8a5-c542eff9850b.png)

RDS Data APIには必ずチェックを入れましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/cbf56870-073d-4361-fa2c-be484734fe07.png)

:::note
RDS Data APiとは、**永続的なデータベース接続を必要とせず、HTTPエンドポイントやAWS SDKを通じてDBにアクセスできる機能**です。

主な概要としては、以下の4つです。
- DBへのウェブサービスインターフェイスを提供
※ウェブサービスインターフェイス：HTTPプロトコルを使用してアプリケーション同士が通信するための標準化されたAPI
- 永続的なデータベース接続が不要で、代わりにセキュアなHTTPエンドポイントを使用
- AWS SDKとの統合が可能
- AWS Secrets Managerに保存された認証情報を使用

また、用いるメリットとして、特にサーバーレスアーキテクチャやマイクロサービスでの利用に最適で、DB接続の管理やVPC設定の複雑さを軽減することができます。
:::

特に不要であれば、Performance Insightsや拡張モニタリングは無効化しておきましょう。今回は検証なので無効にしておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/12956c05-db79-26c3-8875-349a19a70bb6.png)

最後に任意のDB名を設定したら、作成していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/c45bce79-8f7e-920c-b8b0-7d0bf1354ca0.png)

作成完了しました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/211085bc-23dd-bb21-02a1-98738b3da9c0.png)

## Auroraクラスターの設定を行う
コンソールのクエリエディタを用いて、マスターユーザーでPostgresDBへ接続します。
この時、Secrets Manager ARNには、先ほどDB作成時に設定したものを使用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/c082c685-5077-bedd-72b3-95caa57c2f66.png)

以下のコマンドを実行して `pgvector` 拡張機能をインストールします。
```
-- pgvegtor 拡張機能のインストール
CREATE EXTENSION IF NOT EXISTS vector;

-- pgvector のバージョン確認
SELECT extversion FROM pg_extension WHERE extname='vector';
```

`pgvector` のバージョンは0.5.0以降であればOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/8008d5c8-3136-d757-f51c-16f176bdcd7d.png)

続いて以下のコマンドを実行します。
スキーマ名・ロール名は適宜変更してください。

また、'your password'の部分は任意の文字列を入力してください。
ただ、この後Secrets Managerの設定で使用するのでどこかにメモしておきましょう。
```
-- スキーマの作成
CREATE SCHEMA bedrock_knowledgebase;

-- ロールの作成
CREATE ROLE bedrock_user WITH PASSWORD 'your_password' LOGIN;
H14ijej9jfhaa021

-- スキーマに対する権限を付与
GRANT ALL ON SCHEMA bedrock_knowledgebase to bedrock_user;
```

:::note
コマンド実行時、画面下の「出力」のStatusが「success」になることを確認してください。
:::

***
続いて、Secrets Managerでbedrock_user用のDB認証情報を作成します。
パスワードは先ほど設定したものを使用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/5457c0ba-e5b2-46c8-a0dc-c52400c77ff0.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/2390225f-1910-23b3-4e03-8f5bb0f1699c.png)

シークレットが作成できたら、ARNをコピーします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/20d2a63e-a5f6-baf1-331c-1c1d013111e7.png)

***
再びRDSのクエリエディタに戻り、今度はbedrock_userの認証情報を用いてDBに接続します。
エディタ内にある「データベースを変更する」から操作し、先ほどのシークレットのARNを貼り付けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/2289acb1-c31e-5651-86a1-1f2ec7554b4c.png)
↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/b912ff2e-4d12-488d-c4ec-06a737d217d9.png)

接続できたら、以下のコマンドを実行してテーブルとインデックスを作成します。
テーブル名は適宜変更してください。

また、`embedding vector(1024)`の箇所については、ナレッジベースを作成する際に指定する**埋め込みモデルのベクトル次元数を入力**してください。
この値が一致していないとエラーになります。

参考は以下です。
- Titan Text Embeddings V2: 256 or 512 or 1024
- Titan Embeddings G1 - Text: 1536
- Embed English: 1024
- Embed Multilingual: 1024

```
-- テーブルの作成
CREATE TABLE bedrock_knowledgebase.dodeuce (id uuid PRIMARY KEY, embedding vector(1024), chunks text, metadata json);

-- インデックスの作成
CREATE INDEX on bedrock_knowledgebase.dodeuce USING hnsw (embedding vector_cosine_ops);
```

:::note
コマンド実行時、画面下の「出力」のStatusが「success」になることを確認してください。
:::

上記コマンドによって、テキストデータのベクトル表現を格納し、効率的な類似度検索を可能にします。

ここまでできたら、データベースの設定は完了です！

## S3を作成し検証で使用するドキュメントを格納する
適当にS3バケットを1つ作成し、その中にドキュメントを格納します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/4289f7d8-f2dd-e8a6-ed39-519c1ab6b207.png)

以前、RAGを作成した際にWikipediaをPDF化して格納したところ、精度があまりにも低かったので、今回はWikipediaを要約したものをMarkdown形式で用意しました。

バケットの暗号化は任意ですが、今回はSSE-KMSで暗号化しました。
ここで使用するKMSキーを、この後ナレッジベースでも用いて復号化します。

## ナレッジベースを作成する
いよいよナレッジベースを作成していきましょう。
最初はベクトルストアを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/af96162f-a534-961f-2cf1-5f9b803d04c0.png)

任意の名前をつけて作成を進めます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/61403353-3dc1-f5c2-c590-20de0e9828ea.png)

データソースにはS3を指定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/036c751f-e131-cc1e-8c51-5cc200ca76fa.png)

その後、データソースの設定をしていきます。

S3 URIには、先ほど作成したS3のオブジェクトキーを指定します。
また、S3の暗号化にKMS CMKを使用した場合は、同じキーをここでも指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/d3eddf9c-fa79-d070-3793-6f2a537ae1f8.png)

Parsing strategy(変換戦略)、チャンキング戦略などはデフォルト設定でいきます。

埋め込みモデルは、CohereのMultilingual v3を指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/e3034fa7-ce25-7913-ff60-0bf2665ef2c9.png)

そしてベクトルデータベースの設定を行います。
「作成したベクトルストアを選択」し、「Amazon Aurora」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/98e09cce-72c2-cb7d-06e7-2445aebe19e6.png)

そして、これまでに作成してきたAuroraやシークレットのARNなどを設定していきます。
- Amazon Aurora DB クラスター ARN：`arn:aws:rds:<region>:<account_id>:cluster:<your_cluster>`
- データベース名：任意のDB名(ここでは`knowledge_base_aurora`)
- テーブル名：任意のテーブル名(ここでは`bedrock_knowledgebase.dodeuce`)
- シークレットARN：`arn:aws:secretsmanager:<region>:<account_id>:secert:<your_secert>`
- シークレット用のカスタマーマネージドKMSキー：シークレットをKMS CMKで暗号化した場合はここでKMSキーのARNを指定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/094434e1-c8a3-5993-ef0d-17833cb3af74.png)

続いて、インデックスフィールドマッピングの設定をしていきます。
先ほど設定した`dodeuce`テーブルの定義とマッピングします。
- ベクトルフィールド名：embedding
- テキストフィールド名：chunks
- Bedrockマネージドメタデータフィールド：metadata
- プライマリキー：id

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/7cd2a5a2-7240-25af-d096-60856c164698.png)

すべて入力を終えたら、ナレッジベースを作成しましょう！

:::note warn
※作業中にAuroraが自動停止した状態になっていると、下記エラーが発生します。
こうなると一度画面更新しないと作成成功しないようなので、ナレッジベース作成前にAuroraが起動しているかを確認しておくのをおすすめします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/374abc1c-1f84-05c8-a1a4-cc6517731af1.png)
:::

上手く設定できていれば、ナレッジベースが完成します！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/254648e0-f221-c083-29f7-a37c77647288.png)

## 試してみる
実際の動作確認をしてみました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/8ba458b9-bf72-331e-c6ec-8241db7db2be.png)

うーん、合ってるけど、「すべて」ではないんですよね…
天皇賞・秋とジャパンカップが省略されている…

諦めずもう1つ聞いてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/f5e0a3f9-a54a-46c8-5f30-f537d1ea42ed.png)

だめだこりゃ！ｗ

ということで精度がいまいち。
チャンクの設定が悪いのか、ドキュメントがまだ悪いのか…次回以降はちょっとこの辺り精度向上のために頑張ってみようと思います。

ただ、Auroraでベクトルストア作成したので、一々消さなくてもお金かからないのが嬉しいところですね！
(OpenSearch Serverlessは従量課金の上にめっちゃ高いので、検証終わるたびに消さないといけなかったんですよね…)

# 個人的に疑問に思っていたところ
最後に、今回の検証をやろうと思ったきっかけとその答えについて纏めておきます。

## Q.Bedrockからプライベートサブネット内のAuroraにどうやって接続するのか？
検証前までは、VPCエンドポイントを立てて、エンドポイント経由でAuroraへアクセスする必要があるのかなーなどと考えていました。

しかし**結論としては、不要**でした。

## Q.セキュリティグループは何を指定するべき？最小権限は？
ということで、インバウンドルールをなしにして、データソースの同期と実行をしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/9f63a4cd-a908-f4db-21a2-8a285c054fc1.png)

データソースの同期→成功
実行→成功
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/ceccc6ac-3d53-2d29-b683-5f8bed1541b7.png)

ということで、**セキュリティグループは設定無しでOKそう**ですね。

ちなみにですが、クエリエディタに接続する際にも設定無しで良かったみたいです。
普通に接続できましたし、下記コマンドによるクエリも成功しました。
```
select * from bedrock_knowledgebase.dodeuce limit 10;
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616210/6093b210-de82-03c8-71d7-3affe73c5a12.png)

## なぜこうなるのか？
**RDS Data APiを用いているから**、と私は結論付けました。

Data APIを用いることで、Auroraを他のAWSリソースと統合することができます。
VPC内のAuroraへアクセスするために、Lambda関数を設定することなく、DBクラスターにアクセスできます。

HTTPエンドポイントを用いてAuroraへのアクセスが可能になるため、そもそもVPCを経由しておらず、その結果VPCエンドポイントは不要なのだと思います。

(間違ってたらコメント等で教えて下さい！)

# まとめ
ちょっと設定は大変ですが、一度構築できるとその後はかなり恩恵が大きいです！
今度はこれとGraphRAGの精度を比較してみようと思います！

# 参考にさせていただいたページ

https://qiita.com/hayao_k/items/45e59c1c2a183c27b20d

https://qiita.com/hayao_k/items/ff5482c5abc513e6f0b7

https://dev.classmethod.jp/articles/aurora-serverless-v2-query-editor-connection/

https://dev.classmethod.jp/articles/cloudformation-knowledge-base-for-bedrock-with-aurora/

https://www.cloudbuilders.jp/articles/4907/