- はじめに——「チャンキングを最適化したのに、検索精度が頭打ち」の原因
- クエリリライト・クエリ拡張とは——RAGの「前処理パイプライン」
- テクニック①:HyDE(Hypothetical Document Embeddings)
- テクニック②:Multi-Query Retrieval
- テクニック③:Step-Back Prompting
- テクニック④:会話履歴の解決(Contextual Compression)
- テクニック⑤:社内用語辞書との連携(クエリ拡張)
- テクニック⑥:クエリルーティング
- 主要フレームワーク別の実装パターン比較
- クエリリライトのコストと精度のトレードオフ
- Anthropic Contextual Retrieval——2026年の標準実装
- 実装ロードマップ——「どこから手を付けるか」
- よくある質問(Q&A)
- まとめ——「クエリの質」がRAG精度を決める
- 参考リンク・関連記事
はじめに——「チャンキングを最適化したのに、検索精度が頭打ち」の原因
RAG(Retrieval-Augmented Generation)の検索精度を上げるために、チャンキング戦略を見直し、ハイブリッド検索を導入し、評価フレームワークを整備した——それでもユーザーから「期待した回答が返ってこない」というフィードバックが減らない。
この壁にぶつかっているチームは少なくありません。原因の多くは、インデックス側や検索器の最適化に偏り、「ユーザーが入力した質問そのものを書き換える前処理」が抜け落ちていることです。
具体的には、こんな質問がRAGに投げられています。
- 「それってどうだっけ?」(前のターンの代名詞を解決できない)
- 「うちの会社の経費精算ルール教えて」(社内俗称が文書には載っていない)
- 「先月のあの件、どうなった?」(曖昧で検索キーワードが抽出できない)
- 「働き方改革って何?」(抽象的すぎて、具体的な文書とマッチしない)
これらは検索器の問題ではなく、クエリの問題です。チャンキングや埋め込みモデルをどれだけ最適化しても、入力クエリが曖昧なら検索精度は上がりません。
この記事では、2026年の標準実装テクニックとなりつつある「クエリリライト・クエリ拡張」の設計パターンを、HyDE・Multi-Query・Step-Back Prompting・会話履歴解決・社内用語辞書連携・クエリルーティングの6つの観点で整理します。LangChain・LlamaIndex・Difyでの実装例、コストと精度のトレードオフ、評価方法まで、実務に必要な情報を一気通貫で解説します。
クエリリライト・クエリ拡張とは——RAGの「前処理パイプライン」
RAGパイプラインにおける位置づけ
典型的なRAGパイプラインは以下の3段階で構成されます。
- クエリ前処理(Query Processing):ユーザーの入力を検索可能な形に変換する
- 検索(Retrieval):ベクトル検索・BM25・ハイブリッド検索などで関連文書を取得
- 生成(Generation):取得した文書をコンテキストとしてLLMが回答を生成
多くのRAG実装は、2と3を熱心にチューニングしますが、1の前処理は「ユーザー入力をそのまま使う」ことが多いのが現状です。クエリリライト・クエリ拡張は、この1番目の段階で追加のLLM呼び出しを行い、検索クエリの質を上げるテクニックの総称です。
「クエリの質を上げる」とは具体的に何か
| 問題のあるクエリ | 変換後のクエリ | 使う技術 |
|---|---|---|
| 「あれってどうだっけ?」 | 「先週議論したマーケティング戦略の予算配分はどうなったか?」 | 会話履歴解決 |
| 「経費精算のルール」 | 「経費精算 申請手順 承認フロー 上限金額」(複数言い換え) | Multi-Query |
| 「働き方改革って何?」 | 「日本における労働時間規制と労働環境改善政策の概要」(抽象化) | Step-Back |
| 「うちの経費精算」 | 「株式会社○○ 経費精算規程」(社内用語展開) | 用語辞書連携 |
| 「最新のRAG手法は?」 | 「RAG手法は、コンテキスト圧縮、ハイブリッド検索、リランキングなどがある」(仮想回答生成) | HyDE |
これらの変換を経たクエリで検索すると、ベクトル検索の精度が大きく改善します。なぜなら、埋め込み空間では「質問」と「回答」の距離が近く、「曖昧な質問」と「具体的な文書」の距離は遠いからです。
テクニック①:HyDE(Hypothetical Document Embeddings)
HyDEの基本アイデア
HyDE(ハイド:Hypothetical Document Embeddings)は、2022年にCarnegie Mellon Universityが発表した手法で、ユーザーの質問から「仮の回答」をLLMに生成させ、その仮の回答でベクトル検索するテクニックです。
「質問→検索」ではなく、「質問→仮の回答→検索」という流れを作ります。
なぜHyDEは精度が上がるのか
埋め込みモデルは「意味的に近い文章」をベクトル空間で近くに配置します。しかし、質問文と回答文は文体・構造が異なるため、ベクトル空間では意外と離れていることがあります。
- 質問:「東京の人口は?」
- 正解文書:「2024年時点で東京都の人口は約1,400万人である」
この2つは意味的には対応していますが、文体が違うためベクトル距離が遠くなりがちです。一方、HyDEで生成した仮の回答「東京の人口は約1,400万人です」は、正解文書と同じ「回答形式」のため、ベクトル空間で近くなります。
HyDEの実装例(LangChain)
from langchain.chains import HypotheticalDocumentEmbedder
from langchain.embeddings import OpenAIEmbeddings
from langchain.llms import OpenAI
base_embeddings = OpenAIEmbeddings()
llm = OpenAI()
# HyDEのembedder
embeddings = HypotheticalDocumentEmbedder.from_llm(
llm=llm,
base_embeddings=base_embeddings,
prompt_key="web_search" # 用途別のプロンプトテンプレート
)
# 通常のembeddings.embed_query()と同じインターフェースで使える
query_embedding = embeddings.embed_query("東京の人口は?")
# 内部で「東京の人口は約1,400万人です」のような仮回答を生成し、その埋め込みを返す
HyDEが効くケース・効かないケース
| 効くケース | 効かないケース |
|---|---|
| 事実確認系の質問(「○○とは?」「○○の数字は?」) | LLMが事実誤認をする可能性が高い専門領域 |
| 一般知識でカバーできるドメイン | 社内固有・最新情報が中心のRAG |
| 質問文と文書の文体が大きく異なる | もともと質問形式のFAQが文書側にある |
注意:HyDEはLLMが「ハルシネーション」した仮回答を作る可能性があります。社内文書RAGなど、外部知識が役に立たない領域では精度が下がることもあります。必ずA/Bテストで効果を検証してください。
テクニック②:Multi-Query Retrieval
Multi-Queryの基本アイデア
Multi-Query Retrievalは、1つの質問をLLMに「複数の言い換え」に展開させ、それぞれで検索し、結果を統合する手法です。
例えば「経費精算のルールを教えて」という質問は、以下のように展開されます。
- 経費精算の申請手順
- 経費精算の承認フロー
- 経費精算の上限金額
- 経費精算規程
各クエリで検索した結果を統合し、重複を除去して上位N件を採用します。
なぜMulti-Queryは精度が上がるのか
ユーザーの1つの質問は、文書側では複数の表現で書かれていることが多いです。1つのクエリだけだと「マッチする文書」が見落とされる可能性があります。Multi-Queryで複数の表現で検索することで、ベクトル検索の「再現率(Recall)」を大きく改善できます。
Multi-Queryの実装例(LangChain)
from langchain.retrievers.multi_query import MultiQueryRetriever
from langchain.chat_models import ChatOpenAI
llm = ChatOpenAI(temperature=0)
retriever = MultiQueryRetriever.from_llm(
retriever=vector_store.as_retriever(),
llm=llm,
# デフォルトでは3つの言い換えを生成
)
# 内部で3つのクエリに展開し、それぞれで検索、結果を統合
docs = retriever.get_relevant_documents("経費精算のルールを教えて")
Multi-Queryのコスト
Multi-Queryは1質問あたり「LLM呼び出し1回 + 検索N回」のコストがかかります。N=3の場合、検索コストは3倍、LLMコストは1回追加です。本番運用では、以下のチューニングが必要です。
- 言い換えの数(通常3〜5が最適)
- 各クエリの結果統合方法(Reciprocal Rank Fusion推奨)
- キャッシュ戦略(同じ質問は再展開しない)
テクニック③:Step-Back Prompting
Step-Backの基本アイデア
Step-Back Promptingは2023年にGoogle DeepMindが発表した手法で、「具体的すぎる質問」を一段抽象化してから検索するテクニックです。
例:
- 具体的な質問:「2023年第3四半期のiPhone 15 Proの北米での販売台数は?」
- Step-Backクエリ:「iPhone 15シリーズの2023年の販売実績の概要」
抽象化したクエリでまず関連文書を広く取得し、その後で具体的な情報を抽出します。
なぜStep-Backは精度が上がるのか
具体的すぎる質問は、文書中のごく一部にしかマッチしません。一方、抽象化した質問は文書の「文脈」全体にマッチしやすいため、関連度の高い文書群を取得できます。
特に、複雑な推論を必要とする質問(「なぜ?」「どのように?」)で効果的です。
Step-Backの実装パターン
step_back_prompt = """
以下の質問を一段抽象化してください。
具体的な数字や固有名詞を取り除き、より広い視点での質問に変換してください。
元の質問: {original_question}
抽象化した質問:
"""
# 1. Step-Backクエリで広く検索
abstract_query = llm.invoke(step_back_prompt.format(original_question=question))
abstract_docs = retriever.get_relevant_documents(abstract_query)
# 2. 元のクエリでも検索
original_docs = retriever.get_relevant_documents(question)
# 3. 統合してLLMに渡す
context = abstract_docs + original_docs
answer = llm.invoke(f"以下の文書を参考に質問に答えてください: {context}\n質問: {question}")
テクニック④:会話履歴の解決(Contextual Compression)
会話履歴解決が必要な理由
RAGがチャットボットとして使われる場合、ユーザーは前のターンを参照する質問を投げます。
- ユーザー:「経費精算の上限はいくら?」
- RAG:「出張費は1日あたり10,000円が上限です」
- ユーザー:「それを超えた場合は?」 ← この「それ」が解決できない
「それを超えた場合は?」という単独のクエリでは、ベクトル検索は何もヒットしません。会話履歴を考慮して「出張費が1日10,000円の上限を超えた場合の処理」というクエリに再構築する必要があります。
会話履歴解決の実装パターン
history_resolution_prompt = """
以下の会話履歴と最新の質問を読み、最新の質問を「単独で意味が通る完全な質問文」に書き換えてください。
代名詞や省略された主語・目的語を、会話履歴から補完してください。
会話履歴:
{chat_history}
最新の質問: {latest_question}
書き換えた質問:
"""
resolved_query = llm.invoke(history_resolution_prompt.format(
chat_history=conversation.get_history(),
latest_question=user_input
))
docs = retriever.get_relevant_documents(resolved_query)
LangChainのConversationalRetrievalChain
LangChainには、この処理を自動化するConversationalRetrievalChainが用意されています。
from langchain.chains import ConversationalRetrievalChain
chain = ConversationalRetrievalChain.from_llm(
llm=llm,
retriever=retriever,
# 内部でcondense_question_promptを使い、会話履歴と新質問から
# スタンドアロンな質問を生成してから検索する
)
result = chain({"question": user_input, "chat_history": history})
テクニック⑤:社内用語辞書との連携(クエリ拡張)
社内俗称・略称の問題
企業のRAGで頻発するのが、「社内で使われる略称・俗称が、正式文書に載っていない」問題です。
| ユーザーの入力(俗称) | 文書側の表記(正式名称) |
|---|---|
| 「マネ会」 | 「マネジメント会議」 |
| 「経費シス」 | 「経費精算システム」 |
| 「○○本部」 | 「○○事業本部」(正式名称) |
| 「ICT統」 | 「情報通信技術統括部」 |
これらは社内の人にしか分からない表現で、ベクトル検索でもマッチしにくいです。
用語辞書を使ったクエリ拡張
社内用語辞書({"マネ会": "マネジメント会議", "経費シス": "経費精算システム", ...})を用意し、クエリに含まれる俗称を正式名称に展開(または併記)します。
def expand_query_with_glossary(query: str, glossary: dict) -> str:
"""社内用語辞書でクエリを拡張"""
expanded = query
for slang, formal in glossary.items():
if slang in query:
# 俗称を正式名称に置換、または併記
expanded = expanded.replace(slang, f"{slang}({formal})")
return expanded
# 使用例
query = "マネ会の議事録ある?"
expanded = expand_query_with_glossary(query, company_glossary)
# → "マネ会(マネジメント会議)の議事録ある?"
docs = retriever.get_relevant_documents(expanded)
動的な辞書管理
辞書は手作業ではなく、以下のような自動化が望ましいです。
- 社内Wiki・Slackから略称・正式名称のペアを抽出
- 「検索失敗(0件ヒット)したクエリ」をログ化し、辞書追加候補とする
- LLMで「このクエリに含まれる略称・俗称を抽出してください」と前処理する
テクニック⑥:クエリルーティング
クエリルーティングが必要な理由
すべての質問をベクトル検索に投げるのは非効率です。質問の種類によって、最適な検索手段は異なります。
| 質問の種類 | 最適な検索手段 |
|---|---|
| 「経費精算のルールは?」(概念検索) | ベクトル検索 |
| 「ID 12345の注文ステータスは?」(ID検索) | SQL / API直接呼び出し |
| 「2024年の売上トップ10は?」(集計) | SQL(DB直接クエリ) |
| 「○○という固有名詞を含む文書」 | BM25(キーワード検索) |
| 「最新の天気は?」(リアルタイム情報) | API呼び出し(外部) |
クエリルーティングは、LLMに質問内容を分類させ、適切な検索手段を選択する仕組みです。
クエリルーティングの実装パターン
routing_prompt = """
以下の質問を分類してください。
選択肢:
- VECTOR_SEARCH: 概念や説明を求める質問
- SQL_QUERY: 集計・統計・特定IDを参照する質問
- BM25_SEARCH: 固有名詞や特定の用語を含む文書検索
- API_CALL: リアルタイム情報や外部データが必要な質問
質問: {question}
分類(VECTOR_SEARCH/SQL_QUERY/BM25_SEARCH/API_CALL のいずれか):
"""
route = llm.invoke(routing_prompt.format(question=user_query))
if route == "VECTOR_SEARCH":
docs = vector_retriever.get_relevant_documents(user_query)
elif route == "SQL_QUERY":
docs = sql_agent.query(user_query)
elif route == "BM25_SEARCH":
docs = bm25_retriever.get_relevant_documents(user_query)
elif route == "API_CALL":
docs = api_tool.invoke(user_query)
LangChainのRouterChain / LlamaIndexのRouterQueryEngine
主要フレームワークには、ルーティング機能が組み込まれています。
- LangChain:
MultiPromptChain、RouterChain - LlamaIndex:
RouterQueryEngine、SubQuestionQueryEngine - Dify:ワークフロー機能の「Question Classifier」ノード
主要フレームワーク別の実装パターン比較
| 機能 | LangChain | LlamaIndex | Dify |
|---|---|---|---|
| HyDE | HypotheticalDocumentEmbedder | HyDEQueryTransform | カスタムノードで実装 |
| Multi-Query | MultiQueryRetriever | QueryRewriter | 並列検索ワークフロー |
| Step-Back | カスタムプロンプトで実装 | StepBackQueryEngine(実験的) | ワークフローで実装 |
| 会話履歴解決 | ConversationalRetrievalChain | ChatEngine | 会話変数 + LLMノード |
| クエリルーティング | RouterChain | RouterQueryEngine | Question Classifierノード |
| ノーコード対応 | × | △(一部) | ○(GUI完備) |
選定の目安:
- 細かいカスタマイズが必要 → LangChain
- RAG特化で高度な機能 → LlamaIndex
- 非エンジニアと協業・GUI重視 → Dify
クエリリライトのコストと精度のトレードオフ
追加コストの内訳
クエリリライト・拡張は、必ず追加のLLM呼び出しが発生します。本番運用では、以下のコスト試算が必要です。
| テクニック | 追加LLM呼び出し | 追加検索回数 | レイテンシ増加 |
|---|---|---|---|
| HyDE | 1回 | 0回(検索クエリは1つ) | +0.5〜1秒 |
| Multi-Query (N=3) | 1回 | 2回追加(合計3回) | +1〜2秒 |
| Step-Back | 1回 | 1回追加(元 + Step-Back) | +0.5〜1秒 |
| 会話履歴解決 | 1回 | 0回 | +0.5〜1秒 |
| 用語辞書拡張 | 0回(辞書置換のみ) | 0回 | ほぼ0 |
| クエリルーティング | 1回 | 0回(1つの手段に振り分け) | +0.5〜1秒 |
すべて組み合わせると、1質問あたりLLM呼び出しが3〜5回追加される可能性があります。GPT-4クラスを使うと、1クエリあたり0.05〜0.1ドル程度のコストになります。
コスト削減の打ち手
- 用語辞書拡張は最優先:LLM呼び出しゼロでクエリ品質が改善
- クエリリライト用は軽量モデル:GPT-4ではなくGPT-4o-mini、Claude Haiku、Gemini Flashなど
- キャッシュ戦略:同じ質問は前処理結果をRedisにキャッシュ
- 分岐実装:シンプルな質問は前処理スキップ(短い・代名詞なし・固有名詞ありなら直接検索)
精度改善の評価方法
クエリリライトの効果は、必ず定量的に評価してください。評価指標の例:
- Hit Rate@K:上位K件に正解文書が含まれる割合
- MRR (Mean Reciprocal Rank):正解文書の順位の逆数の平均
- NDCG:順位を考慮した関連度スコア
- End-to-End評価:最終的な回答の正確性(RAGAS、LangSmith等)
評価駆動開発(RAG Evaluation)の詳細は、こちらの記事もご参照ください。
Anthropic Contextual Retrieval——2026年の標準実装
2024年9月にAnthropicが発表した「Contextual Retrieval」も、クエリリライト・拡張の系譜にある手法です。
Contextual Retrievalの基本
各チャンクに、その文脈を説明する短い文(50〜100トークン)をLLMで生成して埋め込み、検索精度を改善する手法です。HyDEが「クエリ側を仮回答化する」のに対し、Contextual Retrievalは「文書側に文脈を付加する」発想です。
Anthropicの実験では、Contextual RetrievalとBM25を組み合わせ、さらにReranking(再ランキング)を加えることで、検索失敗率を最大67%削減できたと報告されています。
クエリリライトとの組み合わせ
Contextual Retrievalは「文書側の最適化」、クエリリライトは「入力側の最適化」であり、両者は補完関係にあります。2026年の標準実装としては、以下の組み合わせが推奨されます。
- 会話履歴解決でスタンドアロンな質問に変換
- 用語辞書で社内俗称を展開
- クエリルーティングで検索手段を選択
- 必要ならMulti-QueryまたはHyDEで検索クエリを拡張
- Contextual Retrieval + ハイブリッド検索(ベクトル + BM25)
- Rerankerで上位N件を再ランキング
- 取得した文書でLLMが回答生成
実装ロードマップ——「どこから手を付けるか」
すべてを一度に実装するのは現実的ではありません。投資対効果(ROI)の高い順に段階的に導入することを推奨します。
フェーズ1:低コスト・高効果(まず実装)
- 会話履歴解決:チャットボット型RAGの必須機能。代名詞・省略の解決
- 社内用語辞書:LLM呼び出し不要、辞書置換のみ
フェーズ2:中コスト・高効果
- クエリルーティング:質問の種類で検索手段を分岐
- Multi-Query Retrieval:再現率を上げたい場面で導入
フェーズ3:要評価で導入判断
- HyDE:ドメインによって効果が分かれる。A/Bテスト必須
- Step-Back Prompting:複雑な推論を要する質問が多いRAGで検討
フェーズ4:大規模システムで標準化
- Contextual Retrieval:文書側最適化と組み合わせ
- Reranker導入:CohereやBGEの再ランキングモデル
よくある質問(Q&A)
Q1. クエリリライトは必ず効果がありますか?
「必ず」効果がある手法はありません。RAGの対象ドメイン、ユーザーの質問パターン、文書の性質によって効果は異なります。必ずA/Bテストで検証してから本番投入してください。特にHyDEは、社内固有情報が中心のRAGでは精度が下がるケースもあります。
Q2. すべてのテクニックを同時に使うべきですか?
いいえ。テクニックを増やすほどコストとレイテンシが増えます。「実装ロードマップ」のフェーズ1から段階的に導入し、各段階で評価指標が改善するか確認しましょう。多くのRAGでは、フェーズ1(会話履歴解決+用語辞書)だけで体感精度が大きく改善します。
Q3. クエリリライト用のLLMは何を使うべきですか?
本回答生成には高性能モデル(GPT-4、Claude Opus等)を使い、クエリリライトには軽量・高速モデル(GPT-4o-mini、Claude Haiku、Gemini Flash等)を使うのが推奨です。クエリリライトは「文を変換するだけ」のタスクなので、軽量モデルで十分な品質が得られます。
Q4. キャッシュ戦略はどう設計しますか?
クエリリライトの結果は、入力が同じなら出力も同じになりやすいため、Redisなどのインメモリキャッシュで再利用できます。キャッシュキーには「ユーザーの元クエリ + 会話履歴のハッシュ」を使うのが一般的です。TTLは数時間〜数日で設定し、辞書更新時にはキャッシュをパージします。
Q5. 評価データセットはどう作りますか?
最低でも50〜100件の「質問+正解文書ID」のペアを作成しましょう。実際のユーザーの質問ログから抽出するのが理想です。各質問に対して「どの文書が回答に使われるべきか」を専門家が判定します。LangSmith、RAGAS、TruLensなどのツールがデータセット管理を支援します。
まとめ——「クエリの質」がRAG精度を決める
RAGの精度向上は、ついインデックス側・検索器側のチューニングに目が行きがちです。しかし、ユーザーが入力したクエリそのものが曖昧なら、どんなに高性能な検索器でも限界があります。
クエリリライト・クエリ拡張は、2026年のRAG標準実装になりつつあります。重要なポイントを再掲します。
- 段階的に導入する:会話履歴解決と用語辞書から始め、効果を測りながら追加
- 必ず評価する:A/Bテストと定量指標(Hit Rate、MRR、NDCG)で検証
- コストを管理する:軽量モデルとキャッシュでLLM呼び出しを最適化
- 文書側最適化と組み合わせる:Contextual Retrievalやハイブリッド検索と併用
RAGは「インデックス×検索器×クエリ前処理×回答生成」の総合力で精度が決まります。前処理パイプラインを侮らず、ユーザー入力の質を上げることが、これからのRAG実装で差をつけるポイントです。
参考リンク・関連記事
- HyDE論文(arXiv: Precise Zero-Shot Dense Retrieval without Relevance Labels)
- Step-Back Prompting論文(arXiv: Take a Step Back)
- Anthropic Contextual Retrieval公式ブログ
- LangChain MultiQueryRetriever公式ドキュメント
- LlamaIndex Query Transformations公式ドキュメント
- RAG評価駆動開発ガイド
- RAGハイブリッド検索設計ガイド
- RAGチャンキング戦略ガイド
免責事項:本記事は2026年4月時点の公開情報に基づく技術解説であり、特定のRAG実装における動作を保証するものではありません。本番環境への導入前には、必ず自社のデータと評価基準で検証を行ってください。各フレームワーク・ツールのバージョンによってAPIや動作が変わる可能性があるため、最新の公式ドキュメントを併せてご参照ください。

コメント