RAG (検索拡張生成) のさまざまな手法 (パターン)

ここでは、ChatGPT などの大規模言語モデル (LLM) を使った構築で欠かせない RAG (検索拡張生成) で使える、さまざまな応用的手法 (パターン) を紹介します。

1. RAG の流れ (基本)

まず、以前「プロンプト エンジニアリングの例と解説」でも紹介しましたが、ご存じない方のために、オーソドックスな RAG のアーキテクチャを復習しておきます。

ChatGPT などの言語モデルを使って質問・応答 (Question-Answering) をおこなう際、例えば「明治維新について教えて」など、一般的事実は問題なく回答できますが、ビジネスにおいては、企業内のドキュメントや FAQ など、言語モデルが知らない情報についても応答させたい場合があります。
このような場合、下記例のようにコンテキスト (context) として元となる情報を与えることで、言語モデルが知らない情報も回答させることが可能です。

(以降、ハイライト部分は、言語モデルが返したレスポンスをあらわしています。)

以下のコンテキストを使って下記の質問に答えてください。
もし答えがない場合には、「私は知らない」と答えてください。

コンテキスト: """Surface Book が空の状態から完全に充電されるまで、2 ~ 4 時間かかります。
Surface Book を充電しながらゲームやビデオ ストリーミングのような電力消費の多い活動に Surface を使用している場合、
さらに時間がかかる可能性があります。
電源アダプターに付いている USB ポートを使って、Surface Book の充電中にスマートフォンなどの他のデバイスを充電することもできます。
電源アダプターの USB ポートは充電専用であり、データ転送用ではありません。"""

質問: Surface Book の充電時間を節約するにはどうするか。

Surface Book を充電しながら電力消費の多い活動を行わないことで、充電時間を節約することができます。

この方法を使って、以下のような手順で質問・応答をおこなうアーキテクチャを RAG (Retrieval Augmented Generation, 検索拡張生成) と言います。

  1. 対象となるドキュメント (FAQ、企業内文書など) をデータベースに保存。
  2. ユーザーが質問をした際に、データベースから質問に近いドキュメントを検索。
  3. 検索されたドキュメントを上述の「コンテキスト」(context) として使用してプロンプトを作成し、言語モデル (ChatGPT など) を呼び出す。
    そして、言語モデルが返した答えをユーザーに返す。

特に上記 2 のデータベースからの検索では、通常のキーワード検索以外にベクトル検索も使用されます。
OpenAI などが提供する言語モデルでは、文書を高次元のベクトルに変換する Embedding と呼ばれる処理が可能で、この Embedding 用のモデルを使ってベクトル化をおこなうと、意味的に近い文書はベクトルとしても近くなります。このモデルを使って、対象となるドキュメントすべてをベクトルとしてデータベースに保存しておき、検索時は、ユーザーが与えた質問をベクトルに変換して、このベクトル (質問のベクトル) と近いベクトルを持つ文書をデータベースから検索します。(この際、ベクトルの 1:1 マッチングによる検索は遅くなるため、一般に、クラスタリング、ツリー、HNSW アルゴリズムなどによる近似最近傍探索 (ANN) の最適化アルゴリズムが使われます。)
このベクトル検索を使った RAG のアーキテクチャを下記に図示します。

単純なベクトル検索やキーワード検索だけでなく、検索システムによっては、キーワードベースの旧来手法である TF-IDF やランキングアルゴリズムの BM25、あるいは、よりモダンなセマンティック検索を実装している場合があります。
例えば、Cohere の Reranking や Azure AI Search のハイブリッド検索では、キーワード検索とセマンティック検索、キーワード検索とベクトル検索、あるいは、キーワード検索とベクトル検索とセマンティック検索など、複数の検索要素に基づく re-ranker を提供することで、より精度の高い検索が可能です。(2-stage RAG)
また LangChain の Ensemble Retriever や LlamaIndex の Node Postprocessor では、こうした組み合わせを構成できます。(LLM による re-rank なども可能です。)
こうした検索エンジンそのものの機能は、下記のどの手法 (パターン) とも組み合わせることができます。

2. Advanced RAG

