4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【AWS】Bedrock Managed Knowledge Baseの自動同期スケジューリングを試してみました

4
Posted at

はじめに

Amazon Bedrock Managed Knowledge Base に自動同期スケジューリングが来ました。

これまでは S3 のファイルを差し替えるたびにコンソールで「同期」を押すか、同期APIを発火するかだったのかので、リソースの削減や自動化できるので試してみました

自動同期スケジューリングとは

そもそも Knowledge Base には同期を自動化する仕組みがありませんでした。定期的に同期したければ、EventBridge から Lambda を叩いて StartIngestionJob を呼ぶ仕組みを自分で組むしかなかったんですね。それが syncSchedule というフィールドを1つ足すだけで済むようになった、というのが今回の機能です。指定できる頻度は3つです。

頻度 書き方 指定できること
日次 {"daily": {}} なし
週次 {"weekly": {"dayOfWeek": "MONDAY"}} 曜日だけ
月次 {"monthly": {"dayOfMonth": {"dayNumber": 15}}} 日付(1〜28)または月末

この3つは排他で、daily と weekly を同時に書くとエラーになります。syncSchedule を書かなければ、従来どおりの on-demand(手動同期のみ)です。

マネジメントコンソールだと、データソースの編集画面にこういう選択肢が並びます。

image.png

日本語 UI で開いているのに、この Sync schedule セクションだけ英語のままです。出たばかりの機能なので、ローカライズが追いついていないみたいですね。

実行時刻は選べません

最初の注意点です。daily を選んでも「何時に走るか」は指定できません。API のモデル定義にはっきり書いてあります。

A daily sync that runs once a day at a system-chosen off-peak time. The run time is not configurable.

AWS 側が off-peak な時間帯を勝手に選びます。「業務時間前の朝6時に同期を終わらせておきたい」といった要件には使えません。

月次が「28日まで」な理由

monthly の dayNumber1〜28 しか指定できません。理由もモデル定義に書いてありました。

Values are capped at 28, so a monthly sync runs in every month, including February.

2月をスキップしないためですね。「毎月末に走らせたい」場合は dayNumber ではなく lastDayOfMonth を使います。

{ "monthly": { "dayOfMonth": { "lastDayOfMonth": {} } } }

やってみる

東京リージョン(ap-northeast-1)で試します。

Managed Knowledge Base を作る

Managed 型はベクトルストアを自分で用意しなくていいので、これだけです。

import boto3

bedrock = boto3.client("bedrock-agent", region_name="ap-northeast-1")

r = bedrock.create_knowledge_base(
    name="mkb-syncsched-demo",
    roleArn="arn:aws:iam::123456789012:role/mkb-sync-test-role",
    knowledgeBaseConfiguration={
        "type": "MANAGED",
        "managedKnowledgeBaseConfiguration": {"embeddingModelType": "MANAGED"},
    },
)

作成した KB をコンソールで見るとこんな感じです。

image.png

「ナレッジベースタイプ: マネージドベクトルストア」「埋め込みモデル: マネージド」となっていて、ベクトルストアまわりの設定項目が軒並み - なのが Managed 型らしいところです。

スケジュール付きでデータソースを作る

ここからが本題です。syncSchedule を置く場所なのですが、managedKnowledgeBaseConnectorConfiguration の直下です。私は最初、コネクタ固有の設定だろうと思って connectorParameters の中に書いてしまい、静かに無視されました。同じ罠にはまらないよう気をつけてください。

bedrock.create_data_source(
    knowledgeBaseId=KB_ID,
    name="s3-weekly",
    dataDeletionPolicy="DELETE",
    dataSourceConfiguration={
        "type": "MANAGED_KNOWLEDGE_BASE_CONNECTOR",
        "managedKnowledgeBaseConnectorConfiguration": {
            "connectorParameters": {
                "type": "S3",
                "version": "1",
                "connectionConfiguration": {
                    "bucketName": BUCKET,
                    "bucketOwnerAccountId": ACCOUNT_ID,
                },
            },
            "syncSchedule": {"weekly": {"dayOfWeek": "MONDAY"}},
        },
    },
)

レスポンスを見ると、指定した syncSchedule がそのまま返ってきます。

"managedKnowledgeBaseConnectorConfiguration": {
  "mediaExtractionConfiguration": {
    "imageExtractionConfiguration": { "imageExtractionStatus": "ENABLED" }
  },
  "connectorParameters": "{\"type\":\"S3\",...,\"maxFileSizeInMegaBytes\":\"500\",\"aclEnabled\":false}",
  "syncSchedule": { "weekly": { "dayOfWeek": "MONDAY" } }
}

データソースの詳細画面にも Sync schedule の欄が増えていて、設定した内容がそのまま出ます。

image.png

