ブログ一覧

RAGの精度が上がらない原因は?検索・チャンク・評価を改善する手順

· 約11分で読めます

RAGの誤回答を、検索の取りこぼしと回答生成の誤りに分けて調べる。recall@kの計算、チャンク分割、ハイブリッド検索、権限フィルタ、pgvectorの件数不足、変更前後の評価を、社内ヘルプの例で解説します。

RAGの精度が上がらないとき、最初に検索と生成を分ける

RAG(Retrieval-Augmented Generation)は、質問に関係する資料を検索し、その根拠を使って回答を生成する方式です。社内ヘルプが誤った手順を返すとき、プロンプトの調整だけでは原因を絞れません。正解資料が索引にない、検索で落ちた、モデルへ渡す前に切れた、根拠を読み違えた、などの経路があります。

社内ヘルプの独自の設計例:各境界で根拠IDと版を追い、欠落した場所を探す

原本・更新・ACL → 解析とチャンク化 → 許可範囲の検索 → 候補の統合と再ランキング → コンテキストへ収める → 回答と根拠の検証

根拠が届かなかったことは、その資料に基づく回答を保証できないという意味です。モデルが偶然正しく答える可能性まで否定するものではありません。調査では検索結果だけでなく、実際に生成へ渡したチャンクのIDと版も確認します。全文ログには機密情報が混じりうるため、必要な調査範囲と権限を決めます。

評価セットを作る:質問・正解の根拠・利用者権限を組にする

たとえば、回答できる100問、資料に答えがない20問、権限がない資料を尋ねる20問を用意します。これは説明用の構成で、実際は業務の頻度と失敗時の影響に合わせます。質問ごとに、正解となる根拠チャンクのID集合、期待する回答の条件、利用者とテナント、資料の版・有効時点を記録します。

質問の種類正解の決め方確認したい失敗
規程の言い換え質問現行規程の根拠と必要な説明意味が近い資料を見つけられない
型番・エラーコード該当する正確な識別子と手順似たコードの資料を答える
複数資料を合わせる質問関連する根拠集合と必要な事実1件だけで回答を完成させてしまう
正解資料なし・権限なし回答を控える、追加確認する等の契約資料がないのに断定する、機密を漏らす

開発中に繰り返し見る問題と、最後の判定に使う問題を分け、評価セットへの過剰な調整を避けます。同じ文書の言い換えだけに偏らず、旧版、表、見出しをまたぐ説明、短い質問も含めます。原本や権限が変わったら、正解ラベルの版も管理します。

recall@kの計算:正解が複数ある場合の分母をそろえる

ここでは評価単位を根拠チャンクにそろえます。質問の正解集合をG、検索の上位k件をRとすると、recall@k = |R ∩ G| ÷ |G|です。質問ごとの値を単純平均する方式をmacro平均と呼びます。Gが空の質問はこの平均から除き、回答を控えられた率などで別に評価します。

質問正解集合G上位5件内の正解recall@5
Q1A・BA1/2 = 50%
Q2CC1/1 = 100%
Q3D・E・FD1/3 ≈ 33.3%

この3問のmacro recall@5は(1/2 + 1 + 1/3) ÷ 3 = 11/18、約61.1%です。一方、「正解が1つでも入った質問の率」は3/3で100%。すべての正解件数をまとめるmicro平均なら3/6で50%になります。何を分母に、どの単位で集計したかを書かないと、同じ「再現率」でも比較できません。

Python 3の計算例:macro recallと、1つでも見つかった率を分ける
cases = [
    ({"A", "B"}, ["A", "X", "Y", "Z", "W"]),
    ({"C"}, ["C", "X", "Y", "Z", "W"]),
    ({"D", "E", "F"}, ["D", "X", "Y", "Z", "W"]),
]
k = 5
recalls = [len(gold & set(found[:k])) / len(gold)
           for gold, found in cases]
hits = [bool(gold & set(found[:k])) for gold, found in cases]
print(f"macro recall@5={sum(recalls) / len(recalls):.1%}")
print(f"hit@5={sum(hits) / len(hits):.1%}")

チャンク分割を改善する:長さを変える前に、欠けた文脈を見る

「申請は30日以内」とだけ切り出されたチャンクでは、何の申請か、例外があるかが分かりません。見出し、製品名、規程の版などを一緒に保持し、表なら列名と行の意味が失われていないか確認します。原本に答えがあるのに解析で表が抜けていた場合、検索モデルを変えても直りません。