上記が一般的な RAG の流れですが、現在、これを改良したさまざまな先進的手法が紹介されています。(LangChain では、こうした手法を体系化して Advanced RAG と呼んでいます。)
以下に、代表的なもの (よく使われるもの) をいくつかピックアップして紹介します。

Summary Embeddings

ベクトルまたはインデクスとしてデータベース (または検索システム) に登録する内容を最適化する Multi representation indexing と呼ばれる手法の 1 つです。
Summary Embedding では、ドキュメント全体のインデクスやベクトルを使用する代わりに、各ドキュメントの Summary (要約) を作成して、これをベクトル化 (Embedding) してデータベースに保存します。
ユーザーからの質問に基づく検索では、この登録されたベクトルを使って近い文書を検索しますが、コンテキストとして取り出すのは (要約文書ではなく) 元のドキュメントです。

そのドキュメントが意図する内容を表したベクトル表現 (またはインデクス表現) に近くなるため、各ドキュメントが意図を持って分割されているようなケース (例えば、条文ごとに分割された法律文書など) では良いパフォーマンスが期待できます。

Summary から作成したインデクス (ベクトルなど) とチャンクから作成したインデクス (ベクトル) の双方を使って、最初は Summary のインデクスでフィルタリングし、そのグループ内をチャンクのインデクスを使って検索する 2 ステップの検索をおこなうケースもあります。
また、Multi-Vector Retriever (=文書、画像、テーブルなど Multi-modal コンテンツの抽出) と組み合わせて使用するケースもあります。

Chunk と Parent Retriever

一般に、言語モデルでは、受け付けられるテキストのサイズが決まっています。(例えば、OpenAI の text-embedding-ada-002 では最大 8191 トークン、BERT ベースの Encoder では最大 512 トークン、など)
登録するドキュメントが大きい場合、トークンの節約と、ピンポイントな検索 (=知りたい箇所に絞った検索) の双方のメリットから、文書をチャンク (Chunk) に分割して登録する手法は、以前「プロンプト エンジニアリングの例と解説」でも紹介しました。

一般に、検索時には、検索したい意図にそった情報が含まれているかどうかがポイントなので、Chunk のまま検索することで該当箇所をピンポイントに特定できますが、質問・応答の際には前後の文脈も考慮する必要があります。
そこで、ユーザーが質問した際に、登録された各 Chunk のベクトル (またはインデクス) を対象に検索し、言語モデルに渡す質問・応答のコンテキストとしては、断片化した Chunk ではなく、親のドキュメント全体を使用することで精度向上を狙うのがこの方法です。(この親のドキュメントを決定する際には、例えば、「検索結果の上位 n 個のうち、m 個以上の検索結果で同一の親を持つ場合、この親をコンテキストとして使う」など選択基準を設けます。)

こうした方法 (Parent Retriever) 以外に、長い文書を「文」ごとに Embedding して検索し、検索された 1 つの文に対して前後 k 個の文 (合計で最大 2k + 1 個の文) までをコンテキストとして使用する Window Retriever の方式を使うケースもあります。

Hypothetical Document Embeddings (HyDE)

「質問」を検索に適した形に変換するクエリー変換 (Query Transformation) と呼ばれる手法の 1 つです。
質問 (Question) の Embedding をおこなうのではなく、代わりに、質問をいったん言語モデル (LLM) に (コンテキストを付与せずに) 尋ねて、そこで得られた答え (Answer) を使って、その答えを Embedding して近いドキュメントを検索する方法が HyDE (Hypothetical Document Embeddings) です。
(以降は、いつものように、検索されたドキュメントを使ってコンテキストを含む質問・応答をおこないます。)

このコンテキストを使わない最初の質問応答では、誤った (でたらめな) 答えが返る可能性がありますが、それでも生成されたテキストは本来必要とする答えと似たパターンを持つであろうと想定されるため、より近いドキュメントが検索できることが期待できます。つまり、「質問」で「答え」の文書を検索するのではなく、「疑似的な答え」で「本来の答え」の文書を検索することで、類似ドキュメント検索の精度向上を期待する手法です。

Query Expansion

