現役のITエンジニアが、 システム開発の現場で求められる知識を発信
記事検索
公開

Amazon Bedrock Knowledge Baseでのメタデータ活用法

生成AI関連

はじめに

RAG(Retrieval Augmented Generation)を構築していると、

  • 検索結果をもっと的確に絞り込みたい
  • 回答に「URL」や「カテゴリ」といった補足情報も含めたい

と感じる場面は多いのではないでしょうか。Amazon Bedrockのナレッジベースでは、メタデータを活用することで、こうした要望に応えることができます。特にうまく使うと、RAGの精度や実用性を一段引き上げることが可能です。

本記事では、次の2つを実現する方法を整理していきます。

  • メタデータを使って検索結果を賢く絞り込む(フィルタリング)
  • メタデータの情報を回答生成に活用する

あわせて、「できること」と「できないこと」を明確にしながら、実際に実行する場合の回避策を紹介します。

本記事のナレッジベースは、下記の構成に基づいています。構成や作成方法は下記を参照下さい。

生成AI関連
Amazon Bedrock Knowledge Base × S3 VectorsでRAGを作って…

ナレッジベースのメタデータ

ナレッジベースにおけるメタデータの役割

ナレッジベースでは、ドキュメント本文とは別に、任意のメタデータを付与できます。例えば、以下のような情報です。

  • category:カテゴリ名
  • documentName:ドキュメント名
  • url:元のポータルページURL

これらのメタデータは、検索(retrieve)時の条件指定に利用できます。まず前提として、ナレッジベースではドキュメント本文とは別でメタデータファイルを用意して、登録する必要があります。

メタデータの登録方法

S3に配置するドキュメントでは、本文ファイルと同じ名前で .metadata.json ファイルを用意することで、メタデータを登録できます。例として、以下のような構成を考えます。


docs/
  スキルアップ支援制度/
    資格取得支援制度.md
    資格取得支援制度.md.metadata.json

このとき、資格取得支援制度.md.metadata.json の中身は
次のように記述します。

json

{
  "metadataAttributes": {
    "category": "スキルアップ支援制度",
    "documentName": "資格取得支援制度",
    "url": "https://...(実際のURL: 省略)"
  }
}

これらのデータをセットでS3にアップロードし、ナレッジベースで同期することでメタデータが登録されます。

メタデータで検索をフィルタリングする

フィルタリングで得られる効果

メタデータフィルタを使うことで、

  • 特定カテゴリのドキュメントだけを対象に検索できる
  • 関係のない文書を事前に除外できる
  • 類似度検索の精度を安定させられる

といった効果があります。検索対象のドキュメントが多すぎてほしい情報が得られない、ということはRAGの精度に直結するため、検索段階で母集団を絞ることは非常に重要です。

デモ:メタデータのフィルタリングテスト

Bedrock ナレッジベースのコンソールには、検索テスト機能が用意されています。ここでメタデータフィルタを指定すると、検索結果がどのように変わるかを簡単に確認できます。
テスト画面に入ったら、まずはフィルタリング無しで質問してみましょう。下記のような結果となります。

フィルタリングなしでの実行結果

フィルタリングなしでの実行結果

次に、フィルターを設定してから同じ質問をしてみましょう。まず設定ですが、左側でフィルター > 手動フィルターで下記のように設定します。

メタデータフィルタリングの作成方法

メタデータの手動フィルターの設定方法

次に右側で、下記のように検索してみます。

フィルタリングありでの実行結果

フィルタリングありでの実行結果

期待通り、対象のドキュメントを取得できなくなっていました。このようにナレッジベースでは、簡単にフィルタリングを実行できます。

フィルターパターン一覧

フィルターでできることはおおよそ下記となっています。

type 演算子 意味 備考
string equals 文字列の完全一致
string notEquals 文字列の不一致
string in 指定配列のいずれかに一致
string startsWith 前方一致 ⚠️ S3 Vectorsでは非対応
string stringContains 部分一致 ⚠️ S3 Vectorsでは非対応
number equals 数値の完全一致 float でも問題なし
number notEquals 数値の不一致 キー未設定のドキュメントも取得される
number greaterThanOrEquals / lessThanOrEquals 指定値以上(以下)
number greaterThan / lessThan 指定値より大きい(小さい)
number in / notIn 複数値一致 ❌ 未対応
boolean equals true / false 指定
boolean notEquals true / false 否定 キー未設定ドキュメントも取得される
list listContains 配列に値が含まれるか 文字列のみ(そもそも数字のリストを登録できない)
複合 andAll 全条件一致
複合 orAll いずれか一致

