生成AIの活用ノウハウや、 注目の技術に関する記事を掲載
公開
更新

Knowledge Base × S3 Vectors Index 設定の落とし穴

今回のポイント

  • S3 Vectors では、フィルタリング可能なメタデータ(filterable metadata)は 2KB までという制限がある
  • Knowledge Base は内部的に AMAZON_BEDROCK_TEXT や AMAZON_BEDROCK_METADATA を自動付与する
  • これらが filterable 扱いになると、チャンク本文がそのままメタデータに入り、2KB制限を超えて同期エラーになる
  • この設定は自分で S3 Vectors Index を作成し、それを Knowledge Base と連携する場合に注意が必要(Knowledge Baseによる自動生成では問題ない)
  • CDK などで Index を作る場合は、metadataConfiguration.nonFilterableMetadataKeys に AMAZON_BEDROCK_TEXT と AMAZON_BEDROCK_METADATA を明示的に指定すること

はじめに

CDK を使って Knowledge Base と S3 Vectors を構築し、デプロイした環境を利用しようとしたところ、データソースの同期がすべて失敗するという事象に遭遇しました。以前の記事では、コンソールから Knowledge Base を作成し、そのまま利用した際には問題なく同期できていました。

生成AI関連
Amazon Bedrock Knowledge Base × S3 VectorsでRAGを作って…
生成AI関連
Amazon Bedrock Knowledge Baseでのメタデータ活用法

しかも今回アップロードしたファイルおよびメタデータは、以前の記事で利用したものとまったく同じ内容です。

  • 同じドキュメント
  • 同じ metadata.json
  • 同じチャンク設定

それにもかかわらず、今回は同期が失敗しました。違いはただ一つです。

  • 以前:Knowledge Base をコンソールから作成(S3 Vectorsは自動作成)
  • 今回:S3 Vectors Index と Knowledge Base をCDKで自作し、それを連携

本記事では、このエラーをどのように切り分け、最終的にどこに原因があったのかを、実際の検証の流れに沿って整理します。

事象:データソースの同期がすべて失敗

同期を実行すると、すべてのデータソースがエラーになりました。

データソースの同期が全滅

データソースの同期が全滅した様子

表示されたエラーメッセージは次の通りです。

Encountered error: Invalid record for key 'fe734cb8-98ff-4720-bd94-01f6ae634119': Filterable metadata must have at most 2048 bytes (Service: S3Vectors, Status Code: 400, Request ID: 8efb6bea-703f-4ff9-8e5b-cbf79762e54c) (SDK Attempt Count: 1). Call to Amazon S3 Vectors did not succeed.

エラーコードによると「Filterable metadata must have at most 2048 bytes」とあり、フィルターに使うメタデータ(filterable metadata)は 2KB 以下である必要があることが分かります。
しかし、登録していた metadata は実測で300B 程度でした。一見すると、2KB 制限に抵触する理由は見当たりません。ここから調査を開始しました。

調査

検証①:ドキュメントサイズが影響しているのか?

エラーメッセージには metadata と書かれていますが、

  • 本文サイズ
  • チャンクサイズ
  • 埋め込み対象テキスト

といった要素が内部的に影響している可能性も考えられます。そこで、極端に小さなドキュメントを用意して検証しました。

ドキュメント1.md

ドキュメント1です。
合言葉は、「犬」です。
ドキュメント1.md.metadata.json

{
	"metadataAttributes": {
		"name": "ドキュメント1",
		"version": 1.3,
		"year": 2024
	}
}

既存データを削除し、このテストデータのみをアップロードして同期を実行します。

テストデータのデータソースの同期に成功

テストデータのデータソースの同期に成功

同期は成功しました。
この時点で分かったのは、

  • 小さなドキュメントでは問題が発生しない
  • 何らかの「サイズ依存の要素」が関係している可能性が高い

ということです。
まだ原因は特定できていませんが、「metadata 単体の問題ではなさそう」という感触が得られました。

検証②:Knowledge Base が自動付与するメタデータを確認する

次に、Knowledge Base から retrieve を実行し、metadata の中身を確認しました。

kb_retrieve.py

import json

import boto3
from dotenv import load_dotenv

load_dotenv()

REGION = "ap-northeast-1"   # ご自身のリージョンに置き換えてください
KNOWLEDGE_BASE_ID = "XXXXXXXXXX"  # ご自身のKnowledge Base IDに置き換えてください