上述のオーソドックスな RAG の流れでは、質問 (Query) のちょっとした書き方の違いが検索結果を左右します。
Query Expansion は、ユーザーが与えた質問の別のバージョンを (いくつか) 作成することで、この揺らぎをできるだけ少なくする手法です。(これも、クエリー変換 (Query Transformation) の手法の 1 つです。)

例えば、「タスク分解の手法にはどのようなものがありますか?」という質問に対して、言語モデル (LLM) を使って下記のように 5 つの異なるバージョンを作成します。

あなたは AI 言語モデルのアシスタントです。
あなたのタスクは、ベクトルデータベースから同等のドキュメントを検索する目的で、与えられたユーザーの質問に対して、5 つの異なるバージョンの質問を作成することです。
それでは、下記の代替となる質問を改行で区切って提供してください。

質問 : タスク分解の手法にはどのようなものがありますか?

1. タスク分解に使用される一般的な手法は何ですか?
2. タスク分解のために使用される一般的なアプローチは何ですか?
3. タスク分解において一般的に使用される手法は何ですか?
4. どのような手法がタスク分解に使用されるのですか?
5. タスク分解に使用される主要な手法は何ですか?

作成された個々の表現を元にベクトル データベースから近いドキュメントをそれぞれ検索して、単一の union を作成し、それをコンテキストとして使用します。

Rewrite-Retrieve-Read

同じくクエリー変換 (Query Transformation) 手法の 1 つで、同様にユーザーの質問をそのまま使うのではなく、質問からいったんクエリーに適した形に変換して検索します。
この手法では、下記のように言語モデルを使って最適なクエリーテキストを生成します。

元となるユーザーの質問

Nicholas Ray と Elia Kazan に共通の専門分野は何ですか?

言語モデルに渡すプロンプトとレスポンス

与えられた質問に答えるために、Web 検索エンジンに渡す検索クエリーを作成してください。クエリーは「**」で終了するようにしてください。
質問 : Nicholas Ray と Elia Kazan に共通の専門分野は何ですか?
答え : Nicholas Ray Elia Kazan 共通 専門分野**

例文の出典 : 論文「Query Rewriting for Retrieval-Augmented Large Language Models」から日本語化

この作成されたクエリー (今回の場合、「Nicholas Ray Elia Kazan 共通 専門分野」) を Web 検索などに提供し、検索された結果 (ドキュメント) をコンテキストに使用します。

Hypothetical Questions

Hypothetical Questions は、上記 (HyDE) とは逆に、ドキュメント登録の際に、各ドキュメントから類推される想定質問 (複数) を (言語モデルなどを使って) 作成し、これをベクトル化 (Embedding) してデータベースに保存します。
ユーザーからの質問に基づく検索では、この登録されたベクトルを使って近い文書を検索しますが、もちろん、コンテキストとして取り出すのは (「想定質問」のほうではなく) 元のドキュメントです。
HyDE 同様、「質問」で「答え」の文書を検索するのではなく、「ユーザーの質問」で「想定質問」の文書を検索することで、類似検索の精度向上を期待する手法です。

これも、上述の Multi representation indexing の手法の 1 つです。

Knowledge Graph

エンティティとリレーションの関係を表現したものを Knowledge Graph と呼びます。

質問・応答では、こうしたエンティティとリレーションの関係をたどることで、より正確で詳細な答えに到達できる場合があります。

例えば、映画に関する専門的な情報を構成して質問・応答に対処する場合、項目ごとに Wikipedia のような巨大なテキスト データベースで管理するのではなく、各エンティティ (俳優、監督、映画 等) を下図のようなグラフに体系化してまとめることで、ある映画俳優や映画などについて質問した場合に、その俳優のプロパティ (生年月日, 出生地, 性格など) だけでなく、その俳優が出演している作品 (映画、番組) や、その作品のプロパティ、その作品の続編、あるいは、その俳優と共演した出演者の情報などもたどって、安定的、かつ体系的に質問に答えられるかもしれません。(不足している関係性が見つかった場合も、関係するドキュメントすべてを修正するのではなく、グラフ上の関係性の 1 つを修正するだけで済みます。)

この Knowledge Graph による質問・応答については、投稿「Knowledge Graph による質問応答のアーキテクチャ解説」で詳細を解説しましたので参照してください。(投稿をわけました。)

ReAct (Reasoning+Acting)

