Amazon Bedrock EvaluationsのRAG評価結果をDuckDBからS3の生ログにクエリしてみよう

Amazon Bedrock EvaluationsのRAG評価結果をDuckDBからS3の生ログにクエリしてみよう

2025.09.16

Amazon Bedrock Evaluationsを利用すると、Bedrock Knowledge Base等のRAGシステムの検索精度を評価し、AWSコンソール上から結果を確認できます。
同時に、ジョブ実行時の設定にあるように、評価ジョブの生ログは、S3バケットにJSONL形式で出力されます。

本記事では、Bedrock Knowledge Baseの評価結果を例に、S3に出力されるログの仕様を解説し、DuckDBを使ってAWSコンソールに頼らずにSQLで直接分析する方法を紹介します。 評価方法は「検索のみ(Retrieval only)」とします。

S3の評価ログを直接分析することで、アドホックに評価ジョブを分析したり、評価ジョブパイプラインを組んでジョブ結果を通知したり、独自の集計軸で評価結果を可視化するというように、AWSコンソールでは実現できない、ユーザーの用途に特化した分析が可能になります。

プログラマブルに評価結果を分析できるため、開発サイクルにうまく取り込むことで、テスト駆動開発(TDD)ならぬ 評価駆動開発(Evaluation-Driven Development;EDD) が可能になります。

Bedrock EvaluationsのRAG評価の仕組み

Amazon Bedrock Evaluationsは、生成AIモデルやRAGシステムの性能を評価するためのマネージドサービスです。

Bedrock EvaluationsでRAGの検索精度の評価を行う場合、以下の流れで行います。

  1. ユーザーが用意した評価用の想定する検索結果を用意(理想)
  2. RAGシステム(Bedrock Knowledge Base等)へ実際に検索を実行(現実)
  3. 検索の理想と現実のギャップを LLM で評価

Bedrock Evaluations の大きな特徴の一つは LLM に評価させる点であり、このような評価手法は、一般に LLM as a Judge と呼ばれています。

https://www.thoughtworks.com/radar/techniques/llm-as-a-judge

Amazon Bedrock Evaluations は様々な評価が可能です。

本記事では、一番シンプルな 「Bedrock Knowledge Baseに対して検索のみで評価する」 ケースを例にします。

この場合の コンソールから の検索評価方法は次の記事を参考にしてください。

https://dev.classmethod.jp/articles/intro-to-bedrock-evaluations-rag-with-search-only/

「検索と生成」や独自のRAGシステムやカスタムメトリクスは、適宜読み替えてください。

S3出力の仕様

評価ジョブは非同期に実行され、ジョブ作成時に指定したS3バケットのプリフィックス以下にジョブごとにディレクトリをわけて出力されます。

ディレクトリ構造

Bedrock Evaluationsの評価結果は、指定したS3バケットに次のような階層構造で出力されます。

			
			s3://YOUR-BUCKET-NAME/OUTPUT-PREFIX
└── {Evaluation-Job-Name}
    ├── amazon-bedrock-evaluations-permission-check
    └── {Evaluation-Job-Id}
        └── inference_configs
            └── 0
                └── datasets
                    └── RagDataset
                        └── {uuid}_output.jsonl

		

具体例です

			
			s3://YOUR-BUCKET-NAME/OUTPUT-PREFIX
└── rag-evaluation-job-quick-start-20250910020852
    ├── amazon-bedrock-evaluations-permission-check
    └── cefzulgxjgwy
        └── inference_configs
            └── 0
                └── datasets
                    └── RagDataset
                        └── 7d36ced6-8d91-476e-b5d2-9386636f5b4f_output.jsonl

		

分析すべきは、最下層にある評価ジョブ結果ファイル({uuid}_output.jsonl)です。

ジョブ結果のJSONLの仕様

評価結果は1行1レコードのJSONL形式で出力されます。各行には評価データ、実際の検索結果、1つのプロンプトに対する評価結果を表します。

JSONLファイルのスキーマ