def make_kb_client():
    session = boto3.Session()
    return session.client("bedrock-agent-runtime", region_name=REGION)


def retrieve_documents(query: str) -> None:
    bedrock_client = make_kb_client()

    response = bedrock_client.retrieve(
        knowledgeBaseId=KNOWLEDGE_BASE_ID,
        retrievalQuery={"text": query},
        retrievalConfiguration={
            "vectorSearchConfiguration": {
                "numberOfResults": 3,
            }
        },
    )

    print("----------- retrieve -----------")
    print(json.dumps(response, indent=2, ensure_ascii=False))
    print("--------------------------------")


if __name__ == "__main__":
    retrieve_documents("test")
実行結果

----------- retrieve -----------
{
  "ResponseMetadata": {
    (省略)
  },
  "retrievalResults": [
    {
      "content": {
        "text": "ドキュメント1です。 合言葉は、「犬」です。",
        "type": "TEXT"
      },
      "location": {
        "s3Location": {
          "uri": "s3://(省略)"
        },
        "type": "S3"
      },
      "metadata": {
        "name": "ドキュメント1",
        "x-amz-bedrock-kb-source-file-modality": "TEXT",
        "year": 2024.0,
        "version": 1.3,
        "x-amz-bedrock-kb-chunk-id": "c8f9c02a-a1b0-431b-a11c-35ff1691e36a",
        "x-amz-bedrock-kb-data-source-id": "H4YXHZENRS"
      },
      "score": 0.5249484777450562
    }
  ]
}
--------------------------------

ここで、自分で設定していない以下のキーが付与されていることが分かります。

  • x-amz-bedrock-kb-chunk-id
  • x-amz-bedrock-kb-data-source-id
  • x-amz-bedrock-kb-source-file-modality

つまり、Knowledge Base は内部的にメタデータを自動付与しているということです。ただし、これらは ID やファイル種別といった管理情報であり、ドキュメント本文のサイズには依存しません。そのため、これらが追加されたとしても 2KB を超えるとは考えにくい状況でした。

検証③:S3 Vectors に格納された実データを直接確認する

次に、S3 Vectors から直接ベクトルデータを取得しました。

get_metadata.py

import json

import boto3
from dotenv import load_dotenv

load_dotenv()

REGION = "ap-northeast-1"   # ご自身のリージョンに置き換えてください
VECTOR_BUCKET = "xxxx-xxxxxxxxx-xxxxx"   # ご自身のS3 Vectorバケット名に置き換えてください
VECTOR_INDEX_NAME = "yyyy-yyyyyyyyy-yyyyy"   # ご自身のS3 Vectorインデックス名に置き換えてください


def get_vectors_with_metadata(limit: int = 5):
    client = boto3.client("s3vectors", region_name=REGION)

    response = client.list_vectors(
        vectorBucketName=VECTOR_BUCKET,
        indexName=VECTOR_INDEX_NAME,
        maxResults=limit,
    )

    for vector in response.get("vectors", []):
        key = vector["key"]

        # 実データ取得
        item = client.get_vectors(
            vectorBucketName=VECTOR_BUCKET,
            indexName=VECTOR_INDEX_NAME,
            keys=[key],
            returnData=True,
            returnMetadata=True,
        )

        print(json.dumps(item, indent=2, ensure_ascii=False))


if __name__ == "__main__":
    get_vectors_with_metadata()
実行結果

{
  "ResponseMetadata": {
    "RequestId": "a9c00bfb-c746-42eb-a557-7e58abc904b4",
    "HostId": "",
    "HTTPStatusCode": 200,
    "HTTPHeaders": {
      "date": "Thu, 12 Feb 2026 09:00:11 GMT",
      "content-type": "application/json",
      "content-length": "22584",
      "connection": "keep-alive",
      "x-amz-request-id": "a9c00bfb-c746-42eb-a557-7e58abc904b4",
      "access-control-allow-origin": "*",
      "vary": "origin, access-control-request-method, access-control-request-headers",
      "access-control-expose-headers": "*"
    },
    "RetryAttempts": 0
  },
  "vectors": [
    {
      "key": "c8f9c02a-a1b0-431b-a11c-35ff1691e36a",
      "data": {
        "float32": [
          -0.0544898696243763,
          (1,024次元、省略)
          -0.06755758076906204
        ]
      },
      "metadata": {
        "version": 1.3,
        "x-amz-bedrock-kb-data-source-id": "H4YXHZENRS",
        "AMAZON_BEDROCK_METADATA": "{\"text\":null,\"author\":null,\"createDate\":\"2026-02-12T08:39:51Z\",\"modifiedDate\":\"2026-02-12T08:39:51Z\",\"source\":{\"sourceLocation\":\"s3://(省略)/ドキュメント1.md\",\"sourceType\":null},\"descriptionText\":null,\"pageNumber\":null,\"pageSizes\":null,\"graphDocument\":{\"entities\":[]},\"parentText\":null,\"relatedContents\":null,\"sourceDocumentId\":\"9sOnR6eTCvL7d7hbp62iaQt0A0dvqA1AqZYGjyaIjbauPuGsUG6w/CzDfkL9zyII\",\"additionalMetadata\":null}",
        "AMAZON_BEDROCK_TEXT": "ドキュメント1です。 合言葉は、「犬」です。",
        "name": "ドキュメント1",
        "x-amz-bedrock-kb-source-file-modality": "TEXT",
        "year": 2024.0
      }
    }
  ]
}