プロンプト エンジニアリングの例と解説」で紹介した Reasoning (論理解釈によるタスク分解) を使ったより高度な方法です。

現在 ReAct は Autonomous Agent など様々なシーンで使われますが、もともとの ReAct の論文では検索を扱った例を紹介しており、その実際の動きは こちら で詳しく解説されています。
ここでは、同様のケースを日本語の例で解説してみましょう。

まず、この例では、RAG において、Wikipedia のデータベースがデータストア (Knowledge Base) として参照できると仮定します。
ReAct を使うことで、Wikipedia だけを参照して、以下の質問に答えたいと思います。

手塚治虫の代表作「ブラック・ジャック」の連載開始と同じ年にテレビアニメ化されたある漫画を書いた人物で、同じトキワ荘の住人だった有名な漫画家は誰か ?

こうした質問・応答は Multi-Hop QA と呼ばれ、Wikipedia の単一の記事を見ても答えが得られませんが、複数の記事を横断的に見ることで答えが得られるような意地悪な質問となっています。

研究者向けに、こうした Multi-Hop QA を集めた HotpotQA という英語の Dataset が提供されています。

ReAct では、これを手順に沿って考察させるため、以下のようなプロンプトを渡します。

あなたは、以下のツールが利用可能です。

- Wikipedia検索: このツールは Wikipedia の記事を返します。引数は、取得したい Wikipedia の項目名です。

ツールを利用するには、以下のフォーマットを使います。

```
考察 : どのような考えでそのツールを使うのか記述
行動 : 使用するツールの名前。今回は Wikipedia検索 のツールのみ使用可能です。
入力 : ツールに渡す引数
結果 : この行動の結果
```

与えられたタスクを解くために、このフォーマットでツールを 1 つずつ使用します。
そして、最終的にユーザーに結果を応答する場合は、以下のフォーマットを使います。

```
考察 : 答えがわかりました
答え : 最終的なタスクの結果
```

では、はじめましょう。
以下のタスクを求める手順を 1 つずつ答えてください。

タスク : 手塚治虫の代表作「ブラック・ジャック」の連載開始と同じ年にテレビアニメ化されたある漫画を書いた人物で、同じトキワ荘の住人だった有名な漫画家は誰か ?

ご存じの通り、Wikipedia の記事は非常に大きく、すべてを取り込むのは非効率なので、論文の中では、Wikipedia の最初の数行分の内容を返す search のツールと、記事の中で特定の文字列を探してその文の内容を返す lookup のツールの、2 つのツールを使用しています。ここでは、話を複雑にしないよう、search 用のツール (Wikipedia検索) のみを定義しています。
また、プロンプトの内容も多少省略して書いていますので (例えば、答えが見つからなかったときの動きなど)、実際の使用に際しては入念にチューニングしてください。

言語モデルは、このタスクを処理するために、以下の通り返してくるでしょう。

あなたは、以下のツールが利用可能です。

- Wikipedia検索: このツールは Wikipedia の記事を返します。引数は、取得したい Wikipedia の項目名です。

ツールを利用するには、以下のフォーマットを使います。

```
考察 : どのような考えでそのツールを使うのか記述
行動 : 使用するツールの名前。今回は Wikipedia検索 のツールのみ使用可能です。
入力 : ツールに渡す引数
結果 : この行動の結果
```

与えられたタスクを解くために、このフォーマットでツールを 1 つずつ使用します。
そして、最終的にユーザーに結果を応答する場合は、以下のフォーマットを使います。

```
考察 : 答えがわかりました
答え : 最終的なタスクの結果
```

では、はじめましょう。
以下のタスクを求める手順を 1 つずつ答えてください。

タスク : 手塚治虫の代表作「ブラック・ジャック」の連載開始と同じ年にテレビアニメ化されたある漫画を書いた人物で、同じトキワ荘の住人だった有名な漫画家は誰か ?

考察 : まずは、手塚治虫について調べる必要があります。
行動 : Wikipedia検索
入力 : 手塚治虫
結果 : ...

...

考察 : 答えがわかりました
答え : 石ノ森章太郎

