RAG改良手法の学習

はじめに

前回、RAGのチャットボットを作成しました。
しかし性能がイマイチで文書を検索し、そのまま内容を表示することしかできませんでした。

これを改善していくにはどのようなアプローチが良いのでしょうか?
いくつか学習した内容をまとめて、有効そうなアプローチを検討していきます。

想定する使い方は、前回と同じく3DCGソフトウェアの実践的な使い方を教えて助けてくれるヘルパーボットを想定していきます。


1. 読書

RAGについて書かれている書物をいくつか読んで、情報を仕入れていきます。

1-1. RAG超入門

Amazon.co.jp: RAG(Retrieval-Augmented Generation)超入門: RAGの基本から実装方法まで: Python eBook : Joe: Kindleストア

単純なRAGの具体的な実装方法が記されていました。
しかしあまり実践的な改善手法は記されていませんでした。

RAGとファインチューニングの違いなど、RAGの基礎的な内容を学ぶには良いかもしれません。
またハンズオンとして実際に簡単なRAGを構築することができます。

1-2. AI・LLMの実務で使えるRAG精度改善

Amazon.co.jp: AI・LLMの実務で使える ― RAG精度改善 eBook : 咸 毅成: Kindleストア

こちらはとても実践的な内容が載っていました。
これまでの「質問→検索→生成→回答」の単純なRAGがNaive RAGであり、それに改善を施していったものをAdvanced RAG、Modular RAGとしてそれらに必要な技術を丁寧に解説しています。

また、改善手法の前に評価方法を記しているところも誠実で良いですね。
小手先の手法だけでなく、それによりどの性能が向上するのか解説しています。
「この性能が上がる代わりにこの精度が悪くなる」のような、事実に基づいて解説してくれています。

目次を以下に記します。

第1章 なぜRAGが必要なのか  
1.1 RAGとは  
1.2 RAGの分類と定義  
 - Naive RAG —— 最も基本的なRAG(主にPoCやデモ用途)  
 - Advanced RAG —— 精度を高める実務的アプローチ  
 - Modular RAG —— 一部品化の設計で精度を積み上げる発展形  
 - いま、この三分類をどう捉えるか  
1.3 RAGと幻覚(Hallucination)問題  
 - なぜLLMは幻覚を起こすのか? —— OpenAIの最新知見  
 - 幻覚によるリスクとRAGの役割  
 - 幻覚はなくならない、だからこそRAG  
1.4 なぜRAGが必要なのか、そしてなぜ高精度RAGが求められるのか  
 - RAGが必要とされる理由  
 - なぜ「高精度RAG」が求められるのか  
第2章 RAG評価とベンチマーク設計  
2.1 「良いRAG」とは何か  
2.2 LLMを評価者とする手法(LLM-as-a-Judge)  
2.3 評価指標について  
 - Retrieval 評価指標  
 - Generation 評価指標  
 - コラム:ルールベースとLLMベースの精度評価  
2.4 評価用データセットの構築  
 - Ragasによる合成データ生成  
 - LangSmithによるモニタリング  
2.5 公開ベンチマークの活用  
第3章 RAG精度改善の実践  
3.1 前処理(Data Parsing & Indexing)  
 - Data Parsing(データの正規化と構造化)  
 - OCR  
 - 構造化出力  
 - コラム:表における「文脈喪失」問題  
 - Indexing(チャンクとベクトル化)  
 - チャンク分割  
 - コラム:Semantic Chunking(意味単位での分割)  
 - ベクトル化  
3.2 検索(Retrieval)  
 - Hybrid Search(ハイブリッド検索)  
 - Rerank(再ランキング)  
 - LLM Rerank(LLMを使った再ランキング)  
 - Query Rewrite(クエリを書き換え)  
 - ChunkRAG(文脈単位のフェイルオーバー)  
 - GraphRAG(ナレッジグラフを活用した検索精度改善)  
 - GraphRAGの発展 —— RAPL  
 - Parent Page Retrieval(親ページ取得)  
 - Contextual Retrieval(文脈をチャンクに追加)  
3.3 生成(Generation)  
 - Self-RAG(検索の要否を“自分で”判断する)  
 - Agentic RAG(AgentとRAGの組み合わせ)  
 - RAG-Reasoning(RAGと推論の相互作用)  
 - コラム1:DeepSearchとDeepResearchについて  
 - コラム2:DeepSearchの精度改善手法 —— URL Ranking  