メタデータの情報を用いて回答を作成する

ナレッジベースのテストで起きること

メタデータの情報は必ずしもドキュメントに含まれているわけではありません。例えば今回、弊社ポータルサイトの情報をマークダウンに起こしてRAGを作成しました。その際、回答にポータルサイトのURLを含めたいと考えるのは自然な考えとなります。
では、資格取得支援制度のページのURLを取得してみましょう。


資格取得支援制度について記載のあるポータルページのURLを教えて下さい。

メタデータの情報を取得してみる

メタデータの情報を取得してみる

このように、一見ちゃんとURLを返してくれているように見えますが、https://techfun-portal.example.comと存在しないドメインを回答しています。ドキュメントのメタデータには url が設定されているにもかかわらず、回答にはメタデータの情報を含めることができないのです。

なぜ取得できないのか

これは不具合ではなく、仕様どおりの挙動です。ナレッジベースにおいて、

  • LLMに自動で渡されるのは「本文(チャンク)」のみ
  • メタデータは、暗黙的にはプロンプトに含まれない

という前提があります。そのため、メタデータにURLを入れておけば回答してくれるはずという期待は成立しません。

回避例① メタデータを本文に埋め込む

最もシンプルな回避策は、データ作成時にメタデータを本文へ埋め込む方法です。例えば、ドキュメント本文の冒頭や末尾に、

  • カテゴリ
  • ドキュメント名
  • URL

を明示的に記載しておくことで、LLMが参照できるようになります。この方法は実装が簡単で、ナレッジベース単体で完結しますが、

  • データ生成時の手間が増える
  • チャンクごとにURLを含める事ができない

といったデメリットもあります。

回避例② 回答生成を自前で実装する

より柔軟で実務向きなのが、ナレッジベースは検索専用と割り切り、回答生成を自前で制御する方法です。

全体の流れ
  1. ナレッジベースで retrieve (ドキュメントの取得のみ)を実行
  2. 本文と一緒にメタデータを取得
  3. メタデータを含めてプロンプトを組み立てる
  4. Bedrock の LLMで回答生成

この構成により、メタデータを根拠として回答に反映できます。

回避例②のデモ:メタデータの情報も含めて回答できるようにする

以下は、ナレッジベースを検索(retrieve)した結果の本文とメタデータをまとめて Nova に渡し、そこで回答生成をしてもらう実装例です。

kb_agent.py

import json

import boto3
from dotenv import load_dotenv

load_dotenv()

KNOWLEDGE_BASE_ID = "XXXXXXXXX"  # ご自身のKnowledge Base IDに置き換えてください


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


def make_bedrock_runtime_client():
    session = boto3.Session()
    return session.client("bedrock-runtime", region_name="us-east-1")


def retrieve_documents(query: str, k: int = 3) -> dict:
    bedrock_client = make_kb_client()

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


def build_prompt(user_query: str, retrieval_response: dict) -> str:
    results = retrieval_response.get("retrievalResults", [])

    # LLMに渡すコンテキストを作る
    chunks = []
    for i, r in enumerate(results, start=1):
        text = (r.get("content", {}) or {}).get("text", "")
        meta = r.get("metadata", {}) or {}

        chunks.append(
            f"""\
## document-{i + 1}
### 本文
{text}

### メタデータ
{json.dumps(meta, ensure_ascii=False)}
"""
        )

    context = "\n".join(chunks)

    prompt = f"""\
あなたは社内制度ドキュメントのアシスタントです
次の「検索結果(text)とメタデータ(metadata)」だけを根拠に回答してください
根拠に使ったdocument番号も、[1]、[2]の形で、該当箇所に一緒に示してください

例: 「〇〇」と記載があります [1]。

# 質問
{user_query}

# 検索結果
{context}
"""
    return prompt


def generate_answer_with_nova(prompt: str) -> str:
    runtime_client = make_bedrock_runtime_client()

    res = runtime_client.converse(
        modelId="arn:aws:bedrock:us-east-1:682033496318:inference-profile/us.amazon.nova-2-lite-v1:0",
        messages=[{"role": "user", "content": [{"text": prompt}]}],
        inferenceConfig={"maxTokens": 200, "temperature": 0.7, "topP": 0.9},
    )

    return res["output"]["message"]["content"][0]["text"]