上記で ... の箇所は省略して書いていますが、実際には何らかの文書が返ってきます。
この文書は、実際に Wikipedia 検索で得た答えではなく、言語モデルが勝手な想定で返している答えです。実際、最終的な答えである「石ノ森章太郎」は、誤った回答となっています。

そこで、アプリケーション側では、最初のステップである「まずは、手塚治虫について調べる必要があります。」を処理するため、実際に「手塚治虫」の Wikipedia の項目を検索して、その本当の結果を取得します。

つぎに、言語モデルに対して、その本当の結果を埋めた下記のようなプロンプトを渡します。
ここでも同様に ... を使って省略して書いていますが、下記の通り、Wikipedia 検索の結果には、質問の回答を解く鍵である「ブラック・ジャック」の連載開始の年が記載されているのがわかります。

あなたは、以下のツールが利用可能です。

- Wikipedia検索: このツールは Wikipedia の記事を返します。引数は、取得したい Wikipedia の項目名です。

ツールを利用するには、以下のフォーマットを使います。

```
考察 : どのような考えでそのツールを使うのか記述
行動 : 使用するツールの名前。今回は Wikipedia検索 のツールのみ使用可能です。
入力 : ツールに渡す引数
結果 : この行動の結果
```

与えられたタスクを解くために、このフォーマットでツールを 1 つずつ使用します。
そして、最終的にユーザーに結果を応答する場合は、以下のフォーマットを使います。

```
考察 : 答えがわかりました
答え : 最終的なタスクの結果
```

では、はじめましょう。
以下のタスクを求める手順を 1 つずつ答えてください。

タスク : 手塚治虫の代表作「ブラック・ジャック」の連載開始と同じ年にテレビアニメ化されたある漫画を書いた人物で、同じトキワ荘の住人だった有名な漫画家は誰か ?

考察 : まずは、手塚治虫について調べる必要があります。
行動 : Wikipedia検索
入力 : 手塚治虫
結果 : ... 1973年に『週刊少年チャンピオン』(秋田書店)で連載開始された『ブラック・ジャック』も、もともとは少年誌・幼年誌で人気が低迷していた手塚の最期を看取ってやろうという、 ...

言語モデルは、次に、下記のような応答を返してきます。

あなたは、以下のツールが利用可能です。

- Wikipedia検索: このツールは Wikipedia の記事を返します。引数は、取得したい Wikipedia の項目名です。

ツールを利用するには、以下のフォーマットを使います。

```
考察 : どのような考えでそのツールを使うのか記述
行動 : 使用するツールの名前。今回は Wikipedia検索 のツールのみ使用可能です。
入力 : ツールに渡す引数
結果 : この行動の結果
```

与えられたタスクを解くために、このフォーマットでツールを 1 つずつ使用します。
そして、最終的にユーザーに結果を応答する場合は、以下のフォーマットを使います。

```
考察 : 答えがわかりました
答え : 最終的なタスクの結果
```

では、はじめましょう。
以下のタスクを求める手順を 1 つずつ答えてください。

タスク : 手塚治虫の代表作「ブラック・ジャック」の連載開始と同じ年にテレビアニメ化されたある漫画を書いた人物で、同じトキワ荘の住人だった有名な漫画家は誰か ?

考察 : まずは、手塚治虫について調べる必要があります。
行動 : Wikipedia検索
入力 : 手塚治虫
結果 : ... 1973年に『週刊少年チャンピオン』(秋田書店)で連載開始された『ブラック・ジャック』も、もともとは少年誌・幼年誌で人気が低迷していた手塚の最期を看取ってやろうという、 ...

考察 : つぎに、トキワ荘について調べる必要があります。
行動 : Wikipedia検索
入力 : トキワ荘
結果 : ...

...

考察 : 答えがわかりました
答え : 石ノ森章太郎

ここでも同様に、言語モデルは勝手な推測で結果を記載していますが (相変わらず、誤った答えを返しています)、つぎに「トキワ荘」を調べるべきであるという提案をしています。
さきほどと同様に、この行動提案にしたがって、アプリケーション側で「トキワ荘」の Wikipedia 検索を実際におこない、その本当の結果を取得して、再度、下記の通りプロンプトとして渡します。

あなたは、以下のツールが利用可能です。