第4章 まとめ  
4.1 本書のまとめ

チャンク分割

チャンクサイズ、文書の分割サイズについてはよく分からないまま設定していました。
しかし、チャンクサイズは大きくても小さくても問題があり、調整が難しいようです。

  • 大きすぎる場合
    無駄な情報やノイズが多く混入し、検索結果がぼやける
    リコールが下がり、回答の的確さが落ちる
  • 小さすぎる場合
    十分な文脈が含まれず、回答が断片的になる
    検索対象のチャンク数が増えて計算コストが膨らみ、待ち時間も長くなる

ただ、最近はLLMの性能向上により多少余計な情報が混ざっても正しく選択できるようになってきているようで、なので小さいよりは大きめがいいのでしょうか?

実務的なテクニックに、小さめのチャンクで検索→位置情報を利用して上下1チャンクも追加で返すという手法もあるようです。
検索精度は小チャンクの粒度で確保しつつ、回答生成時には上下の文脈も補えるため、精度と文脈保持の両立が可能。

本当に大きくても小さくても長所短所があるんですね。
他にも意味単位での分割やメタデータとしてその文書の要約を添えるなど様々な手法があるようです。

ベクトルDB

ベクトルDBについて、前回は特に種類を知らないままFAISSを使用しましたが以下のような種類があるようです。

  • Chroma
    軽量で構築が非常に簡単、チュートリアルや学習用コードでよく使われる
    小規模プロジェクトやPoCに向いている
  • Qdrant
    性能とスピードのバランスがよく、人気が高い
    OSSでコミュニティが活発、実務で最も広く使われている部類
  • Faiss
    Metaが開発した大規模データ向けのライブラリ
    検索スピードが非常に早く、研究用途やプロダクションで定番
  • LanceDB
    マルチモーダル(画像+テキストなど)に強みがある
    画像や表データを扱うユースケースに適している

クエリ書き換え

ユーザーが入力した質問をそのまま検索に使うのではなく、LLMによって検索に適した形に改変するアプローチ。

通常、ユーザークエリは質問文であることが多いが、検索の対象となる文書は回答文や説明文であることがほとんど
クエリ:第二次世界大戦が始まった年は?
ドキュメント:第二次世界大戦は1939年に勃発した
この場合、質問文x回答文で類似度を測るよりも、回答文x回答文で比較したほうが適切な文書を拾いやすいのではないか?

という説明には納得させられました。

GraphRAG

文書群から知識グラフ(Knowledge Graph)を生成し、そのグラフを使って検索を行う仕組み。

  • ノード:文中に現れるエンティティ(人名、組織、場所、出来事など)
  • リレーション:それらの間の関係性(雇用関係、因果関係、所属、対立など)

高精度で、速度よりも正確さが何より重要というケース、たとえば法務やリスク分析のような領域に向いている。
ベクトル検索のような単なる類似度ではなく、構造化された関係性を活かすのが最大の特徴。

実際のケースとしてMicrosoft ReseachのGraphRAGに関する論文では、ウクライナ関連のニュース記事を対象にした検証が紹介

  • ベースラインRAGでは「Novorossiya」という組織の活動内容を答えられなかった
  • GraphRAGでは「PrivatBankを含む施設破壊計画に関与していた」といった具体的な活動内容まで導けた
    単なるテキスト一致ではなく、「Novorossiya→破壊計画→PrivatBank」というリレーションを辿ることで答えに到達できた
    さらに根拠文も同時に提示されるので、回答の透明性も高まる

Agentic RAG

Agentを使って適切な検索方法を判断させる。
ユーザーのクエリを解釈し、どの知識源・どのクエリ形式が最適かをエージェントが決める。
例:

  • 「XXとは何でしょうか」→概念定義なのでVectorDB(類似概念)
  • 「ユーザー数トップ3を教えて」→集計クエリなのでRDBMS(SQL)
  • 「XとYの関係を教えて」→GraphDB(ノード/リレーション探索)
  • 「X社の最新の売り上げを教えて」→WebSearch(最新性が重要)

また、検索結果の妥当性を評価して不足していたら再度妥当なプロンプトで再検索をかける。

LLMの利用

クエリ書き換えやAgentic RAGのように、様々な改善でLLMを使うと性能が良くなる側面がある。