各行には以下の3点が含まれています

			
			{
  "conversationTurns": [
    {
      "inputRecord": { ユーザーが用意した評価用の想定する検索結果(理想) },
      "output": { RAGシステム(Bedrock Knowledge Base等)への実際の検索結果(現実) },
      "results": [ 検索の理想と現実のギャップの LLM による評価 ]
    }
  ]
}

		

詳細に展開します

			
			{
  "conversationTurns": [
    {
      "inputRecord": {
        "prompt": {
          "content": [{"text": "質問文"}]
        },
        "referenceResponses": [
          {
            "content": [{"text": "正解データ"}]
          }
        ]
      },
      "output": {
        "knowledgeBaseIdentifier": "KB_ID",
        "retrievedResults": {
          "retrievalResults": [
            {
              "content": {"text": "検索されたチャンク"},
              "location": {
                "s3Location": {"uri": "s3://..."},
                "type": "S3"
              },
              "metadata": {
                "x-amz-bedrock-kb-source-uri": "...",
                "x-amz-bedrock-kb-chunk-id": "...",
                "x-amz-bedrock-kb-data-source-id": "..."
              }
            }
          ]
        }
      },
      "results": [
        {
          "metricName": "Builtin.ContextRelevance",
          "evaluatorDetails": [
            {
              "modelIdentifier": "arn:aws:bedrock:...",
              "explanation": "評価の詳細説明"
            }
          ],
          "result": スコア
        },
        {
          "metricName": "Builtin.ContextCoverage",
          "evaluatorDetails": [
            {
              "modelIdentifier": "arn:aws:bedrock:...",
              "explanation": "評価の詳細説明"
            }
          ],
          "result": スコア
        }
      ]
    }
  ]
}

		

各フィールドは以下の通りです。

inputRecord

  • prompt: 評価に使用した質問文
  • referenceResponses: 質問文に対する理想的な正解(グラウンドトゥルース)

output

output フィールドは bedrock-agent-runtime:Retrieve API で実際に Bedrock KB に検索した結果とみなせば大丈夫です。

https://docs.aws.amazon.com/bedrock/latest/APIReference/API_agent-runtime_Retrieve.html

  • knowledgeBaseIdentifier: 使用したKnowledge BaseのID
  • retrievedResults: RAGシステムが検索した結果
    • content.text: 検索されたチャンクのテキスト
    • location: チャンクの元ファイル情報
    • metadata: チャンクのメタデータ

results

繰り返しとなりますが、results フィールドは LLM が理想(inputRecord)と現実(output)を比較評価した結果であり、Bedrock Evaluationsの肝です。

  • metricName: 評価メトリクス名
    • Builtin.ContextRelevance: 関連性スコア
    • Builtin.ContextCoverage: 網羅性スコア
  • evaluatorDetails: LLM-as-a-judgeの詳細
    • modelIdentifier: 評価に使用したLLMモデル
    • explanation: 評価理由の説明
  • result: スコア(0.0〜1.0)

スコア(result) が低いものはその理由(explanation) を確認しましょう。Builtin.ContextCoverage の理由は普通の文字列、Builtin.ContextRelevance の理由はJSON文字列("{\"passage_0\": \"foo ...", }")であることにも注意が必要です。

ジョブ単位で固定されるはずのLLM as aa Judgeの肝の評価モデル(Model Evaluator)が奥まったところに評価メトリクスごとに冗長に出力されていることに注意しましょう。

具体例