- Wikipedia検索: このツールは Wikipedia の記事を返します。引数は、取得したい Wikipedia の項目名です。

ツールを利用するには、以下のフォーマットを使います。

```
考察 : どのような考えでそのツールを使うのか記述
行動 : 使用するツールの名前。今回は Wikipedia検索 のツールのみ使用可能です。
入力 : ツールに渡す引数
結果 : この行動の結果
```

与えられたタスクを解くために、このフォーマットでツールを 1 つずつ使用します。
そして、最終的にユーザーに結果を応答する場合は、以下のフォーマットを使います。

```
考察 : 答えがわかりました
答え : 最終的なタスクの結果
```

では、はじめましょう。
以下のタスクを求める手順を 1 つずつ答えてください。

タスク : 手塚治虫の代表作「ブラック・ジャック」の連載開始と同じ年にテレビアニメ化されたある漫画を書いた人物で、同じトキワ荘の住人だった有名な漫画家は誰か ?

考察 : まずは、手塚治虫について調べる必要があります。
行動 : Wikipedia検索
入力 : 手塚治虫
結果 : ... 1973年に『週刊少年チャンピオン』(秋田書店)で連載開始された『ブラック・ジャック』も、もともとは少年誌・幼年誌で人気が低迷していた手塚の最期を看取ってやろうという、 ...

考察 : つぎに、トキワ荘について調べる必要があります。
行動 : Wikipedia検索
入力 : トキワ荘
結果 : ... 手塚治虫、藤子不二雄、石ノ森章太郎、赤塚不二夫ら著名な漫画家が居住していたことで知られ、漫画の「聖地」となったことから、 ...

このプロンプトに対して、言語モデルは、今度は下記のような応答を返してきます。なぜなら、トキワ荘に住んでいた有名な漫画家が、手塚治虫、藤子不二雄、石ノ森章太郎、赤塚不二夫であり、順番に、藤子不二雄、石ノ森章太郎、赤塚不二夫と調べていけば良いことがわかるからです。

あなたは、以下のツールが利用可能です。

- Wikipedia検索: このツールは Wikipedia の記事を返します。引数は、取得したい Wikipedia の項目名です。

ツールを利用するには、以下のフォーマットを使います。

```
考察 : どのような考えでそのツールを使うのか記述
行動 : 使用するツールの名前。今回は Wikipedia検索 のツールのみ使用可能です。
入力 : ツールに渡す引数
結果 : この行動の結果
```

与えられたタスクを解くために、このフォーマットでツールを 1 つずつ使用します。
そして、最終的にユーザーに結果を応答する場合は、以下のフォーマットを使います。

```
考察 : 答えがわかりました
答え : 最終的なタスクの結果
```

では、はじめましょう。
以下のタスクを求める手順を 1 つずつ答えてください。

タスク : 手塚治虫の代表作「ブラック・ジャック」の連載開始と同じ年にテレビアニメ化されたある漫画を書いた人物で、同じトキワ荘の住人だった有名な漫画家は誰か ?

考察 : まずは、手塚治虫について調べる必要があります。
行動 : Wikipedia検索
入力 : 手塚治虫
結果 : ... 1973年に『週刊少年チャンピオン』(秋田書店)で連載開始された『ブラック・ジャック』も、もともとは少年誌・幼年誌で人気が低迷していた手塚の最期を看取ってやろうという、 ...

考察 : つぎに、トキワ荘について調べる必要があります。
行動 : Wikipedia検索
入力 : トキワ荘
結果 : ... 手塚治虫、藤子不二雄、石ノ森章太郎、赤塚不二夫ら著名な漫画家が居住していたことで知られ、漫画の「聖地」となったことから、 ...

考察 : トキワ荘に居住していた他の有名な漫画家は、藤子不二雄、石ノ森章太郎、赤塚不二夫です。まずは、藤子不二雄について調べる必要があります。
行動 : Wikipedia検索
入力 : 藤子不二雄
結果 : ...

...

さきほどと同様、アプリケーション側では、これを受けて、実際に藤子不二雄の Wikipedia の項目を検索して、以下のようなプロンプトを渡します。
ここには、実は答えとなる文書が入っており、言語モデルでは、下記の通り、答えが「藤子不二雄」であることがわかります。