ここで決定的な情報が見つかります。

"AMAZON_BEDROCK_METADATA": "…",
"AMAZON_BEDROCK_TEXT": "ドキュメント1です。 合言葉は、「犬」です。"

AMAZON_BEDROCK_METADATAには、多くの内部利用データ、そしてAMAZON_BEDROCK_TEXT には本文の全文が格納されていました(おそらく、チャンク分割された後の値)。
この時点で初めて、

  • 本文が metadata として保存されている
  • それが filterable metadata として扱われている可能性がある

という仮説にたどり着きました。

S3 Vectors の制限仕様を確認する

公式ドキュメントによると、S3 Vectors には以下の制限があります。

ベクトルあたりのメタデータの合計: 最大 40 KB (フィルタリング可能 + フィルタリング不可)
ベクトルあたりのフィルタリング可能なメタデータ: 最大 2 KB

また、S3 Vectorsのベストプラクティスには、下記のように記載があります。

ベクトルインデックスのフィルタリング不可能なメタデータフィールドの設定
ベクトルインデックスを作成する際は、フィルタリング不可能なメタデータキーとしてフィルタリングを必要としないメタデータフィールドを設定します。例えば、ベクトル埋め込みのテキストチャンクは、参照のみが必要な場合、フィルタリング不可能なメタデータフィールドとして保存します。詳細については、「フィルタリング不可能なメタデータ」を参照してください。

つまり、Knowledge Baseと連携させる場合、自動付与されるメタデータを把握し、自身でフィルタリング不可能なメタデータ(non-filterable metadata)を設定しなければならないのです。

今回の設定では、「チャンクサイズ:3,072 トークン」としていたので、仮に 1文字1バイトとしても2KB を超えてしまいます。全ドキュメントで同期が失敗していた理由は、これが原因である可能性が高いと考えられました。

なぜ以前は問題が起きなかったのか?

以前の記事では、まったく同じファイルと metadata を使用していました。
違いは、S3 Vectors Index の作成方法です。

  • 以前:Knowledge Base 作成時に自動生成された Index
  • 今回:CDK で自分で作成した Index

以前の環境の Index 設定を確認すると、次の設定が含まれていました。

get_s3_vector_setting.py

import json

import boto3
from dotenv import load_dotenv

load_dotenv()

REGION = "ap-northeast-1"   # ご自身のリージョンに置き換えてください
VECTOR_BUCKET = "xxxx-xxxxxxxxx-xxxxx"   # ご自身のS3 Vectorバケット名に置き換えてください
VECTOR_INDEX_NAME = "yyyy-yyyyyyyyy-yyyyy"   # ご自身のS3 Vectorインデックス名に置き換えてください


def get_vector_index_metadata():
    client = boto3.client("s3vectors", region_name=REGION)

    response = client.get_index(
        vectorBucketName=VECTOR_BUCKET,
        indexName=VECTOR_INDEX_NAME,
    )

    print(json.dumps(response, indent=2, default=str))


if __name__ == "__main__":
    get_vector_index_metadata()
実行結果