クリックで展開
			
			
{
  "conversationTurns": [
    {
      "inputRecord": {
        "prompt": {
          "content": [
            {
              "text": "Amazon S3 にはどれくらいの量のデータを保存できますか?"
            }
          ]
        },
        "referenceResponses": [
          {
            "content": [
              {
                "text": "データの総量とオブジェクト数に制限はありません。個別のオブジェクトサイズは最大5TBです。"
              }
            ]
          }
        ]
      },
      "output": {
        "knowledgeBaseIdentifier": "Z11EITLDWD",
        "retrievedResults": {
          "retrievalResults": [
            {
              "content": {
                "text": "Amazon S3 にはどれくらいの量のデータを保存できますか?  Amazon S3 に格納可能なデータの総量とオブジェクトの数には制限はありません。個別の Amazon S3 オブジェクトのサイズは、最低 0 バイトから最大 5 TB までさまざまです。1 つの PUT にアップロード可能なオブジェクトの最大サイズは 5 GB です。100 MB を超えるオブジェクトの場合は、マルチパートアップロード機能を使うことをお考えください。"
              },
              "location": {
                "s3Location": {
                  "uri": "s3://YOUR-BUCKET/s3/01.txt"
                },
                "type": "S3"
              },
              "metadata": {
                "x-amz-bedrock-kb-source-uri": "s3://YOUR-BUCKET/s3/01.txt",
                "x-amz-bedrock-kb-chunk-id": "f48fadf6-e249-47e6-a9c4-03ab72cb77d5",
                "x-amz-bedrock-kb-data-source-id": "MJ3FBDFWAX"
              }
            },
            {
              "content": {
                "text": "Amazon S3 の耐久性はどれくらいですか?  Amazon S3 は、クラウドで最も耐久性の高いストレージを提供します。S3 は、独自のアーキテクチャに基づいて、99.999999999% (イレブンナイン) のデータ耐久性を実現できるように設計されています。さらに、S3 はデフォルトで最低 3 つのアベイラビリティーゾーン (AZ) にデータを冗長的に保存するため、広範囲に及ぶ災害に対する回復力が組み込みで備わっています。"
              },
              "location": {
                "s3Location": {
                  "uri": "s3://YOUR-BUCKET/s3/05.txt"
                },
                "type": "S3"
              },
              "metadata": {
                "x-amz-bedrock-kb-source-uri": "s3://YOUR-BUCKET/s3/05.txt",
                "x-amz-bedrock-kb-chunk-id": "448e5ec6-3343-4bbf-8b43-8178ab5d62de",
                "x-amz-bedrock-kb-data-source-id": "MJ3FBDFWAX"
              }
            },
            {
              "content": {
                "text": "S3 Standard ストレージクラスは 99.99% のアベイラビリティー、S3 標準 – IA ストレージクラス、S3 Intelligent-Tiering ストレージクラスおよび S3 Glacier Instant Retrieval ストレージクラスは 99.9% のアベイラビリティー、S3 1 ゾーン – IA ストレージクラスは 99.5% のアベイラビリティー、S3 Glacier Flexible Retrieval および S3 Glacier Deep Archive クラスは 99.99% のアベイラビリティーおよび 99.9% の SLA に設計されています。これらのストレージクラスはすべて Amazon S3 サービスレベルアグリーメントによって裏付けられています。"
              },
              "location": {
                "s3Location": {
                  "uri": "s3://YOUR-BUCKET/s3/02.txt"
                },
                "type": "S3"
              },
              "metadata": {
                "x-amz-bedrock-kb-source-uri": "s3://YOUR-BUCKET/s3/02.txt",
                "x-amz-bedrock-kb-chunk-id": "589b2b34-a102-4025-8dee-88ac7c337c13",
                "x-amz-bedrock-kb-data-source-id": "MJ3FBDFWAX"
              }
            },
            {
              "content": {
                "text": "お客様は、データを 1 つの AZ に保存してストレージコストやレイテンシーを最小限に抑えたり、データセンター全体が永久に失われても回復できるように複数の AZ に保存したり、地理的な耐障害性要件を満たすために複数の AWS リージョンに保存したりできます。"
              },
              "location": {
                "s3Location": {
                  "uri": "s3://YOUR-BUCKET/s3/05.txt"
                },
                "type": "S3"
              },
              "metadata": {
                "x-amz-bedrock-kb-source-uri": "s3://YOUR-BUCKET/s3/05.txt",
                "x-amz-bedrock-kb-chunk-id": "324aeea4-a14e-4949-9fb2-b186a513f579",
                "x-amz-bedrock-kb-data-source-id": "MJ3FBDFWAX"
              }
            },
            {
              "content": {
                "text": "Amazon S3 はどの程度信頼できますか?  Amazon S3 によって、高度にスケーラブルで可用性も高く、かつ高速で安価なデータストレージインフラストラクチャを利用できるようになります。このインフラストラクチャは、Amazon が使用しているウェブサイトのグローバルネットワークと同じものです。"
              },
              "location": {
                "s3Location": {
                  "uri": "s3://YOUR-BUCKET/s3/02.txt"
                },
                "type": "S3"
              },
              "metadata": {
                "x-amz-bedrock-kb-source-uri": "s3://YOUR-BUCKET/s3/02.txt",
                "x-amz-bedrock-kb-chunk-id": "3d4fac0c-65a7-4b9d-b6b2-c958bac7d9e8",
                "x-amz-bedrock-kb-data-source-id": "MJ3FBDFWAX"
              }
            }
          ]
        }
      },
      "results": [
        {
          "metricName": "Builtin.ContextRelevance",
          "evaluatorDetails": [
            {
              "modelIdentifier": "arn:aws:bedrock:us-east-1:123456789012:inference-profile/us.anthropic.claude-3-7-sonnet-20250219-v1:0",
              "explanation": "{\"passage_0\": \"\\n    The question asks \\\"How much data can be stored in Amazon S3?\\\" (in Japanese).\\n    \\n    The passage directly answers this question by stating:\\n    - There is no limit to the total amount of data and number of objects that can be stored in Amazon S3\\n    - Individual Amazon S3 objects can range from 0 bytes to 5 TB\\n    - The maximum size for a single PUT upload is 5 GB\\n    - For objects larger than 100 MB, multipart upload is recommended\\n    \\n    The passage provides complete and specific information that directly answers the question about Amazon S3 storage capacity. It addresses both the overall storage limits (unlimited) and the specific object size limitations.\\n  \", \"passage_1\": \"\\n    The question asks \\\"How much data can be stored in Amazon S3?\\\" (translated from Japanese).\\n    \\n    The passage discusses Amazon S3's durability, stating that it provides 99.999999999% (eleven nines) data durability and stores data redundantly across at least 3 Availability Zones. However, the passage does not provide any information about the storage capacity limits of Amazon S3 or how much data can be stored in it.\\n    \\n    The passage talks about the reliability and durability of the storage, but not about the maximum amount of data that can be stored. These are different aspects of the storage service.\\n    \\n    Therefore, the passage does not contain the information necessary to answer the question about Amazon S3's storage capacity limits.\\n  \", \"passage_2\": \"\\n    The question asks about how much data can be stored in Amazon S3 (\\\"Amazon S3 \\u306b\\u306f\\u3069\\u308c\\u304f\\u3089\\u3044\\u306e\\u91cf\\u306e\\u30c7\\u30fc\\u30bf\\u3092\\u4fdd\\u5b58\\u3067\\u304d\\u307e\\u3059\\u304b?\\\"), which is asking about storage capacity limits.\\n    \\n    The passage provided only discusses the availability percentages (\\u30a2\\u30d9\\u30a4\\u30e9\\u30d3\\u30ea\\u30c6\\u30a3\\u30fc) of different S3 storage classes (99.99%, 99.9%, 99.5%, etc.) and mentions the Service Level Agreement (SLA). It talks about reliability metrics but does not provide any information about storage capacity limits or how much data can be stored in Amazon S3.\\n    \\n    Since the passage does not contain any information about storage capacity or data volume limits, which is what the question is asking about, the passage is not relevant to answering the question.\\n  \", \"passage_3\": \"\\n    The question asks about how much data can be stored in Amazon S3 (storage capacity limits). The passage discusses where data can be stored in terms of Availability Zones (AZs) and AWS Regions, and mentions considerations about storage costs, latency, and disaster recovery. However, it does not provide any information about the actual storage capacity limits of Amazon S3 or how much data can be stored in the service. The passage talks about storage location options and redundancy, but not storage capacity limits, which is what the question is specifically asking about.\\n  \", \"passage_4\": \"\\n    The question asks about the storage capacity of Amazon S3 - specifically how much data can be stored in Amazon S3.\\n    \\n    The passage discusses Amazon S3's reliability, scalability, availability, speed, and cost-effectiveness. It mentions that Amazon S3 provides a \\\"highly scalable\\\" data storage infrastructure, which indirectly relates to capacity, but it does not provide any specific information about the actual storage limits or capacity of Amazon S3.\\n    \\n    While the passage mentions that Amazon S3 is a data storage service and that it's \\\"highly scalable,\\\" it doesn't directly answer the question about how much data can be stored. The scalability aspect suggests large capacity, but no specific numbers or limits are provided.\\n    \\n    The passage is about Amazon S3 and mentions its storage capabilities in general terms, but doesn't provide the specific information requested in the question.\\n  \"}"
            }
          ],
          "result": 0.3
        },
        {
          "metricName": "Builtin.ContextCoverage",
          "evaluatorDetails": [
            {
              "modelIdentifier": "arn:aws:bedrock:us-east-1:123456789012:inference-profile/us.anthropic.claude-3-7-sonnet-20250219-v1:0",
              "explanation": "Let's analyze the ground-truth answer and compare it with the information provided in the passages:\n\nGround-truth answer has two main points:\n1. There is no limit to the total amount of data and number of objects that can be stored in Amazon S3.\n2. Individual object size can be up to 5TB.\n\nLooking at the passages, the first passage directly states: \"Amazon S3 に格納可能なデータの総量とオブジェクトの数には制限はありません。個別の Amazon S3 オブジェクトのサイズは、最低 0 バイトから最大 5 TB までさまざまです。\" This completely covers both points in the ground-truth answer.\n\nThe passage even provides additional information about upload limitations and multipart upload functionality, but these details are not part of the ground-truth answer we're evaluating against.\n\nSince all of the information in the ground-truth answer is fully supported by the passages, the appropriate rating is 'Yes'."
            }
          ],
          "result": 1.0
        }
      ]
    }
  ]
}

		

