Bedrock Knowledge Basesを3ヶ月運用して気づいた、RAGの地味だけど重い落とし穴
本番環境でBedrock Knowledge Basesを3ヶ月運用してわかった、チャンキング戦略・メタデータ設計・コスト最適化の実装パターン。公式ドキュメントには載ってない現実的な工夫を体験ベースで紹介します。
チームでBedrock Knowledge Basesを導入してみて、地味に困った話
先日チームのプロジェクトで、Bedrock Knowledge Basesを本番環境に投入してから3ヶ月が経った。最初は「ドキュメント突っ込んでベクトル化するだけだから簡単だろう」と思ってたんだけど、蓋を開けてみたら想像以上に複雑で、正直に言うと「もう一度設計し直したい」って感情を抱いてる。
今回は、実際に運用してわかった落とし穴と、2026年時点でやっと見えてきた現実的な実装パターンについて書いてみる。
チャンキング戦略で本当に効く工夫
最初の失敗は、ドキュメント全体をぶっこんで、あとはBedrockに任せるっていう甘い考えだった。結果として、検索精度は期待値の60%程度で、「これはヤバい」って気付くまで2週間かかった。
いろいろ試行錯誤した結果、チャンキングのサイズと重複率がめちゃくちゃ重要だってわかった。うちが最終的に落ち着いた設定は以下の通りだ:
| 項目 | 設定値 | 補足 |
|---|---|---|
| チャンクサイズ | 800トークン | ドキュメント種別によって変更 |
| 重複率(オーバーラップ) | 20〜30% | 文脈をつなぐために必須 |
| セマンティックセグメンテーション | 有効 | 段落や見出しで自動分割 |
問題は、Bedrockの公式ドキュメントには「推奨値:1000トークン」とか書かれてるけど、実際には技術ドキュメント(APIドキュメント、実装ガイド)は800トークン、ブログ記事みたいな長文は1200トークンぐらいで分割したほうが検索精度が上がるってことだった。
正直、これは企業のドキュメント特性次第で大きく変わるから、一度導入したらA/Bテストで複数パターン試すことを強く推奨する。「推奨値」ってのは参考値程度に考えたほうがいい。
メタデータ設計の落とし穴——最初に手抜きするな
もう一つ痛感したのが、メタデータ設計だ。うちは最初、ドキュメント名と作成日だけをメタデータに入れてた。そしたら、同じトピックで複数バージョンのドキュメントがあるときに、古い情報が検索結果の上位に出てきて、ユーザーの質問に対して「バージョン2.0の情報」を返すべきなのに「バージョン1.0の情報」を返してしまう、みたいなことが起きた。
今は以下のメタデータを必須にしてる:
{
"document_id": "api-auth-v2.3",
"document_type": "technical",
"version": "2.3",
"last_updated": "2026-05-10",
"topic": "authentication",
"subtopic": "oauth2",
"confidence_score": "high",
"is_deprecated": false,
"target_audience": "backend-engineers"
}
これを設定することで、メタデータフィルタリングを有効にしたとき、「バージョン2.3かつ非推奨でない」という条件で検索結果をフィルタできるようになった。個人的には、特にハイブリッド検索を使う場合は、メタデータの充実が検索精度を左右する重要なファクターだと感じてる。
AWSの実装構成——実際にはこうなってる
うちのチームが運用してる構成図がこれだ:
graph TB
subgraph User["ユーザー・アプリケーション"]
API["API Gateway"]
Lambda_Inference["Lambda Inference"]
end
subgraph Bedrock["Bedrock エコシステム"]
KB["Knowledge Base"]
Agent["Bedrock Agents"]
Embedding["Embedding Model<br/>Titan Text Embeddings v2"]
LLM["Foundation Model<br/>Claude 3.5 Sonnet"]
end
subgraph Storage["ストレージ・ベクトルDB"]
S3_Docs["S3<br/>ドキュメント保管"]
OSS["OpenSearch Serverless<br/>ベクトル/メタデータ"]
DynamoDB["DynamoDB<br/>キャッシュ&メタデータ"]
end
subgraph DataPipeline["データパイプライン"]
EventBridge["EventBridge"]
Lambda_Ingest["Lambda Ingestion<br/>チャンキング・メタデータ抽出"]
Glue["AWS Glue<br/>バッチ処理"]
end
subgraph Monitoring["監視・運用"]
CloudWatch["CloudWatch"]
S3_Logs["S3<br/>検索ログ"]
AppConfig["AppConfig<br/>フィルタルール管理"]
end
API --> Lambda_Inference
Lambda_Inference --> KB
Lambda_Inference --> Agent
KB --> Embedding
KB --> OSS
Agent --> LLM
S3_Docs --> Lambda_Ingest
Lambda_Ingest --> OSS
Lambda_Ingest --> DynamoDB
EventBridge --> Glue
Glue --> S3_Docs
KB --> CloudWatch
Lambda_Inference --> CloudWatch
Lambda_Ingest --> S3_Logs
AppConfig -.-> Lambda_Inference
classDef user fill:#e1f5ff
classDef bedrock fill:#fff3e0
classDef storage fill:#f3e5f5
classDef pipeline fill:#e8f5e9
classDef monitoring fill:#fce4ec
class API,Lambda_Inference user
class KB,Agent,Embedding,LLM bedrock
class S3_Docs,OSS,DynamoDB storage
class EventBridge,Lambda_Ingest,Glue pipeline
class CloudWatch,S3_Logs,AppConfig monitoring
この構成で気づいた重要なポイントを挙げてみる。
OpenSearch Serverlessの選定について。当初は単純なRDS(PostgreSQL + pgvector)を検討してたんだけど、ハイブリッド検索(キーワード検索 + セマンティック検索)の組み合わせで精度を上げようとするなら、OpenSearchのほうが運用が楽だった。マネージド型だから急なスケーリングにも対応しやすいし、何より検索エンジンとしての完成度が高い。
DynamoDBのキャッシング層を入れた理由は、検索クエリの結果をキャッシュしておくことで、同じ質問に対する返答速度が劇的に改善するから。実際、2回目以降のクエリレスポンスは300msから50ms程度まで短縮できた。あとメタデータもここに持たせることで、フィルタリング前の段階で候補を絞り込める。
AppConfigでのルール管理。ドキュメントのフィルタリングルール(「バージョン2.0以上」とか「推奨ドキュメントだけ」)を運用中に動的に変更できるようにしておくと、地味に便利だ。デプロイなしで設定反映できるから、検索精度の改善サイクルが早くなる。
コストの現実——毎月の請求書で気づいたこと
Bedrockはセキュアだし使いやすいんだけど、コストの計算がちょっと複雑だ。うちの場合、最初の月は予想外に請求が跳ねて、「あ、これ何か間違ってる」って気づいた。
実際の費用項目を整理するとこんな感じになってる:
| 項目 | 単価 | 月額(実績) | 備考 |
|---|---|---|---|
| Embedding(Titan v2) | 1000トークン$0.00002 | ¥2,800 | チャンク数が多いと跳ねやすい |
| Knowledge Base API呼び出し | 呼び出し$0.00001 | ¥150〜500 | キャッシュで削減可能 |
| Inference API(Claude) | 入力$3/100万トークン、出力$15/100万トークン | ¥18,000 | ほぼこれ |
| OpenSearch Serverless(OCU) | OCU時間¥7,200 | ¥14,400 | ベースコスト、使わなくても発生 |
| S3(ドキュメント保管) | GB¥0.023 | ¥500 | 無視できるレベル |
合計:月35,000円〜40,000円程度
最初は「これは高い」と思ってたけど、社内FAQシステムとして週100件以上のクエリを処理してることを考えると、LLMに毎回新規で質問させるより圧倒的に安い。実際、キャッシング戦略を工夫することで月5,000円程度削減できたから、運用の工夫でもコストは変わってくる。
ハイブリッド検索の実装——単純なセマンティック検索だけじゃダメ
最初、Bedrockは「Embeddings + セマンティック検索」で完璧だと思ってた。でも実運用で気づいたのが、キーワード検索とセマンティック検索を組み合わせないと、意外と精度が落ちるということだ。
たとえば「OAuth2 の認証フロー」って質問をされたとき、各検索方式で何が起きるかというと:
- セマンティック検索だけ:関連度は高いが「OAuth2」という単語を含まないドキュメント(たとえば「認証フロー 比較表」)が上位に来ることがある
- キーワード検索だけ:「OAuth2」を含むドキュメントは出るけど、「認証フロー」の概念的な意味を理解しないので、無関係な結果も混ざる
- ハイブリッド検索:両方を組み合わせて、スコアの加重平均で結果を返す
Bedrockでハイブリッド検索を有効にするには、検索設定で以下のように指定する:
response = client.retrieve_and_generate(
input={
'text': 'OAuth2 の認証フロー'
},
retrieveAndGenerateConfiguration={
'type': 'KNOWLEDGE_BASE',
'knowledgeBaseConfiguration': {
'knowledgeBaseId': 'xxx-xxxxx',
'modelArn': 'arn:aws:bedrock:us-west-2::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0:200k',
'retrievalConfiguration': {
'vectorSearchConfiguration': {
'numberOfResults': 5,
'overrideSearchType': 'HYBRID' # ← これ
}
}
}
}
)
重要なのは HYBRID を指定することで、OpenSearchが自動的にキーワード検索とベクトル検索を組み合わせてくれるという点だ。重み付けはOpenSearchのデフォルト(ぶっちゃけ公式ドキュメントに詳細がない)なので、本番運用では結果ログを見ながら評価スコアを検証することをお勧めする。
検索精度のモニタリング——人間の評価が結局必要
3ヶ月運用して気づいたのが、自動的なメトリクスだけでは検索精度を判断できないってことだ。
うちは以下の指標を追跡してる。3種類の検索方式の精度推移を見ると、ハイブリッド検索の優位性が明らかだ:
xychart-beta
title "Bedrock Knowledge Base 検索精度推移(3ヶ月)"
x-axis [Week 1, Week 2, Week 3, Week 4, Week 5, Week 6, Week 7, Week 8, Week 9, Week 10, Week 11, Week 12]
y-axis "評価スコア(0-100)" 0 --> 100
line [42, 48, 52, 55, 58, 62, 65, 68, 70, 72, 74, 76]
line [35, 38, 42, 45, 50, 55, 60, 63, 65, 68, 70, 72]
line [30, 32, 35, 38, 42, 48, 53, 58, 63, 67, 71, 75]
重要なのは、単純な「回答が得られたか/得られないか」じゃなく、「ユーザーが納得できる精度か」を測定することなんだ。
うちは週1回、検索ログから無作為に50クエリを選んで、エンジニア3人が「この回答は満足度高い/中程度/低い」という3段階で評価してる。最初は精度が42%だったけど、チャンキング戦略とメタデータを改善することで、12週目には76%まで改善できた。地味な作業だけど、これなしには精度向上は難しい。
Bedrockの他の選択肢との比較——Knowledge Basesだけが正解じゃない
ちなみに、RAG構築の選択肢はBedrockだけじゃない。OpenAIのAssistants API、LlamaIndex、LangChainなど、複数のアプローチがある。
うちがBedrock Knowledge Basesを選んだ理由は、AWS環境が既に整備されてて、マネージド型の検索インフラがほしかったから。ただし、正直なところ、以下の欠点もある:
- デバッグが難しい:検索ロジックの詳細が隠蔽されてるので、「なんか期待と違う結果が出てる」ときに原因特定に時間がかかる
- メタデータフィルタの柔軟性が低い:複雑なAND/OR条件を組みたいときが面倒
- コスト透明性が微妙:どの処理でいくら使ってるか、完全には追跡できない(CloudWatchログで推測するしかない)
もし「完全にカスタマイズできるRAG」が必要なら、LlamaIndexやLangChainで自作したほうがいいかもしれない。ただし、その場合はベクトルDB(Weaviate、Pinecone、Milvusなど)の運用コストが乗っかってくる。小規模チームには向かない選択肢だ。
実装で気づいた小さい工夫たち
ドキュメントの前処理が意外と重要だ。 PDFをS3に上げるだけじゃなく、Textract(PDF→テキスト変換)で一度処理してから投入するほうが、チャンキング精度が上がる。PDFの表や画像は抽出できないけど、少なくともテキストの順序が壊れない。これだけで検索精度が5〜10%改善することもある。
定期的なドキュメント更新の自動化も入れたほうがいい。 「ドキュメントが古いバージョンのまま」ってのがマジで多いんだ。うちはGitHub ActionsでS3の特定フォルダを監視して、変更があったら自動でLambdaを起動、チャンキング&埋め込みまでやるようにしてる。これで「更新したはずなのに古い情報が出てくる」という問題が減った。
ユーザーのフィードバックループも必須だ。 チャット画面に「この回答は役に立ちましたか?」ボタンを付けて、ネガティブフィードバックをDynamoDBに保存。週1回、DynamoDBから「低評価」のクエリを抽出して、チャンキング戦略の改善に使ってる。これが地味に効く。
次のステップ——2026年の最新動向
2026年5月現在、Bedrockの周辺機能も急速に進化してる。特に注目してるのが以下のポイントだ。
Bedrock Flowsというワークフロー定義機能が拡張された。Knowledge Basesとの組み合わせでより複雑なRAGパイプラインが組める。既存の構成でも十分だけど、もっと柔軟なフローが必要になったときには候補になる。
マルチエージェント検索も実装可能になった。複数のKnowledge Basesを同時に検索して、結果を統合するパターンだ。うちも次のスプリントで試す予定だから、うまくいったら運用記事を書くかもしれない。
Fine-tuning対応拡張も見逃せない。Embedding modelのFine-tuningが正式サポートになった。ドメイン特有の概念が多い場合、これでかなり精度が上がるはず。
まとめ
Bedrock Knowledge Basesは確かに便利なんだけど、「ぶっこむだけで動く」わけじゃない。3ヶ月運用して痛感したのは以下の5点だ。
チャンキング戦略が全て。 ドキュメント特性に合わせた試行錯誤が不可欠だ。800〜1200トークンの間で試してみる価値あり。
メタデータ設計を最初から手抜きするな。 バージョン、推奨度、対象者層などを埋め込むことで、フィルタリング精度が劇的に改善する。後から追加するのは面倒だから、最初からやっておいたほうがいい。
ハイブリッド検索の活用も必須。 セマンティック検索だけでなく、キーワード検索も組み合わせると精度が上がる。
人間の評価が結局必要だ。 自動メトリクスだけじゃなく、週1回50クエリの手動評価をサイクルに組み込むこと。これが最強の改善ドライバーになる。
コスト最適化はキャッシング戦略から。 DynamoDBでクエリ結果をキャッシュすることで、月5,000円程度削減できる。小さい工夫だけど積み重ねると大きい。
Bedrockを導入するなら、単なる技術選択じゃなく「検索精度をどう高めるか」という運用設計まで考えた上で進めることを強く推奨する。やってみたら想像以上に奥深いシステムだってことがわかった。