ストーリー
田
田中VPoE
ベクトルDB、ハイブリッド検索、メタデータフィルタリング — 個別のコンポーネントは揃った。次はこれらを統合した検索パイプラインを構築する
あなた
Retriever→Reranker→Generatorの流れですね
あ
田
田中VPoE
そうだ。各コンポーネントをどう接続し、パラメータをどう設定するかがパイプライン設計の肝だ。レイテンシとコストも考慮しながら設計しよう
あなた
フレームワークはLangChainを使いますか?
あ
田
田中VPoE
LangChainを使うが、フレームワークに依存しすぎないこと。内部で何が行われているかを理解した上で使うのがプロだ
検索パイプラインの全体設計
パイプラインの構成
検索パイプラインの全体像:
[Input Layer]
ユーザーのクエリ
↓
[Query Processing]
├── クエリの前処理(正規化、長さ制限)
├── 自動フィルタ抽出(LLM)
└── クエリのEmbedding生成
↓
[Retrieval Layer]
├── ベクトル検索(Top-20)
├── キーワード検索 / BM25(Top-20)
└── Reciprocal Rank Fusion → Top-20統合
↓
[Post-Processing Layer]
├── Reranker(Cross-Encoder)→ Top-5
├── コンテキスト圧縮(不要部分の除去)
└── 参照元メタデータの抽出
↓
[Generation Layer]
├── プロンプト構築(システムプロンプト + コンテキスト + クエリ)
├── LLM呼び出し(Claude API)
└── 出力パース(回答 + 参照元)
↓
[Output Layer]
回答テキスト + 参照ドキュメントリスト
Retriever設計
Top-K の設定指針
| パイプライン段階 | Top-K | 理由 |
|---|
| 初回検索(ベクトル/BM25) | 20〜50 | 十分な候補を確保(Recallの最大化) |
| RRF統合後 | 15〜20 | 重複除去後の統合結果 |
| Reranker後 | 3〜5 | 高精度の結果のみ(Precisionの最大化) |
| LLMに渡す | 3〜5 | コンテキストウィンドウとコストの制約 |
Top-Kの段階的絞り込み:
初回検索: 20件 × 2(ベクトル + BM25)= 40件
↓ RRF統合 + 重複除去
統合結果: 20件
↓ Reranker
最終結果: 5件 → LLMに渡す
プロンプト構築
RAG用プロンプトテンプレート
プロンプト構成:
[システムプロンプト]
あなたはNetShop社の社内ナレッジアシスタントです。
以下のルールに従って質問に回答してください:
- 提供されたコンテキストの情報のみに基づいて回答すること
- コンテキストに情報がない場合は「該当する情報が見つかりませんでした」と回答すること
- 回答の最後に参照元ドキュメントを明示すること
- 推測や外部知識での補完は行わないこと
[コンテキスト]
以下は関連するドキュメントです:
---
出典: {source_1_title}({source_1_url})
{chunk_1_content}
---
出典: {source_2_title}({source_2_url})
{chunk_2_content}
---
...
[ユーザーの質問]
{user_query}
プロンプト設計のポイント
| ポイント | 説明 |
|---|
| ハルシネーション防止 | 「コンテキストの情報のみで回答」を明示 |
| 参照元の明示 | 回答の根拠となるドキュメントを表示 |
| 不明時の対応 | 情報がない場合の回答テンプレートを定義 |
| コンテキスト量 | LLMのコンテキストウィンドウの50%以下が目安 |
| 構造化 | システムプロンプト、コンテキスト、クエリを明確に分離 |
レイテンシ最適化
パイプライン各段階のレイテンシ目安
| 段階 | レイテンシ目安 | 最適化手法 |
|---|
| クエリEmbedding | 100〜300ms | バッチ処理、キャッシュ |
| ベクトル検索 | 50〜200ms | HNSWパラメータ調整、メモリ最適化 |
| BM25検索 | 30〜100ms | インデックス最適化 |
| Reranker | 200〜500ms | 入力件数の削減、軽量モデル |
| LLM生成 | 1000〜3000ms | ストリーミング、モデル選定 |
| 合計 | 1.5〜4秒 | |
ストリーミング応答
ストリーミングの効果:
非ストリーミング:
[検索: 0.5s][Rerank: 0.3s][LLM生成: 2s][ 表示 ]
→ ユーザーの待ち時間: 2.8秒(すべて完了まで何も表示されない)
ストリーミング:
[検索: 0.5s][Rerank: 0.3s][LLM生成開始 → トークンが逐次表示...]
→ ユーザーの体感待ち時間: 0.8秒(最初のトークンが表示されるまで)
エラーハンドリング
| エラー | 対処 | ユーザーへの応答 |
|---|
| ベクトルDB接続エラー | リトライ(3回)→ キャッシュから返却 | 「一時的にエラーが発生しました。再度お試しください」 |
| Reranker APIエラー | Rerankingスキップ、検索結果をそのまま使用 | 通常通り回答(品質はやや低下) |
| LLM APIエラー | リトライ → フォールバックモデル | 「回答の生成に失敗しました」 |
| 検索結果ゼロ件 | フィルタを緩和して再検索 | 「該当する情報が見つかりませんでした。条件を変えてお試しください」 |
| コンテキスト長超過 | チャンクを要約して圧縮 | 通常通り回答 |
「パイプラインのどこが壊れても、ユーザーに適切なフィードバックを返すこと。沈黙は最悪のUXだ」 — 田中VPoE
まとめ
| ポイント | 内容 |
|---|
| パイプライン構成 | Query Processing → Retrieval → Post-Processing → Generation |
| Top-K設計 | 段階的に絞り込み。初回は広く、最終はPrecision重視 |
| プロンプト設計 | ハルシネーション防止、参照元明示、構造化プロンプト |
| レイテンシ | ストリーミング応答で体感速度を改善 |
| エラーハンドリング | 各段階でのフォールバックとユーザーへの適切なフィードバック |
チェックリスト
次のステップへ
次は「演習:検索パイプラインを構築しよう」です。ここまでの知識を統合して、NetShop社の検索パイプラインを設計しましょう。
推定読了時間: 30分