あなたは、以下のツールが利用可能です。

- Wikipedia検索: このツールは Wikipedia の記事を返します。引数は、取得したい Wikipedia の項目名です。

ツールを利用するには、以下のフォーマットを使います。

```
考察 : どのような考えでそのツールを使うのか記述
行動 : 使用するツールの名前。今回は Wikipedia検索 のツールのみ使用可能です。
入力 : ツールに渡す引数
結果 : この行動の結果
```

与えられたタスクを解くために、このフォーマットでツールを 1 つずつ使用します。
そして、最終的にユーザーに結果を応答する場合は、以下のフォーマットを使います。

```
考察 : 答えがわかりました
答え : 最終的なタスクの結果
```

では、はじめましょう。
以下のタスクを求める手順を 1 つずつ答えてください。

タスク : 手塚治虫の代表作「ブラック・ジャック」の連載開始と同じ年にテレビアニメ化されたある漫画を書いた人物で、同じトキワ荘の住人だった有名な漫画家は誰か ?

考察 : まずは、手塚治虫について調べる必要があります。
行動 : Wikipedia検索
入力 : 手塚治虫
結果 : ... 1973年に『週刊少年チャンピオン』(秋田書店)で連載開始された『ブラック・ジャック』も、もともとは少年誌・幼年誌で人気が低迷していた手塚の最期を看取ってやろうという、 ...

考察 : つぎに、トキワ荘について調べる必要があります。
行動 : Wikipedia検索
入力 : トキワ荘
結果 : ... 手塚治虫、藤子不二雄、石ノ森章太郎、赤塚不二夫ら著名な漫画家が居住していたことで知られ、漫画の「聖地」となったことから、 ...

考察 : トキワ荘に居住していた他の有名な漫画家は、藤子不二雄、石ノ森章太郎、赤塚不二夫です。まずは、藤子不二雄について調べる必要があります。
行動 : Wikipedia検索
入力 : 藤子不二雄
結果 : ... 1969年に連載を開始した『ドラえもん』(1969-1996)が1973年のテレビアニメ化を経てじわじわと人気を高め、1977年にはドラえもんを ...

考察 : 答えがわかりました
答え : 藤子不二雄

今回は、たまたま 1 人目の藤子不二雄が答えでしたが、もし藤子不二雄が答えでない場合には、石ノ森章太郎、赤塚不二夫と、答えが見つかるまで順番に調べていくことになるでしょう。

この ReAct の手法は、Multi-Hop QA だけでなく、例えば、顧客情報データベース、顧客問い合わせ履歴データベース、製品情報データベースのように複数のデータソースにわかれている検索 (Multi Data-Source の検索) でも、同じ手法で、まずどのデータソースを検索すべきか提案させることで対応できます。

人の思考手順を模した非常に強力な手法です。

Step-Back Prompting (STP)

こちらも Reasoning を使います。

少し難解なので、論文で紹介されている例を使って日本語で紹介します。

今回、ユーザーから、下記のような科学的な質問 (自然文) が渡されたと仮定します。

温度が 2 倍、体積が 8 倍に増加した場合、
一般に気体の圧力 P はどうなりますか ?

まず抽象化フェーズでは、言語モデルに、一般性を伴う (より上位概念の) step-back 質問を作成させます。
今回の場合、言語モデルが、

この質問の背景にある物理の原理は何ですか ?

という step-back 質問を作成したと仮定します。(論文では、言語モデルとして Google の PaLM-2 を使用しています。)
そして、この step-back 質問に対する回答をいつものように (Web 検索や DB 検索による) RAG によって作成します。
今回の場合、以下の回答が得られたと仮定します。

状態方程式: PV = nRT
ここで、P は圧力、V は体積、n はモル数、
R は気体定数、そして T は温度です。

さいごに Reasoning フェーズで、この step-back 質問の結果と元の質問を与えて、回答を生成させます。(ハイライト箇所は、言語モデルが返した答えです。)

質問に回答するために、以下のコンテキストを使用してください。
もし回答がコンテキストから得られない場合、「私は知らない」と回答してください。

コンテキスト:
"""
状態方程式: PV = nRT
ここで、P は圧力、V は体積、n はモル数、
R は気体定数、そして T は温度です。
"""