分割の症状試すこと代償・確認点
回答の条件と例外が別々になる構造を保った分割、隣接チャンクの追加無関係な情報と入力サイズも増える
同じ短い表現が大量に出る見出し・資料名などの文脈を補う補った説明の誤りや旧版混入を確認
長いチャンクが上位を占める必要な範囲への分割と重複の整理細かすぎると意味のまとまりが失われる

最適なトークン数や重なり幅は資料によって変わります。変更したら索引を作り直し、旧索引と混在しない版で評価します。同じページのほぼ同じ断片が上位を埋める場合は、重複を除くことも候補ですが、似た文面に含まれる重要な例外を落としていないか確かめます。

エラーコードに弱いなら、ハイブリッド検索とリランキングを比べる

埋め込み検索が言い換えを捉えても、識別子の完全一致をうまく順位へ反映できないことがあります。BM25などのキーワード検索を合わせ、候補を統合する方法を比較します。RRFは順位から候補を統合する方法の1つで、異なる方式のスコアをそのまま足す必要を避けられます。改善の有無は自分の質問で評価します。

候補を多めに集め、リランキングで生成へ渡す順番を見直すこともできます。ただし、候補に存在しない根拠を並べ替えで復元することはできません。候補段階のrecallと、最終的にモデルへ入る根拠のrecallを別に測り、再ランキングやコンテキスト上限で落ちた場所を特定します。

テナントで絞ると結果が足りない?近似検索のフィルタ位置を確認する

「資料はあるのに5件を要求して1件しか返らない」場合、近い候補を集めた後で権限やテナントを絞る方式が関係することがあります。仮に候補40件の各候補が対象テナントに属する確率を1%と置けば、残る期待件数は40 × 0.01 = 0.4件です。これは候補の構成に対する仮定であり、全資料での比率がそのまま当てはまる保証はありません。

pgvector v0.8.0の文書では、近似索引の探索後にフィルタが適用される挙動と、必要件数か探索上限に達するまで追加で探す反復スキャンを説明しています。探索幅・反復スキャン・パーティション・許可集合の総当たりを候補にし、同じ権限条件での総当たり結果を基準に比較します。返却件数を満たしても、業務上正しい根拠を取れたとは限りません。

根拠は届いているのに間違うなら、生成と回答の検証を調べる

正しい根拠を渡した場合でも、旧版と現行版が混ざる、条件を読み飛ばす、引用と結論が対応しないことがあります。回答に必要な事実を評価項目として分け、引用した箇所が実際にその主張を支えるか確認します。根拠が不足する場合の回答保留や追加質問の基準も用意します。

評価軸確かめること
根拠との整合渡した資料が述べていない内容を足していないか
正しさ・完全性現行の正解と一致し、必要な条件や例外を落としていないか
引用提示したID・箇所が実在し、その結論を支えるか
答えられない場合資料なし・権限なしのケースで、漏えいや根拠のない断定を避けるか

根拠に忠実でも、原本が誤っていたり古かったりすれば正しい答えにはなりません。JSONの形式検証だけでも、内容の正しさは測れません。IDや数値などはコードで照合し、文章の判断は具体的なルーブリックを使います。LLMによる採点には順序や長さへの偏りがあり、人の判断と一致するかも確認します。

改善の検証手順:同じ質問・資料・権限で1つずつ比較する

  1. 基準の構成を固定する。原本・索引・埋め込み・検索条件・プロンプト・モデル・採点方式の版を記録する。
  2. 失敗を段階とカテゴリで分け、最も多いか影響の大きい原因を1つ選ぶ。
  3. 変更前後で同じ入力と権限を使い、検索の根拠再現率と回答品質を比較する。
  4. 全体平均だけでなく、エラーコード、複数資料、旧版、権限なしなどのカテゴリを見る。
  5. 生成や採点の揺れを複数回の実行で見て、改善が安定しているか確認する。
  6. 検索・再ランキング・生成の遅延と費用も測り、公開条件を満たす構成を選ぶ。

トップkを増やす、リランキングを足す、大きなモデルへ替える、といった変更は遅延や費用にも影響します。平均の正答率が上がっても、権限なしの漏えいや重要な手順の誤りが増えたなら公開を止める基準を決めます。本番で新たに見つかった失敗は、個人情報を除いて評価セットへ戻します。

よくある疑問:チャンクを大きく、top-kを多くすれば精度は上がる?

検索・評価・認可の設計を確認する一次資料

この記事で深掘りしたTips