DuckDBを使ったS3ログの分析

以下では OLAP が得意な DMBS である DuckDB でこのS3の JSONL 形式の評価ジョブファイルを SQL で分析する方法を紹介します。

DuckDBのインストール

DuckDBをインストールし、JSONLファイルを読み込める状態にします。

			
			# macOSの場合
brew install duckdb

# DuckDB CLIを起動
duckdb --version
v1.3.2 (Ossivalis) 0b83e5d2f6

		

$ duckdb でCLI起動し、 $ duckdb -ui とするとブラウザインターフェースが起動します。

後者はノートブック連携できたりと、ユーザー体験が優れているため、CLI 操作に慣れていない場合は、ブラウザ版をオススメします

https://duckdb.org/2025/03/12/duckdb-ui.html

DuckDBとS3の連携

DuckDB は ローカルファイルシステムに対してSQLを投げることも Amazon Athena のように S3オブジェクトをソースとしてSQLを投げることもできます。

ローカルファイルシステムにSQLを投げる

この場合、S3上のファイルをローカルにダウンロードしましょう

			
			$ aws s3 sync s3://YOUR-BUCKET/OUTPUT-PREFIX/JOB-NAME .

		

S3にSQLを投げる

IAM RoleをAssumeできるようにした状態で、以下を実行しましょう。