質問:
温度が 2 倍、体積が 8 倍に増加した場合、
気体の圧力 P はどうなりますか ?

回答:
温度が 2 倍になると、圧力も 2 倍になります。
体積が 8 倍になると、圧力は 1/8 になります。
よって、気体の圧力 P は 2/8 = 1/4 倍になります。

下図に、論文で紹介されている Step-back Prompting の概念図を掲載します。(図中の「Step 1: Abstration」と「Step 2: Reasoning」が、それぞれ上述の抽象化フェーズと Reasoning フェーズに対応します。)
すなわち、その名前 (Step-Back) が示すように、いったん俯瞰的に見ることで、質問応答の精度をあげる手法です。

図出典: 「TAKE A STEP BACK: EVOKING REASONING VIA ABSTRACTION IN LARGE LANGUAGE MODELS

Reasoning の応用 (Dynamic Routing, Query Construction, …)

上記の ReAct の例からおわかりいただけるように、Reasoning を使うと、問い合わせの内容に応じて、適宜必要なアクティビティを呼び出して、タスクを処理できます。(Dynamic Routes)

また、Reasoning には他の応用例もあります。
例えば、問い合わせ内容が「どのカテゴリの製品に関するものか」など、言語モデルの Reasoning により、ユーザー質問 (自然文) から metadata (meta properties) を抽出して、この metadata による filtering と組み合わせることで検索対象をより絞り込んでインデクス検索をおこない、それにより精度を上げる方法もよく行われます。
また、検索対象が RDB (リレーショナルデータベース) の場合には、「プロンプト エンジニアリングの例と解説」で紹介したコード生成の方法で、言語モデルを使って自然文 (質問) から SQL 文を生成させると良いでしょう。(Query Construction)

このように、原理さえ理解すれば、Reasoning をさまざまな形で RAG に応用できます

Embedding Finetuning

さいごに、Embedding モデルにおいてもファインチューニング (モデルの微調整) が使える点を補足しておきます。

OpenAI のように Embedding の finetuning をサポートしていない Closed な言語モデルでは不可能ですが、オープンソースの Embedding モデル (MPNet, E5, Instructor など) を使用している場合、ドメイン固有のデータを使って Finetuning をおこなうことで、検索の精度が向上することが論文などでも報告されています。(OpenAI 社のセミナーでもこの点は強調しています。動画「A Survey of Techniques for Maximizing LLM Performance」を参照。)

Embedding モデルの Finetuning と聞くと、特別なラベル付けをおこなったデータの準備が必要と思われるかもしれませんが、多くのモデルは、コーパスをそのまま学習させるだけで良く、特別なラベル付けは不要です。
その一方で、学習環境を用意するなど高度なスキルも必要とされます。より現実的なモデル学習や Finetuning については、こちら の動画を参考にしてみてください。(Embedding モデルの finetuning においても、ここで解説している LoRA は使用できます。)

例えば、財務関連のドメインでは、「有価証券報告書」、「有報」、「財務諸表」、「決算書」などは、しばしば同じ文脈の中で扱われることでしょう。このように特定ドメインを対象に RAG のシステムを構築する際、そのドメインの充分なコーパスで Embedding モデルをファインチューンして使うことで、より近いコンテキストの回答が得られることが期待できます。
一歩上の RAG を実装する方法として是非憶えておいてください。

 

ここでは、より先進的な RAG の手法の代表的なものをいくつかピックアップしましたが、検索対象のドキュメントや質問・応答の性質などによって、向いている手法や向いていない手法もあります。また、どれか 1 つを選択するということではなく、必要に応じていくつかの手法を組み合わせると良いでしょう。(順番が関係する場合には、Query Routing などを構成します。)
新しい RAG の手法も日々紹介されていますので、最新の論文など適宜キャッチアップしておくと良いでしょう。

 

2 thoughts on “RAG (検索拡張生成) のさまざまな手法 (パターン)

  1. Pingback: Copilot アーキテクチャと Custom Copilot 作成 | @Subaru
  2. Pingback: Knowledge Graph による質問応答のアーキテクチャ解説 | @Subaru

Comments are closed.