RAGに「関係あるか」を見分ける小さな判定器を置く — 取得したものを、全部は渡さない
はじめに
自分用に、日々の記録を貯めて意味検索で引ける知識ベース(RAG)を運用している。検索精度そのものを数値で上げていった話は 測定駆動でRAGの検索精度を上げる に書いた。
ただ、検索がうまくなっても残る問題がある。ベクトル検索は「意味が近いもの」を取ってくるが、近いだけで質問には関係ないものも混じる。 これは別の記事(ベクトル検索に別カテゴリが紛れ込む罠)でも書いた、埋め込みの素直さの裏返しだ。
取ってきたものを全部そのままLLMに渡すと、無関係な記憶がノイズになって答えを濁す。この記事は、取得とLLMの間に「これは本当に関係あるか」を判定する小さな判定器を置いた話だ。
問題:取得=正解ではない
素朴なRAGは、検索で上位に来たものを全部LLMのプロンプトに詰め込む。品質のゲートが無い。
質問
│
▼
検索(意味が近いものを上位から取る)
│ ← 近いだけで「関係ない」ものも一緒に上がってくる
▼
取れたものを全部 LLM へ渡す ← 無関係な記憶が答えを濁す
「意味が近い」は「関係がある」とは限らない。似た言葉を含むだけの、質問とは無関係な記録が混じると、LLM はそれに引きずられる。
考え方:取得とLLMの間に判定器を置く(CRAG)
対策の骨子はシンプルだ。取得したあと、LLMに渡す前に、一つずつ「関係あるか」を判定する。 関係あるものだけ通し、無関係なものは落とす。取得後に品質を正す、という意味でこの型は CRAG(Corrective RAG)と呼ばれる。
質問
│
▼
検索(意味が近いものを取ってくる)
│
▼
┌───────────────────────────────┐
│ 判定器:この記憶は、この質問に関係あるか?(二値で判定) │
└───────────────────────────────┘
│
├─ 関係あり ─▶ LLM へ渡す
└─ 関係なし ─▶ 落とす(答えを汚さない)
なぜ「大きなLLM」ではなく「小さな判定器」か
判定そのものは、大きなLLMにもできる。だが、検索のたびに取得結果を一件ずつ大きなモデルに問い合わせると、遅いし重い。外部APIに投げるなら、そのたびに自分の記憶をクラウドへ送ることにもなる。
そこで、判定だけに特化した小さなモデルを用意した。しかも、汎用の判定ではなく、自分のRAGのドメインに合わせた訓練データで微調整する。判定器の仕事は「使う/使わない」の二値だけなので、小さなモデルでも務まる。
【大きなLLMに毎回判定させる】
検索結果 ─▶ 大きなモデル ─▶ 判定 … 遅い・重い・(外部なら)クラウド送信
【自分のドメインで微調整した小さな判定器】
検索結果 ─▶ 小さなモデル(手元)─▶ 使う/使わない … 速い・軽い・手元で完結
手元で完結する利点は速さだけではない。自分の記憶を一切外に出さずに判定できる(プライバシー)。個人の記録を扱うRAGでは、これが効いてくる。
作ったもの(実測)
ベースは小型の指示チューニング済みモデル(Qwen2.5-3B)。これを QLoRA(4bit 量子化+LoRA) で、二値の関連度判定に微調整した。訓練は手元のノート用GPU(RTX 2070 Max-Q)で、約 1 時間 53 分。最終 loss は約 1.45、二値判定の正解率はおよそ 76% だった。
76% は完璧ではない。だが、判定器の役目は「明らかに関係ないものを落とす」ことであって、完璧な選別ではない。第一段のふるいとしては十分に働く。実際、この判定器は今、検索が走るたびに動いて、関連度の低いチャンクを静かに落としている。
数字を大きく見せるより、正直に言う。小さく速く、手元で完結し、明らかなノイズを落とす ——それが狙いで、それは満たせている。
取得を、正解にしないために
取得は正解ではない。渡す前に判定器を置く。 検索で上がってきたものを、そのまま全部LLMに渡さない。「意味が近い」と「関係がある」は別物だ。間に一段、関連度を確かめる関門を挟む。
判定器は、大きなモデルに頼らず、小さく専用に作れる。 二値判定のような限定された仕事なら、自分のドメインの訓練データで小さなモデルを微調整すれば足りる。速く、軽く、手元で回る。
手元で完結させて、記憶を外に出さない。 個人の記録を扱うなら、判定のために中身をクラウドへ送らずに済む構成を選ぶ。
検索を速くするのはチューニングの半分だ。取ってきたものを、関係あるかどうかで一度ふるいにかける ——この判定器を持って初めて、RAGは「近いもの」でなく「役に立つもの」を返し始める。
関連する記事
- 検索精度そのものを数値で上げていった話は 測定駆動でRAGの検索精度を上げる に書いた。
- 「意味が近い=出してよい」ではない、という同じ根の落とし穴は ベクトル検索に別カテゴリが紛れ込む罠 にまとめた。
- そもそも、この意味検索を専用のベクトルDBを足さずに実装した話は 「字面」でなく「意味」で探す — 専用のベクトルDBを足さずに意味検索を実装する にある。
- この判定器の土台になった、手元GPUでの小型モデル微調整(QLoRA)そのものの記録は QLoRAでローカルにファインチューニングした話 にある。