{
  "ResponseMetadata": {
    "RequestId": "91663b82-5b43-449b-a3c4-db78501f1a71",
    "HostId": "",
    "HTTPStatusCode": 200,
    "HTTPHeaders": {
      "date": "Thu, 12 Feb 2026 09:19:43 GMT",
      "content-type": "application/json",
      "content-length": "491",
      "connection": "keep-alive",
      "x-amz-request-id": "91663b82-5b43-449b-a3c4-db78501f1a71",
      "access-control-allow-origin": "*",
      "vary": "origin, access-control-request-method, access-control-request-headers",
      "access-control-expose-headers": "*"
    },
    "RetryAttempts": 0
  },
  "index": {
    "vectorBucketName": "bedrock-knowledge-base-t3s18v",
    "indexName": "bedrock-knowledge-base-default-index",
    "indexArn": "arn:aws:s3vectors:(省略)",
    "creationTime": "2026-01-23 14:34:43+09:00",
    "dataType": "float32",
    "dimension": 3072,
    "distanceMetric": "euclidean",
    "metadataConfiguration": {
      "nonFilterableMetadataKeys": [
        "AMAZON_BEDROCK_TEXT",
        "AMAZON_BEDROCK_METADATA"
      ]
    },
    "encryptionConfiguration": {
      "sseType": "AES256"
    }
  }
}

たしかに、nonFilterableMetadataKeysの設定が存在しています。一方、エラーが発生していた環境では、nonFilterableMetadataKeysが空になっていました。

ここで、同期エラーの原因が特定できました。

CDKで作成する場合の解決方法

CDK で Index を作成する際には、以下のようにnonFilterableMetadataKeysを追加します。


const vectorIndex = new s3vectors.CfnIndex(this, "TestVectorIndex", {
    vectorBucketArn: vectorBucket.attrVectorBucketArn,
    indexName: vectorIndexName,
    dataType: "float32",
    dimension: 1024,
    distanceMetric: "cosine",
    metadataConfiguration: {
        nonFilterableMetadataKeys: [
            "AMAZON_BEDROCK_TEXT",
            "AMAZON_BEDROCK_METADATA",
        ],
    },
});

CDKの再デプロイ後、Index 設定を確認し、再度同期を実行します。

データソースの同期に成功

データソースの同期に成功

無事、同期は成功しました。

まとめ

今回の事象から得られたことは、次の通りです。

  • S3 Vectors には filterable metadata の 2KB 制限がある
  • Knowledge Base は本文を metadata として保持している
  • Index を自作する場合、nonFilterableMetadataKeys を明示しないと、Knowledge Baseとの同期が失敗する可能性が高い

IaC でインフラを構築する場合、「コンソールでは簡単に作れたから、CDKでも特に意識しなくて問題ないはず」という前提は成立しないことがあります。デフォルト設定の違いが、思わぬ挙動差につながることもあるため、仕様の確認と設定値の明示は重要です。

生成AI活用支援サービスのご紹介

Tech Funでは、お客様のフェーズに合わせ、生成AI活用に向けた支援を3つのパックでご提供しています。

  1. 無料診断パック:業務・プロセスの現状を無料で診断し、生成AI活用の可能性をレポートします。
  2. 検証(PoC)パック:診断で有効性が確認された業務を対象に、プロトタイプ構築を支援します。
  3. コンサルティングサービス:生成AI導入戦略の策定から運用体制構築までを包括的に支援します。

生成AIに限らず、Web・業務システム開発やインフラ設計など、技術領域を問わずご相談を承っています。「何から始めれば良いか分からない」という段階でも構いませんので、ぜひお気軽にお問い合わせください。

執筆・編集

Tech Fun Magazine R&Dチーム
Tech Funの生成AI研究に携わるエンジニアが、最新のAIモデル動向やプロンプト設計、実業務への応用手法など、生成AIに特化した知見を執筆・編集しています。
モデル評価や業務シナリオに応じたAI活用設計など、日々のR&D活動で得られる実践的なノウハウをわかりやすく紹介します。

ARTICLE
生成AI関連記事一覧

生成AI関連

ChatGPT Workとは?Businessで週次報告を任…

生成AI関連

Amazon Bedrock Managed Knowled…

生成AI関連

Google Sheets canvasはどこまで業務アプリ…

生成AI関連

Amazon BedrockのRerank APIで検索順位…

生成AI関連

OpenAI Agents APIとは?本番運用に必要な5つ…

生成AI関連

Codex App Serverとは?Pythonでの使い方…

生成AI関連

Amazon Bedrockの基盤モデルパーサーを実測する―…

生成AI関連

ChatGPT WorkのScheduled TasksをW…

生成AI関連

Amazon Bedrock Knowledge Bases…

記事一覧を見る