また、リージョン(AWS_REGION) をソースとするS3バケットに合わせましょう。

			
			$ export AWS_REGION=us-east-1
$ duckdb
D INSTALL httpfs;
D LOAD httpfs;

D CREATE SECRET (
      TYPE S3,
      PROVIDER CREDENTIAL_CHAIN
  );
┌─────────┐
│ Success │
│ boolean │
├─────────┤
│ true    │
└─────────┘

		

永続的なキーを利用する場合は以下のようにSECRETを定義します

			
			$ duckdb
D INSTALL httpfs;
D LOAD httpfs;

D CREATE SECRET (
    TYPE S3,
    KEY_ID 'AKIAXXX',
    SECRET 'wJalXXX',
    REGION 'us-east-1'
);

		

テーブル作成(DDL)

このJSONLを CREATE TABLE AS SELECT(CTAS)で eval_results テーブルを定義します。

ポイントは以下です。

  • Bedrock Knowledge Base連携時の「検索のみ(Retrieval only)」 決め打ち
    • カスタムメトリクスや「検索と生成:Retrieval and response generation」は想定外
  • JSONL のため read_json_auto 関数を使って変換しています https://duckdb.org/docs/stable/data/json/loading_json.html
  • この関数の引数に S3 またはローカルファイルシステムパスを指定します
    • S3 : read_json_auto('s3://BUCKET/eval/results/*/*/inference_configs/0/datasets/RagDataset/*_output.jsonl', ...)
    • ファイルシステム : read_json_auto('./results/*/*/inference_configs/0/datasets/RagDataset/*_output.jsonl', ...)
  • 理由(explanation)の違い
    • context_coverage_explanation は 文字列 のため、そのまま VARCHR 型で取り込む
    • context_relevance_explanation は JSON文字列 のため、取り込み時に VARCHAR 型ではなく JSON 型にCASTして取り込む

