Azure OpenAIをAzure AI Searchで社内データにグラウンディングしているのに、言い回しが少し変わるだけで回答が薄くなる――。この“ブレ”は、検索の取りこぼしとノイズ混入、そしてプロンプトの曖昧さが重なって起きます。設定と設計を体系立てて整える方法を解説します。
「ほぼ同じ質問」で回答がブレる本当の理由
社内データRAG(Retrieval Augmented Generation)での回答品質は、ざっくり言うと「検索で何が取れたか」で決まります。LLM(Azure OpenAI)の能力差というより、リトリーバー(Azure AI Search)が拾うチャンクのセットが、質問の言い回しで変わってしまうことが原因になりがちです。
ブレが起きるパターンは、現場では主に次の3つに分解できます。
- 取りこぼし型:欲しい情報が載っているチャンクが上位に来ない(または来てもフィルタや閾値で落ちる)
- ノイズ混入型:似ているが別トピックのチャンクが混ざり、モデルが迷って一般論に逃げる
- 生成暴走型:コンテキストが薄い/矛盾しているのに、プロンプトが弱く推測で埋めてしまう
| 症状 | よくある原因(検索側) | よくある原因(プロンプト/生成側) | 即効性のある対処 |
|---|---|---|---|
| 言い回しが変わると急に一般論 | BM25のみで同義語に弱い/ベクターのみで固有名詞に弱い | 「根拠が無いときは答えない」ルールが無い | ハイブリッド検索+セマンティックランカー、システムプロンプト強化 |
| 同じ質問でも日によって微妙に違う | k/topが小さく、境界の順位が揺れる/ノイズが多い | temperatureが高め/長文コンテキストで注意が散る | kを増やして再ランキング、LLMに渡すチャンクを絞る、温度を下げる |
| 一部の重要条件が抜け落ちる | チャンク分割が粗く、必要箇所が埋もれる/メタ情報不足 | 回答フォーマットが自由すぎる | 見出し単位のチャンク化+メタデータ付与、回答テンプレ化 |
| 関係ない規程が混ざる | 部署/制度のフィルタが無い/セマンティック設定が弱い | 引用や根拠提示が無い | メタデータフィルタ、セマンティック構成の見直し、根拠必須化 |
先に結論:一貫性を上げる「王道の型」
回答のブレを減らす最短ルートは、次の型を“揃える”ことです。
- 検索は「ハイブリッド」(キーワードの精密さ+ベクターの意味近さ)
- 上位候補は「セマンティックランカーで再ランキング」(ノイズを落として上位を安定化)
- LLMに渡すのは「少数精鋭のチャンク」(多すぎる根拠は逆に迷いの元)
- システムプロンプトで「根拠が無ければ答えない」を固定(一般論への逃避を止める)
- ログで「検索→投入コンテキスト→出力」を見える化(原因特定が速くなる)
このうち、検索の考え方として重要なのが、Azure AI Searchのハイブリッド検索がテキスト検索とベクター検索を並列に実行し、結果をRRFで統合できる点です。
検索の一貫性を上げる:ハイブリッド検索の設計ポイント
ハイブリッド検索を「前提」にする
社内ドキュメントは、固有名詞(制度名、申請コード、部門名)も、ふわっとした表現(「例外対応」「運用ルール」)も混在します。どちらか一方に寄せると弱点が出やすいので、まずはハイブリッド検索を標準にするのが安定します。
Azure AI Searchのハイブリッド検索は、BM25(テキスト)とベクター検索(HNSWやeKNNなど)を併用し、RRFで統合します。
k と top を分けて考える(ここがブレ対策の核心)
一貫性の調整で最も効くのが k(ベクター側で何件候補を出すか) と top(最終的に返す件数) を分けて設計することです。kが小さいと、言い回しの差で「候補集合」が変わりやすく、結果として回答が揺れます。
セマンティックランカーを使う前提なら、候補を広めに集めてから再ランキングした方が安定しやすく、Microsoft Learnのハイブリッド検索の説明でも、セマンティックランカー利用時は kを50にして入力を最大化する旨が記載されています。
| パラメータ | 役割 | おすすめの考え方 | 初期値の目安 |
|---|---|---|---|
| k | ベクター検索の候補数(再ランキングに渡す母集団) | 小さすぎると取りこぼしと揺れが増える | 50(セマンティック併用時の出発点) |
| top | 最終的に返す検索結果数 | LLMに渡す前提なら、まずは多すぎない数に | 10(アプリ側でさらに5〜8に圧縮すると安定) |
| select | 返すフィールド | LLMに渡すのは「人間が読める本文フィールド」中心 | title, content, url, section など |
| filter | 部署/権限/版などの絞り込み | ノイズ削減に直結。RAGの精度はフィルタで決まる面がある | accessLevel, department, docType など |
並べ替え(orderby)を安易に入れない
検索結果の並べ替えを入れると、関連度ベースの順位付けを上書きしてしまう場合があります。ハイブリッド検索の説明でも、明示的なソートは関連度ランキングを上書きするため、類似度やBM25の関連度を活かしたいならorderbyを省くことが推奨されています。
セマンティックランカー:ノイズを落として上位を安定させる
セマンティックランカーが効く場面
「ほぼ同じ質問」なのに、上位に来るチャンクの顔ぶれが入れ替わると、LLMは途端に迷います。セマンティックランカーは、初期ランキング(BM25やRRF)で得た結果集合を、言語理解モデルで再ランク付けするため、“上位の安定化”に効きます。
ここで重要なのは、セマンティックランカーは「最初の候補集合」に対して働くことです。だからこそ、前段のk/top設計(母集団を広めに取る)が効いてきます。
rerankerScore を使って「LLMに渡すチャンク」を選別する
ハイブリッド検索ではRRF統合後にセマンティックランカーが走り、スコアは @search.rerankerScore として別枠で返ります。セマンティックランキングはRRF統合の後段で行われ、スコアが分離して報告されることが明示されています。
実務では、次のような選別が効果的です。
- LLMに渡すのは rerankerScore 上位だけ(例:上位5〜8チャンク)
- 同じ文書からのチャンクが偏るなら、文書ごとに最大nチャンクなどの制限を入れる
- どうしてもノイズが混ざるなら、閾値(例:rerankerScoreが一定以上)で足切りする
セマンティックキャプション/セマンティックアンサーを活用する
長い本文をそのままLLMに渡すほど、モデルの注意が散ってブレやすくなります。セマンティックランカーは、検索結果にキャプションを返したり、必要に応じて“答えになっている原文の抜粋(semantic answer)”を抽出する機能があります。
RAGの安定性という観点では、次の使い分けが実務向きです。
- キャプション:チャンク本文の代わりに短い要約的抜粋としてLLMに渡す(トークン削減と焦点合わせ)
- セマンティックアンサー:FAQ的に「一文で答えが載っている」ドキュメントが多い場合、根拠抽出に使う
クエリ拡張:同義の聞き方に強くする(クエリリライト+辞書)
クエリリライト(query rewriting)を検討する
ユーザーの入力は短く曖昧になりがちで、社内用語も揺れます。Azure AI Searchには、セマンティック検索の文脈でクエリをより効果的な形に変換し、用語を追加・同義語展開・スペル修正などで検索を改善する「query rewriting」の説明があります。
ただし、リライトは万能ではありません。特に「申請番号」「型番」「規程番号」のような厳密一致が必要なクエリは、リライトで文字列が変わると逆効果になり得ます。そこで実務的には、次のように“守るべきもの”を決めます。
- 保護ルール:正規表現で「IDっぽい文字列」を検出したら、BM25(キーワード)側の比重を上げる/リライトを弱める
- 業務辞書:制度名・略称・旧名称の対応表を用意し、検索前に正規化(例:「人給」→「人事給与システム」)
- クエリテンプレ:ユーザー文をそのまま投げず、「社内規程/手順/FAQのどれを探すか」を補う
日本語の“言い回し揺れ”はアナライザーと辞書の合わせ技
日本語は形態素解析や表記揺れ(全角半角、カタカナ/英字、同音異義語)の影響が大きいので、次の2点をセットで整えると安定しやすいです。
- テキスト検索のアナライザー見直し:部署名や製品名が分割されすぎないようにする
- 同義語マップ(synonym map)運用:略称・旧名称・社内用語を集約し、BM25側の取りこぼしを減らす
ドキュメント分割(チャンク設計):検索にも生成にも効く「粒度の設計」
チャンク設計は“答えのブレ”に直結します。理由は単純で、チャンクが粗いほどノイズが増え、細かすぎるほど必要情報が欠けるからです。さらに、同じ文書でも質問の言い回しでヒットする位置が変わるため、粒度が不安定だと「取れる/取れない」が起きやすくなります。
安定するチャンクの条件
- 見出し単位で意味が完結(それ単体で読んで何の話かわかる)
- 結論・条件・例外が同じチャンクに入る(途中で途切れない)
- 前後の参照が必要なら軽いオーバーラップ(直前の定義や前提を数行含める)
| 設計観点 | おすすめ | 避けたい例 | ブレとして現れる症状 |
|---|---|---|---|
| 粒度 | 章/節/箇条書きのまとまり | 文書を丸ごと1チャンク | ノイズが増え一般論へ逃げる |
| 文脈 | 定義→条件→例外を同梱 | 定義だけ別チャンクに飛ぶ | 重要条件の欠落、誤解釈 |
| 重複 | 最小限のオーバーラップ | 重複ゼロで分断 | 言い回しによりヒットが変わる |
| 見出し | 本文に「見出し文字列」を含める | 見出しはメタ情報にも残さない | 何の話か分からず薄い回答 |
表・PDF・手順書の扱い(社内データで差がつくポイント)
社内資料は表やPDFが多く、ここを雑に扱うと検索が不安定になります。おすすめは次の方針です。
- 表は「行の意味」が保たれる形でテキスト化(列見出しを繰り返す、キー=値形式にする)
- 手順書は「前提→操作→期待結果→例外」をひとまとまりにしてチャンク化
- 図表の代替テキスト(キャプションや説明文)があるなら、図と同じチャンクに寄せる
インデックス設計:メタデータが「ブレ」を止める
検索がブレる現場の多くは、「本文しか入っていないインデックス」になっています。RAGでは、メタデータを使った絞り込みや整理ができるほど安定します。
| フィールド例 | 型 | 用途 | 安定性への効き方 |
|---|---|---|---|
| docId / chunkId | 文字列 | 参照・ログ・重複排除 | 同一根拠の追跡が可能になりチューニングが速い |
| title / sectionTitle | 文字列 | セマンティック設定や表示 | 再ランキングが効きやすくなる |
| department / system | 文字列 | 絞り込み | 関係ない文書混入を強力に防ぐ |
| docType | 文字列 | 規程/手順/FAQ/議事録など | 質問意図に合った集合に固定しやすい |
| validFrom / validTo | 日付 | 版管理 | 古い規程が混ざる事故を防ぐ |
| accessLevel | 数値/文字列 | 権限制御 | 権限外データの混入を防ぐ(設計上必須) |
Embeddings(埋め込み)の調整:モデル選定より「揃え方」が重要
埋め込みの品質はもちろん重要ですが、実務でブレを生むのは「モデルそのもの」より埋め込みの作り方が文書とクエリで揃っていないケースです。次の観点をチェックすると、安定性が上がりやすいです。
- 文書側とクエリ側で同じ埋め込みモデルを使う
- 前処理(正規化)を一致させる(改行処理、URL削除、全角半角、箇条書き記号など)
- 言語が混在するなら、言語ごとにベクターフィールドを分ける/複数vectorQueriesを使う
- タイトル用ベクターと本文用ベクターを分け、質問タイプで重みを変える
Azure AI Searchのハイブリッド検索は、複数のベクターフィールドに対して複数のvectorQueriesを指定できる設計になっており、多言語や複数フィールドの戦略を取りやすいのが利点です。
プロンプト設計:「コンテキスト以外で答えない」を契約にする
検索がどれだけ良くても、プロンプトが弱いとモデルは“親切心”で補完してしまい、一般論や推測が混ざってブレます。ブレ対策では、システムプロンプトを「作文指示」ではなく契約(守るべきルール)として書くのがコツです。
システムプロンプトの実務テンプレ(例)
あなたは社内ナレッジベース回答アシスタントです。次のルールを必ず守ってください。
* 回答は、与えられた「参照コンテキスト」に書かれている内容だけを根拠に作成する。
* コンテキストに必要な情報がない場合は、推測せず「情報が見つかりませんでした」と伝え、追加で必要な確認質問を1〜3個提示する。
* 断定表現は根拠があるときだけ使用する。曖昧なときは「〜の可能性があります」などに留める。
* 回答の最後に「根拠」として、参照したコンテキストの文書名/セクション名/IDを箇条書きで示す。
* セキュリティ上、コンテキストに含まれる機密情報は必要最小限だけ引用し、個人情報はマスキングする。
ポイントは、「無いなら無いと言う」「根拠を出す」「推測禁止」を明文化することです。これだけでも、言い回しで検索が薄くなったときに一般論へ逃げる確率が下がります。
コンテキストの渡し方も“フォーマット固定”が効く
LLMに渡すコンテキストは、毎回同じ構造に揃えます。おすすめは次のような枠です。
- 文書タイトル、セクション、更新日、権限タグ
- 本文(必要ならキャプション中心)
- チャンクID(ログと照合するため)
「コンテキストはここからここまで」と境界を固定し、本文とメタ情報をセットにして渡すと、モデルが根拠を取り違えにくくなります。
Azure OpenAI On Your Data を使っている場合に見るべき設定
もし「Azure OpenAI On Your Data(管理されたRAG)」を使っている場合、検索・再ランキング・投入ドキュメント数などが内部で動きます。Microsoft Learnのトラブルシューティングでは、ワークフローが取り込み(チャンク化してインデックス)と推論(意図生成→検索→strictnessでのフィルタ→再ランキング→topNDocumentsをプロンプトへ投入)という流れで説明されています。
一貫性の観点で効きやすい調整ポイントは次の通りです。
- strictness:厳しすぎると取りこぼし、緩すぎるとノイズ混入が増える
- topNDocuments:多すぎるとノイズ、少なすぎると欠落。代表質問で最適点を探す
- チャンク設定:既定のチャンクサイズから、社内文書の構造に合わせて調整する
| 設定 | 上げると起きやすいこと | 下げると起きやすいこと | 実務的な調整のコツ |
|---|---|---|---|
| strictness | ノイズが減るが取りこぼしやすい | 拾えるが関係ない根拠が混ざる | 「言い回し違い」テストで落ちない範囲まで下げ、rerankで抑える |
| topNDocuments | 根拠過多で回答が散る | 重要条件が欠落しやすい | まずは少なめ→不足時だけ増やす“動的運用”にする |
| チャンク | 粗いとノイズが増える | 細かいと文脈が切れる | 見出し単位+軽いオーバーラップで安定 |
実装例:Azure AI Search(ハイブリッド+セマンティック)クエリの雛形
アプリ側で直接Azure AI Searchを叩く場合のイメージです。ベクター値は省略しています。
{
"search": "社内規程の例外申請の手順は?必要書類と承認者は?",
"vectorQueries": [
{
"kind": "vector",
"vector": [ ... ],
"k": 50,
"fields": "contentVector",
"exhaustive": false
}
],
"top": 10,
"select": "docId,chunkId,title,sectionTitle,content,lastUpdated,url",
"filter": "docType eq '規程' and accessLevel le 2",
"queryType": "semantic",
"semanticConfiguration": "kb-semantic-config",
"captions": "extractive"
}
運用で安定させるなら、検索結果をそのままLLMに渡さず、アプリ側で次のように整形するのがおすすめです。
- rerankerScore上位(例:5〜8件)だけを採用
- 同一docIdに偏るなら分散させる(最大2チャンクまで、など)
- 本文が長い場合はキャプション優先、本文は必要なときだけ採用
ログ設計:原因特定のために「必ず残す」項目
ブレの解消は、勘よりログが早いです。最低限、次を1リクエスト単位で保存すると、改善が加速します。
- ユーザー質問(会話履歴を含むならその要約)
- 検索クエリ(リライト後があるなら両方)
- 検索ヒット上位の docId/chunkId/score/rerankerScore と本文先頭
- LLMへ渡した最終コンテキスト(何を落としたかも)
- モデル出力と、ユーザー評価(👍/👎や自由記述)
| 評価軸 | 見る指標 | 簡易な測り方 | 改善先の当たり |
|---|---|---|---|
| 検索の再現性 | 同義質問で同じdocIdが上位に来る割合 | 代表質問セットで回す | ハイブリッド化、辞書、k/top、フィルタ |
| ノイズ耐性 | 上位チャンクのトピック純度 | 人手で上位10件だけ確認 | セマンティック設定、メタデータ強化、rerankerScore選別 |
| 回答の根拠性 | 根拠IDが回答に紐づく割合 | 回答テンプレに根拠欄を必須化 | プロンプト、コンテキスト整形、チャンク設計 |
| 一貫性 | 言い回し違いで結論が変わらない率 | 言い換え質問を複数用意 | クエリリライト、辞書、温度、コンテキスト圧縮 |
よくある失敗パターンと、効きやすい順のチェックリスト
失敗パターン:topKを増やしたのに悪化する
「拾える情報が増える=良くなる」と思いがちですが、RAGではノイズも一緒に増えるため、回答が薄くなることがあります。対策は「検索結果を増やす」ではなく、候補は増やしつつ、LLMへ渡すのは絞るです(再ランキング+選別)。
失敗パターン:チャンクが“きれい”すぎて答えに必要な文が欠ける
Markdown化や整形で不要な文を削りすぎると、「例外」「注意書き」「承認条件」などが落ち、回答がブレます。社内規程は特に、注意書きが結論を覆すことがあるため、結論・条件・例外が同梱されるチャンク設計が重要です。
チェックリスト(上から順に効きやすい)
- 検索はハイブリッド(キーワード+ベクター)になっているか
- セマンティックランカーを有効化し、kを十分に確保しているか
- メタデータフィルタ(部署/版/文書種別/権限)でノイズを落としているか
- LLMに渡すチャンク数を5〜8程度に圧縮できているか
- システムプロンプトに「根拠がなければ答えない」「推測禁止」「根拠提示」があるか
- 同義語辞書・略称対応・表記正規化が運用されているか
- ログで「検索結果」と「投入コンテキスト」を比較できるか
まとめ:ブレを減らすのは“モデル”ではなく“入力の品質”
Azure OpenAI+社内データの回答一貫性は、モデルを変える前に、まず検索結果の質と安定性を上げるのが最短です。ハイブリッド検索で取りこぼしを減らし、セマンティックランカーで上位を安定化し、LLMに渡す根拠を少数精鋭に整える。最後に、プロンプトで「根拠外の推測」を禁止し、ログで差分を見ながら詰める。
この流れを押さえると、「言い回しが変わるだけで急に一般論になる」という現象は、かなりの割合で抑え込めます。

コメント