検索結果に対しても、関連性・網羅性・信頼度をスコア付けしランキング化したりフィルタリングしたりなど。


2. 改善考察

これらを踏まえて、前回の3DCGソフトウェアの実践的なヘルパーボットの改善策を考えていきましょう。

DBの分割

botに必要とされる知識は1種類ではなく複数に分割できます。

  • ツールの使い方、パラメータの意味、ヘルプ
  • ツールの実践的な使い方、使用例

このことからベクトルDBを複数に分割し、それぞれに適した情報を入れると良いです。
またツールのヘルプはバージョンによって仕様が変わっていくので、情報を更新しやすいように分離する意味もあります。

Agentの導入

検索するDBを判断するのはAgentを用いると良いでしょう。
質問→実際の使用例を検索していくつかの案を出した後、ツールの使い方を検索してその機能がまだ残っているかを確認する。

このためには複数回検索や推論を行う必要があります。
自律的に「この情報で足りているか」を判断できる優秀なLLMを使うと良いです。

Agentを導入することで必然的にクエリの書き換えも行ってもらえます。
先ほどの例で示したような仮想回答を用いた検索技法は実装しないと再現できませんが、人が書く曖昧な言葉や余計な修辞を取り除いて検索してくれるでしょう。

検索方法

ツールの実践的な使い方をGraphRAGで検索するのは良いかもしれません。
特定の表現をしたいときに、ただのベクトル検索だと書かれていることしか検索できませんが、それと関連付けられたツールなどが検索できると便利そうです。

その点、ヘルプの検索はもっと単純なもので良いでしょう。
ベクトル検索でも良さそうですし、親文書を含めておくことで総合的なツールのヘルプが参照できます。

また根本的にベクトル検索ではなく、JSONでリスト検索という手段もあります。
検索したいツール名が具体的に分かっているならその文書を参照すればいいですね。
わざわざチャンク分けし、精度が曖昧なベクトル検索をするよりよっぽど良さそうです。


3. 既存のAgentを使う

こんな理想の動作をしてくれるAgentを組むには大変そうに思えます。
実は既存のAgentを拡張することで簡単に動作確認を行うことができます。

つまりRAG検索のMCPを作ることでAgentが自律的にツールの使い方を考え、再検索をかけたりしてくれます。

MCPを使う利点は他にもあります。
Claude CodeやAntigravityなどで使用することで、各社が代表する賢いLLMをメインの思考として取り入れられます。
またMCPは他のツールと組み合わせられるため、検索結果を用いて実際にソフトを動作させるなど拡張に富んでいます。

実際、RAG MCPというのは開発されています。
ローカルRAGを手軽に構築できるMCPサーバを作りました

同じように3DCGソフトウェアの操作を聞いたり頼んでみたのですが、単純なRAGより格段に性能が上がっていました。

Q: 水を透明感ある感じにレンダリングする方法を考えて、どんなノードを使えばいいか考えた後、その各ノードの使い方などを検索して入力やパラメータを確認して

既存RAGでは「文書を検索できませんでした」となる質問ですが、RAG MCPは回答の真偽はともかくそれなりの回答を作成してくれます。

RAG MCPの回答

Houdiniで透明感のある水をレンダリングする方法

Houdiniで透明感のある水をレンダリングするには、以下のノードと設定を使用します。

1. Houdini Procedural: Ocean LOP

このノードは、レンダー時に低解像度の入力ジオメトリから高解像度の海洋を生成します。ディスク容量を節約し、テクスチャのベイク処理を回避できます。

  • ヘルプ:
    • Houdini Procedural: Ocean LOPノードは、Solaris環境で海洋をレンダリングするためのプロシージャルプリミティブを構成します。このノードは、低解像度の入力ジオメトリを受け取り、指定された解像度でジオメトリをダイシングおよびディスプレイスメントすることにより、レンダー時に高解像度のジオメトリを生成します。
  • 使い方:
    1. Solaris環境でHoudini Procedural: Ocean LOPノードを作成します。
    2. 低解像度の入力ジオメトリをノードに接続します。
    3. スペクトルタイプ、Volume Density、Scattering Phaseなどのパラメータを調整して、海洋の形状と外観を制御します。
  • 入力: 低解像度のジオメトリ
  • 重要なパラメータ:
    • スペクトルタイプ: 海洋のスペクトルタイプを選択します。TessendorfまたはEncinoを選択できます。
      • Tessendorf: より伝統的なスペクトルタイプで、風速と風向に基づいて海洋の形状を生成します。
      • Encino: より高度なスペクトルタイプで、よりリアルな海洋の形状を生成できます。
    • Volume Density: 海洋内部の密度を調整します。値を大きくすると、海洋がより濃く見え、小さくするとより透明に見えます。
    • Scattering Phase: 海洋内部の散乱を調整します。値を調整することで、光が海洋内部でどのように散乱するかを制御できます。
    • Choppiness: 海面の波の細かさを調整します。
    • Foam Amount: 海面の泡の量を調整します。
    • Cusp Scale: 波の先端の尖り具合を調整します。