例えば、「検索のみ(Retrieval only)」評価ジョブと「検索のみ:Retrieval only」評価ジョブが混在すると、評価メトリクスの違いから、想定するテーブル定義も異なります。

評価ジョブの出力先は、評価方法 x RAGシステム ごとに分割し、 read_json_auto 関数には、apple-to-apple で比較可能な評価ジョブが参照されるように設計しましょう。

具体的なDDLは以下の通りです

			
			
CREATE OR REPLACE TABLE eval_results AS
WITH base_data AS (
    SELECT
        filename as file_path,
        regexp_extract(filename, 'results/([^/]+)/', 1) as job_name,
        regexp_extract(filename, 'results/[^/]+/([^/]+)/', 1) as job_id,
        regexp_extract(filename, '([^/]+)$', 1) as file_name,
        conversationTurns
    FROM read_json_auto(
        './results/*/*/inference_configs/0/datasets/RagDataset/*_output.jsonl',
        filename:=true,
        format:='newline_delimited'
    )
),
expanded AS (
    SELECT
        file_path,
        job_name,
        job_id,
        file_name,
        row_number() OVER (PARTITION BY job_id, file_name ORDER BY 1) as row_num,
        conversationTurns[1].output.knowledgeBaseIdentifier as kb_id,
        conversationTurns[1].inputrecord.prompt.content[1].text as prompt,
        conversationTurns[1].inputrecord.referenceresponses[1].content[1].text as reference_response,
        array_length(conversationTurns[1].output.retrievedresults.retrievalresults) as retrieved_doc_count,
        unnest(conversationTurns[1].results) as metric
    FROM base_data
)
SELECT
    file_path,
    job_name,
    job_id,
    file_name,
    row_num,
    kb_id,
    prompt,
    reference_response,
    retrieved_doc_count,
    MAX(CASE WHEN metric.metricName = 'Builtin.ContextRelevance' THEN metric.result END) as context_relevance,
    MAX(CASE WHEN metric.metricName = 'Builtin.ContextRelevance' THEN metric.evaluatorDetails[1].explanation END) as context_relevance_explanation,
    MAX(CASE WHEN metric.metricName = 'Builtin.ContextRelevance' THEN metric.evaluatorDetails[1].modelIdentifier END) as context_relevance_modelIdentifier,
    MAX(CASE WHEN metric.metricName = 'Builtin.ContextCoverage' THEN metric.result END) as context_coverage,
    MAX(CASE WHEN metric.metricName = 'Builtin.ContextCoverage' THEN CAST(to_json(metric.evaluatorDetails[1].explanation) AS JSON) END) as context_coverage_explanation,
    MAX(CASE WHEN metric.metricName = 'Builtin.ContextCoverage' THEN metric.evaluatorDetails[1].modelIdentifier END) as context_coverage_modelIdentifier
FROM expanded
GROUP BY ALL;


		

作成されたテーブルを確認します

			
			-- データ構造を確認
DESCRIBE eval_results;


		

AWS コンソールと S3評価ジョブ結果ファイルのマッピング

S3上の評価ジョブ結果がAWSコンソール上で表示されています。