ちなみにデータソースの一覧側には同期スケジュールの列がありません。どのデータソースにスケジュールが設定されているかを一覧で把握できないので、複数のデータソースを運用していると地味に不便そうです。

スケジュールを切り替えてみる

UpdateDataSource で切り替えられます。思いつくパターンを全部試しました。

やったこと 結果
weekly(MONDAY) → daily OK
daily → monthly(dayNumber=15) OK
monthly(15) → monthly(lastDayOfMonth) OK
on-demand → weekly(FRIDAY) OK
monthly → syncSchedule を省略 OK。null に戻る
dayNumber=29 / dayOfWeek に MONDAYY NG(ValidationException
dayNumber=0 / daily と weekly を同時 / {} / dayNumber と lastDayOfMonth を同時 NG(boto3 が弾く)

ひととおり試していて気づいたのですが、エラーの弾かれ方が2種類あります。排他違反や 0 以下の値は boto3 のクライアント側で止まっていて、そもそも API まで飛んでいません。一方で 29 という値や不正な曜日名はサーバーまで届いて ValidationException が返ってきます。

同じ「バリデーションエラー」でも、CloudTrail に残るかどうかが変わってくるので、地味に大事なところかもしれません。

コンソールから変えるなら、データソースの「編集」→ Sync schedule を開いて Frequency を選びます。

image.png

CLI でも同じことができます。

aws bedrock-agent update-data-source --region ap-northeast-1 \
  --knowledge-base-id <KB_ID> --data-source-id <DS_ID> --name s3-weekly \
  --data-source-configuration file://ds-config-monthly.json \
  --query 'dataSource.dataSourceConfiguration.managedKnowledgeBaseConnectorConfiguration.syncSchedule'
{ "monthly": { "dayOfMonth": { "lastDayOfMonth": {} } } }

手動 sync と併用できるか

スケジュールを設定した状態で StartIngestionJob を叩いてみました。

job = agent.start_ingestion_job(knowledgeBaseId=KB_ID, dataSourceId=DS_ID)

スケジュールを設定したデータソースに手で割り込む形になるので、怒られるかスケジュールが消えるかするかと思ったのですが、3ファイルを 2分ほどで取り込んで普通に COMPLETE になりました。実行後も syncSchedule はそのまま残っていたので、スケジュールと手動同期は素直に共存します。検索も通りました。

Q: 出張の宿泊費の上限はいくら?
1. score=0.44 s3://.../docs/expense-policy.md
   実費精算。出張時の宿泊費上限は1泊15,000円(首都圏は18,000円)。

ハマったポイント

CloudFormation も CDK もまだ対応していない

ここが一番大きいです。API では動いたので、当然 CDK でも書けるだろうと思って手を動かしたのですが、そもそも型がありませんでした。API では使えるのに、IaC からは書けません。

念のため CloudFormation のスキーマを直接確認してみます。

aws cloudformation describe-type --type RESOURCE \
  --type-name AWS::Bedrock::DataSource --region ap-northeast-1 --query 'Schema'

ManagedKnowledgeBaseConnectorConfiguration に生えているのは ConnectorParameters / DeletionProtectionConfiguration / MediaExtractionConfiguration の3つだけで、SyncSchedule がありません。しかも additionalProperties: false なので、書いても素通りしてくれません。

これは公式のリファレンスでも同じです。プロパティが3つしか載っていません。

CDK も同じです。CDK は CloudFormation のスキーマから型を自動生成しているので、当然といえば当然ですね。こちらも公式リファレンスに syncSchedule はありません。

執筆時点で最新の aws-cdk-lib 2.268.0 の型定義を手元で確認しても、やはり同じでした。

interface ManagedKnowledgeBaseConnectorConfigurationProperty {
    readonly connectorParameters?: any | cdk.IResolvable;
    readonly deletionProtectionConfiguration?: CfnDataSource.DeletionProtectionConfigurationProperty | cdk.IResolvable;
    readonly mediaExtractionConfiguration?: cdk.IResolvable | CfnDataSource.MediaExtractionConfigurationProperty;
}

厄介なのが、validate-template では気づけないことです。

$ aws cloudformation validate-template --template-body file://ds-with-schedule.yaml
{
    "Parameters": [],
    "Description": "Managed KB data source with SyncSchedule (expected to fail)"
}

何事もなかったかのように通ります。validate-template は構文しか見ておらず、プロパティが実在するかまでは検証してくれないんですね。CI で validate を回していても素通りするので、実際にデプロイして初めて落ちることになります。

Lambda と EventBridge の構成はもう要らないの?

そういえば従来の Knowledge Base って、本当に自動同期の手段はなかったはず...
API のモデル定義を全部走査して確かめてみましたが、確認できたのは今回のManaged KnowledgeBaseのみです

=== syncSchedule を持つシェイプ(全走査)===
 -> ManagedKnowledgeBaseConnectorConfiguration

=== Vector 型データソース設定に定期実行系のフィールドがあるか ===
S3DataSourceConfiguration: なし
ConfluenceDataSourceConfiguration: なし
SharePointDataSourceConfiguration: なし
WebDataSourceConfiguration: なし

DataSource 本体にも CreateDataSource のリクエストにも、スケジュールに相当するフィールドはありません。つまり従来型(Type: VECTOR)には今も自動同期の手段がなく、この機能は Managed 型専用ということになります。

実際 AWS 自身も、re:Post のナレッジセンターで「StartIngestionJob を自分で叩いて自動化してください」と案内していました。

さらに公式ブログでは、S3 の変更を EventBridge で拾って SQS を挟んで Lambda で同期する、というソリューションの作り方まで解説されています。同時実行クォータ(Knowledge Base あたり1ジョブ、アカウントあたり5ジョブ)に引っかからないよう自前でチェックし、DLQ とリトライも自分で組む、という内容です。

わざわざこれだけの記事が書かれていたということは、裏を返せばそれだけ面倒だったということですよね。

選択肢は3つある

今回のアップデートで「従来の構成はもう不要になったのか」というと、そうでもないと思っています。

まず、今回のアップデートで何が変わるのかを図にするとこうなります。

image.png

A のように書けば、これまで自前で用意していた EventBridge と Lambda がまるごと消えます。同期のためだけに関数を書いてロールを切ってルールを張る、という手間がなくなるわけですね。

ただし A は、あらかじめ用意された3つの頻度でしか動きません。整理すると選択肢は3つになります。

A. syncSchedule だけ B. 従来どおり Lambda + EventBridge C. 併用
即時反映 できない できる(S3 イベント駆動) できる
実行タイミング daily / weekly / monthly のみ。時刻も選べない cron 式で自由。平日だけ、毎時、なんでも 両方
作るもの なし。フィールド1つ Lambda、IAM ロール、EventBridge ルール(本気なら SQS と DLQ も) 従来構成と同じ
IaC 書けない(前述) CloudFormation / CDK で完結する 一部書けない
対象 Managed 型専用 Vector 型でも Managed 型でも使える Managed 型
失敗の検知 ログ配信を設定して CloudWatch で拾う Lambda のエラーで即分かる。SNS 通知も組める 両方

A の価値は、図を見てのとおり運用・監視する対象がゼロになることに尽きます。関数が1本減るというのは、それだけで気が楽です。

一方で A は、あらかじめ決められた3つの頻度でしか動きません。しかも実行時刻すら選べない。「ファイルを置いた数分後には引けてほしい」とか「毎朝の始業前には必ず終わっていてほしい」といった要件には、そもそも届かないんですよね。

B を選べば、S3 イベント駆動での即時反映も、cron 式による柔軟なスケジュールも自由に組めます。今回のアップデートが出たからといって、B が劣化するわけではありません。

C の併用も成り立ちます。スケジュールを設定した状態でも StartIngestionJob は叩けて、叩いた後も syncSchedule は残ることを確認しました。この場合、即時性は Lambda が担い、S3 イベントの取りこぼし(Lambda の失敗、同時実行クォータ超過など)を syncSchedule の全件スキャンが回収する、という役割分担になります。Lambda とは独立した経路で走るので、冗長性としては意味があります。

個人的にはまだ従来の構成を推したい

ここは好みが分かれるところだと思うのですが、私はまだ B の従来構成のほうがいいかなと思っています

理由はシンプルで、いろんなユースケースに柔軟に対応できるからです。Lambda を1本書いてしまえば、即時反映も、変わった周期も、同期前後の前処理や通知も、あとから何でも足せます。一度作ってしまえば Vector 型の Knowledge Base でも使い回せますし、IaC にも素直に乗ります。

逆に A は「作るものがゼロ」という一点で強いのですが、要件が少しでも動いた瞬間に結局 Lambda を書くことになります。そして Lambda を書くと決めた時点で、A の最大の価値は消えてしまうんですよね。

なので現状の私の結論としては、更新頻度が低くて即時性も要らないデータに限って A、それ以外は素直に B という感じです。

ちなみに Knowledge Base あたりの同時実行ジョブ数は1なので、C の併用でスケジュール同期と手動同期がぶつかったときにどう捌かれるのかは気になるところです。

さいごに

RAG の運用でいちばん面倒なのは「データソースは更新されたのに Knowledge Base が古いまま」という状態なので、それを自前の仕組みなしに解消できるのはありがたいです。設定を1つ足すだけで、拍子抜けするくらい簡単でした。

前章に書いたとおり、これ1本で従来の構成を置き換えられるかというと、現状はまだ厳しいというのが正直な感想です。即時反映も柔軟な周期も要らない、更新頻度の低いデータに絞って使う。今のところはそれくらいの距離感がちょうどいい気がしています。

参考

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?