2. Principled Shader

このシェーダーは、物理ベースのレンダリングを行うためのものです。透明度、反射、屈折などを調整できます。

  • ヘルプ:
    • Principled Shaderは、物理的に正確なシェーディングモデルを実装する多用途シェーダーです。このシェーダーを使用すると、さまざまなマテリアルをリアルにレンダリングできます。
  • 使い方:
    1. Materialノードを作成し、Principled Shaderを割り当てます。
    2. Base Color、Opacity、IOR、Roughnessなどのパラメータを調整して、マテリアルの外観を制御します。
    3. 必要に応じて、Subsurface WeightとSubsurface Radiusを調整して、サブサーフェススキャッタリング効果を追加します。
  • 重要なパラメータ:
    • 透明度 (Opacity): 水の透明度を調整します。値を小さくすると、より透明になります。0に設定すると完全に透明になります。
    • 反射率 (Base Color): 水の反射色を調整します。通常は薄い青色または水色を使用します。
    • 屈折率 (IOR): 水の屈折率を調整します。水の屈折率は通常1.33です。
    • 粗さ (Roughness): 水面の粗さを調整します。値を小さくすると、より滑らかな水面になり、反射がより鮮明になります。値を大きくすると、水面がより粗くなり、反射がぼやけます。
    • Subsurface Weight: 水のサブサーフェススキャッタリングの量を調整します。値を大きくすると、水がより柔らかく見えます。
    • Subsurface Radius: サブサーフェススキャッタリングの半径を調整します。値を大きくすると、光がより深く浸透します。

設定例

  1. Houdini Procedural: Ocean LOPノードを作成し、低解像度のジオメトリを入力します。例えば、Planeノードを使用できます。
  2. Materialノードを作成し、Principled Shaderを割り当てます。
  3. Principled Shaderのパラメータを調整して、透明度、反射率、屈折率、粗さを設定します。以下は設定例です。
    • 透明度: 0.9
    • 反射率: (0.1, 0.2, 0.3)
    • 屈折率: 1.33
    • 粗さ: 0.05
    • Subsurface Weight: 0.2
    • Subsurface Radius: (0.1, 0.1, 0.1)
  4. Material Stylesheetノードを使用して、MaterialノードをHoudini Procedural: Ocean LOPノードの出力に割り当てます。
  5. レンダリング設定を調整して、最適な結果を得ます。
    • Render Settings LOP: このノードを使用して、レンダリング設定を調整します。
      • Samples: サンプル数を増やして、画質を向上させます。
      • Pixel Variance: ピクセルバリアンスを調整して、ノイズを減らします。
      • Motion Blur: モーションブラーを有効にして、動きのある水の表現を向上させます。
      • Depth of Field: 被写界深度を調整して、焦点の合った部分とぼやけた部分を作成します。

その他のヒント

  • 環境光: 環境光を調整して、水の全体的な色と明るさを制御します。
  • ライト: ライトの位置と色を調整して、水の反射と屈折を強調します。
  • コンポジット: コンポジットを使用して、レンダリング結果をさらに調整します。例えば、色補正、ブルーム効果、およびその他のエフェクトを追加できます。

これらの設定を調整することで、透明感のある美しい水のレンダリングを実現できます。

同じベクトル検索をしているだけなのにAgentでここまで性能が変わるんですね。


おわりに

RAGの改善手法について学び、具体的な改善案を検討しました。

投稿者プロフィール

MuramatsuYuki

関連記事

  1. 【Gemini CLI】Windowsアプリ開発における共通ルールの検…

  2. 【WPF|Gemini CLI】読書日記アプリの開発

最近の記事

制作実績一覧

  1. Checkeys