TODO:後ほど追記します

SQL分析例

以下では、作成した eval_results テーブルに対して SQL で分析します。

本記事の DDL は Bedrock Knowledge Base RAG に対して、カスタムメトリクス等を使用していない、一番シンプルなケースを前提に「検索のみ:Retrieval only」評価ジョブを実行したものです。

ポイントは以下です

  • Bedrock Evaluationsは日本語のRAGシステムの評価も行えますが、理由(explanation) は英語で述べられています。
  • メトリクスによって、理由の型が異なります。特に、 JSON で返される Context Relevance の評価コメントを SQL で見やすくするには、工夫が必要です
    • Context Coverage : String
    • Context Relevance : JSON
  • Bedrock EvaluationsによるRAGの評価は 検索のみ(Retrieval only) と 検索と生成(Retrieval and response generation)の2通りがあり、それぞれでメトリクスが異なります。本記事は 「検索のみ(Retrieval only)」です。

データをざっと確認

データをざっと確認しましょう。

			
			select * from eval_results order by job_id limit 5

		

ジョブ単位のサマリーを確認

ジョブごとに GROUP BY します

			
			SELECT
        job_id,
        job_name,
        MAX(file_path),  -- JSONL ファイルのパス
        MAX(context_relevance_modelIdentifier), -- 評価モデル
        COUNT(*) as prompt_count,
        AVG(context_coverage),
        AVG(context_relevance)
    FROM eval_results
   where job_id in ('gmzdn9d37xo2', 'cefzulgxjgwy')
      GROUP BY job_id, job_name
    ORDER BY job_name;

		

必要に応じて

  • 最大(MAX)
  • 最小(MIN)
  • 中央値(MEDIAN)

なども確認しましょう。

低スコアの網羅性の理由を確認

プロンプトデータの referenceResponses であらかじめ用意した正解データ(グラウンドトゥルース)を検索結果がどれだけ網羅できているか文章()で評価してくれます。

Varchar型 の context_coverage_explanation カラムを SELECT するだけです。

表示が長過ぎると感じた場合は、 LEFT(context_coverage_explanation, 40) AS coverage_expl_excerpt のように抜粋しましょう。

			
			SELECT
    job_id,
    row_num,
    prompt,
    context_coverage,
    context_coverage_explanation,
    LEFT(context_coverage_explanation, 40) AS coverage_expl_excerpt
from eval_results 
where context_coverage < 0.4
and job_id = 'gmzdn9d37xo2'
order by context_coverage asc;

		

低スコアの関連性の理由を確認

コンテキストの関連性(Context relevance)の評価は、検索にマッチした各チャンク(passage)に対して、関連があるかチェックします。

そのため、S3 に出力される 評価結果の生ログは次のような JSON 形式ですが、 read_json_auto 関数で JSONL ファイルを DuckDB に取り込む際に Varchar 型として(文字列のJSONとして)取り込まれます。

			
			{
  "passage_0": "評価コメント", 
  "passage_1": "評価コメント"
}

		

関連性スコアが低かったプロンプトに対して、チャンクごとの評価コメントを行展開するのが次のSQLです(Claude先生の作品)

			
			SELECT
      t.job_id,
      t.row_num,
      t.prompt,
      t.context_relevance,
      u.key AS passage_key,
      json_extract(t.context_relevance_explanation, '$.' || u.key) AS passage_value
  FROM
      eval_results AS t,
      UNNEST(json_keys(t.context_relevance_explanation)) AS u(key)
  WHERE t.context_relevance < 0.3
  ORDER BY t.job_id, t.row_num, passage_key;

		

分析しやすい評価ジョブ作成のコツ

S3の生ログを分析に利用する場合、評価ジョブ作成時にいくつか気をつけるべき点があります。

			
			s3://YOUR-BUCKET-NAME/