def main(query: str) -> str:
    retrieval = retrieve_documents(query, k=3)

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

    prompt = build_prompt(query, retrieval)
    answer = generate_answer_with_nova(prompt)

    print("----------- answer ------------")
    print(answer)
    print("--------------------------------")

    return answer


if __name__ == "__main__":
    main("資格支援取得制度について記載のあるポータルページのURLを教えて下さい")

上記コードを実行してみましょう。

実行結果

----------- retrieve -----------
{
  "ResponseMetadata": {...},
  "retrievalResults": [
    {
      "content": {
        "text": "(省略)",
        "type": "TEXT"
      },
      "location": {
        "s3Location": {
          "uri": "s3://knowledge-base-data-source-20260123/portal-info/スキルアップ支援制度/資格取得支援制度.md"
        },
        "type": "S3"
      },
      "metadata": {
        "documentName": "資格取得支援制度",
        "category": "スキルアップ支援制度",
        "url": "https://...",
        "x-amz-bedrock-kb-chunk-id": "d37cf20d-09b0-4b58-aa21-beb6a055ad43",
        "x-amz-bedrock-kb-data-source-id": "1WX35XMKPB"
      },
      "score": 0.48266324262208227
    },
    {
      "content": {
        "text": "(省略)",
        "type": "TEXT"
      },
      "location": {
        "s3Location": {
          "uri": "s3://knowledge-base-data-source-20260123/portal-info/スキルアップ支援制度/スキルアップ支援制度.md"
        },
        "type": "S3"
      },
      "metadata": {
        "documentName": "スキルアップ支援制度",
        "category": "スキルアップ支援制度",
        "url": "https://...",
        "x-amz-bedrock-kb-chunk-id": "f04ce2e0-f03f-4259-985a-9ad2ec32c42e",
        "x-amz-bedrock-kb-data-source-id": "1WX35XMKPB"
      },
      "score": 0.4725861319882243
    },
    ...
  ]
}
--------------------------------
----------- answer ------------
資格支援取得制度について記載のあるポータルページのURLは以下の通りです。

**https://...(実際のURL: 省略)** [2]

このURLは、document-2のメタデータに記載されています。
--------------------------------

このように、メタデータを明示的にプロンプトへ渡すことで、URLなどの補足情報を根拠付きで回答に含めることが可能になります。

まとめ

Amazon Bedrock のナレッジベースにおけるメタデータは、RAGを実務レベルで使いやすくするための重要な要素です。特に、検索段階でメタデータを使って対象ドキュメントを絞り込むことで、類似度検索の精度を安定させ、回答の精度を向上させることができます。

一方で、メタデータに登録した情報は、そのままでは回答生成には利用されません。ナレッジベースのテスト機能でURLなどを尋ねても取得できないのは、仕様上の制約によるものです。この挙動を理解せずに設計を進めると、「入れたはずの情報が回答に出てこない」という違和感につながります。
こうした制約に対しては、いくつかの現実的な回避策があります。小規模であれば、メタデータの内容を本文に埋め込む方法でも対応できますが、より柔軟で拡張性の高い構成を目指すのであれば、ナレッジベースを検索専用と割り切り、retrieve結果とメタデータを明示的にLLMへ渡して回答生成を制御する方法が有効です。
ナレッジベースは「すべてを自動でやってくれる仕組み」ではなく、「検索を担うコンポーネント」として捉えることで、設計の自由度は大きく広がります。メタデータをどう扱うかを意識することで、RAGはより実務に耐える仕組みへと進化していきます。

生成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関連

Amazon Bedrock Knowledge Baseで…

生成AI関連

はじめての人のための:AI・機械学習・統計・生成AI・AGI…

生成AI関連

Amazon Bedrock Knowledge Base …

生成AI関連

NotebookLMで議事録活用【活用編】

生成AI関連

生成AIシステムへのガードレール導入のポイント

生成AI関連

NotebookLMで議事録活用【生成編】

生成AI関連

生成AIの精度を評価するための指標入門(2クラス分類編)

生成AI関連

NotebookLMで議事録活用【検索編】

生成AI関連

類似検索を実現するための「エンベディング」のしくみ

記事一覧を見る