├── results-{KnowledgeBase-Id-Bar}-Retrieval-Only # 評価方法 x RAGシステム ごとにS3出力先を分ける
└── results-{KnowledgeBase-Id-Foo}-Retrieval-Only # 評価方法 x RAGシステム ごとにS3出力先を分ける
    ├── {KnowledgeBase-Id-Foo}-retrieval-only-20250910004252 # ジョブ名にタイムスタンプを含める
    │   ├── amazon-bedrock-evaluations-permission-check
    │   └── gmzdn9d37xo2
    │       └── inference_configs
    │           └── 0
    │               └── datasets
    │                   └── RagDataset
    │                       └── 0d248a22-079e-4626-a2d1-8adaaa8fa71e_output.jsonl
    └── {KnowledgeBase-Id-Foo}-retrieval-only-20250910020852 # ジョブ名にタイムスタンプを含める
        ├── amazon-bedrock-evaluations-permission-check
        └── cefzulgxjgwy
            └── inference_configs
                └── 0
                    └── datasets
                        └── RagDataset
                            └── 7d36ced6-8d91-476e-b5d2-9386636f5b4f_output.jsonl

		

評価方法 x RAGシステム ごとにS3出力先を分ける

DuckDBからS3を直接参照する場合も、ローカルにコピーする場合も、JSONL ファイルは read_json_auto 関数で指定します。

apple-to-apple(同一条件下)な一貫した分析をするという意味では、 評価方法 x RAGシステム ごとにS3出力先を分割するとよいでしょう。

Bedrock Evaluationsの評価は以下の2方式があり、評価メトリクスがそもそも異なります

  • 検索のみ:Retrieval only
  • 検索と生成:Retrieval and response generation

DDL(テーブル定義)と評価メトリクスは 1:1 なので、分析対象ファイル群の評価方法は同一である必要があります。
また、異なるRAGシステムのジョブをまたいで、検索精度を比較することも稀でしょう。

分析したい粒度、例えば評価方法 x RAGシステム ごとに評価ジョブのS3出力先を分割しましょう。

ワイルドカード指定は便利な一方で、含めるべきでないレポートも含めてしまうリスクがあります。

ジョブ名にタイムスタンプを含める

以下の階層構成でジョブ結果が出力されます。

			
			s3://YOUR-BUCKET-NAME/OUTPUT-PREFIX
└── {Evaluation-Job-Name}
    ├── amazon-bedrock-evaluations-permission-check
    └── {Evaluation-Job-Id}
        └── inference_configs
            └── 0
                └── datasets
                    └── RagDataset
                        └── {uuid}_output.jsonl

		

ジョブIDは gmzdn9d37xo2 のようなランダムな文字列です。

いつ実施されたジョブなのか復元できるよう、ジョブ名を「ナレッジベースID-{検索,検索&生成}- タイムスタンプ 」のようにしておくと良いでしょう。

ジョブ一覧はコンソールでフラットに表示されるため、ナレッジベースの識別子や評価方法も含めるのがオススメです。

まとめ

Bedrock Evaluations の特徴は、AWSコンソールから簡単にLLMを使ったRAGの検索精度の評価を行えることです(LLM As as Judge)。
しかも、生ログはS3に JSONL 形式で出力されているため、DuckDB 等から SQL 操作することもできます。

本記事は、後者に着目し、S3に出力される Amazon Bedrock EvaluationsのRAG評価ログをDuckDBで分析する方法を紹介しました。

システマチックにRAGの検索精度の改善サイクルを回したい場合、今回のようにS3の生ログを活用することで、より柔軟な分析や評価の自動化が可能になります。

Bedrock Evaluations RAG の検索だけを評価する場合で、コンソールから操作する方法は次のブログにまとめています。Bedrock Evaluationsを使い始めるなら、ここからがオススメです。

https://dev.classmethod.jp/articles/intro-to-bedrock-evaluations-rag-with-search-only/

本記事は、このコンソール前提ブログのS3生ログへのSQL分析版です。

Bedrock Knowledge Baseに対して Bedrock EvaluationsでRAG評価する方法の概要は次のブログにまとめています。

https://dev.classmethod.jp/articles/bedrock-evaluations-rag-knowledge-bases-llm-judge/

ではでは

参考リンク

この記事をシェアする

FacebookHatena blogX

関連記事