<< TOPへ
QuIM-RAG: Advancing Retrieval-Augmented Generation with Inverted Question Matching for Enhanced QA Performance
# 大きなテーマ:どうやってコンピュータに正確に答えさせるか?
私たちは、コンピュータに「質問」を投げかけるとき、できるだけ正しい答えを知りたいですよね。
でも、コンピュータは一度にいろいろな情報を読んで覚えると、関係ない情報にまぎれてしまったり、間違ったことを答えたりすることがあります。
この研究では、コンピュータに正しい答えを返してもらうために、**「質問するときに必要な情報をきちんと探し、まとめてから答えを作る」**という仕組みを工夫しています。
---
## 1. 「RAG」ってなに?
- **RAG** は「Retrieval-Augmented Generation(情報検索つき文章生成)」の略です。
- ざっくり言うと、**「AIが答える前に、必要そうな資料(テキスト)をちゃんと探してから、その資料をもとに答えを作る」**というやり方です。
- これによって、AIが「なんとなく言いそうな文章」を勝手に作るだけでなく、実際の文章や資料を参考にするので、より正確に答えられるようになります。
---
## 2. でも、課題はある
- **情報が多すぎると、AIが必要な部分をうまく選べない** ことがある
- ときどき AI がでたらめ(ハルシネーション)を言ってしまうことがある
この2つの問題をどう解決するかが大事です。
---
## 3. 新しい工夫「QuIM-RAG」ってなに?
この論文では、RAG をさらに工夫した **「QuIM-RAG」** という方法を提案しています。
これは「Question-to-question Inverted Index Matching(質問をもとにして、質問を探すインデックス)」という仕組みを使います。
### ざっくり解説すると
1. **資料を小さなチャンク(かたまり)に分ける**
- たとえば、教科書をいくつかのパラグラフごとに区切るようなイメージ。
2. **各チャンクから「どんな質問が来たら、このチャンクが答えられそうか」を先に用意しておく**
- AIに「このかたまり(チャンク)の内容を質問にすると、どんな質問が作れる?」と聞いて、まとめておく。
3. **それらの質問を、ベクトルという数字の形に変える**
- AI同士が質問を比べやすくするために、言葉をベクトル化する。
4. **「近い意味の質問は同じグループにまとめる」ようなインデックス(検索表)を作る**
- これを「Inverted Index(インバーテッドインデックス)」と呼ぶ。
5. **ユーザが実際に質問すると、まずその質問をベクトルにして、検索表から近い意味の「質問」を探す**
- 近い質問が見つかったら、その「質問」に紐づいていたチャンク(テキスト)を取り出す。
6. **取り出したチャンクだけを AI に渡して答えを作る**
- 余計な情報を使わないから、間違った回答や関係ない文章がまぎれにくくなる。
---
## 4. どんな実験をしたの?
- 研究者たちは、**North Dakota State University (NDSU)** という大学のサイトをいっぱい集めて(約500ページ以上)、そこに書いてあることを「キャリアアドバイス」と「カタログ(授業や規則)」ごとに分けて大量のデータを準備しました。
- そのデータをチャンクに分けて、それぞれから「こんな質問が来たときはこのチャンクで答えられるよね」という質問をAIで作成。
- そうやって作った大きな質問集&チャンク集(データベース)をもとに、クエリ(ユーザの質問)が来たら、最も近い質問やチャンクを探して答えさせる。
- そして、**従来のやり方(普通のRAG)** と **提案したやり方(QuIM-RAG)** で比べてみました。
---
## 5. 結果はどうなったの?
- 提案した **QuIM-RAG** のほうが、**答えが正確** で、質問に対してより合った答えが返ってきやすくなりました。
- さらに、使われる文脈(チャンク)も、ユーザの質問に合ったものがしっかり選ばれていると評価されました。
- 間違った情報(ハルシネーション)が減ったり、不要に長い説明を避けられる効果も確認されました。
---
## 6. まとめ図:QuIM-RAG のしくみ
下記の図は、ざっくりとしたフローを示します。文字だけですがイメージしてみてください。
```
┌─────────┐ ユーザ
│ 1.たくさんの │ からの質問
│ 資料(文章) │ 「NDSUの
└────┬────┘ 住所教えて」
│
▼ (まず資料を分ける)
┌────────────────────┐
│ 2.資料を小分け(チャンク)にする │
│ 3.チャンクから"どんな質問で答えられそう?" │
│ をAIに生成させる │
└────┬───────────────────┘
│(質問とチャンクをベクトル化+整理)
▼
┌────────────────────┐
│ 4. 質問検索用のデータベース(InvertedIndex)│
│ ここに「質問→チャンク」の対応表を保存 │
└────┬───────────────────┘
│(ユーザが質問してきたら)
▼
┌────────────────────┐
│ 5. ユーザの質問をベクトルに変換し、 │
│ 似た質問を検索→対応するチャンクを取り出す │
└────┬───────────────────┘
│(取り出したチャンクだけ使う)
▼
┌────────────────────┐
│ 6. AIモデルがそのチャンクをもとに回答を生成 │
│ 「住所は〇〇です。確認したいならこのリンク…」│
└────────────────────┘
```
---
## 7. これからの展望
- 大学サイトの情報は毎年、学期が変わるたびに更新されます。そこで、**数か月ごとに新しい情報を取り込む仕組み** を作る予定です。
- また、実際に人が使うときの満足度や使いやすさをテスト(ユーザスタディ)し、結果を見ながら改善していく計画です。
- こうした方法を発展させることで、大学情報だけでなく、他のいろんな分野でも**正確なQA(質問応答)システム**が作れるはずだと考えられています。
---
### まとめ
1. **RAG** とは、必要な情報を探してからAIが文章を作る仕組みで、より正確な答えを出そうとする工夫。
2. **QuIM-RAG** は、質問同士を結びつける特殊な仕組みで、正確なチャンク(文書断片)を探すのが得意。
3. たくさんの大学ページをデータにして実験したら、従来より正確な回答が得られた。
4. これからもっとたくさんの分野で「正確で役立つAI」を作るのに応用できそう。
---
追加に掘り下げてみたよ!
# 1. インデックス(検索表)はどんな形態のデータなの?具体的に
### (1) 大まかな仕組み
- **「Inverted Index(インバーテッドインデックス)」** とは、本来はキーワード検索などで用いられるデータ構造で、キーワード(あるいはトークン)から「それを含む文書ID」の一覧を引けるようにしたものです。
- この研究では、**「単なるキーワード」ではなくベクトル(埋め込み)を用いた「プロトタイプ」** をキーにして、「そのプロトタイプと類似しているベクトル(=質問やチャンク)の集合」を管理する、という形で使っています。
### (2) 具体的な格納イメージ
1. **まずチャンクや生成された質問をベクトル化**
- たとえば、`v_chunk_1, v_chunk_2, ... v_question_1, v_question_2 ...` といった具合に、文章を数百次元のベクトル(浮動小数点値の配列)で表します。
2. **ベクトルを「プロトタイプ(クラスタの代表)」に量子化する**
- ベクトル空間上で似通ったベクトル同士を1つのグループにまとめ、「クラスタの中心(プロトタイプ)」を作ります。
- たとえば `p1, p2, ... pk` というように、**いくつかの代表ベクトル** が用意されていて、それに近いベクトルはみんな同じクラスタに入る仕組みです。
3. **インデックスの構造:**
- **キー:プロトタイプ(またはそのID)**
- **値:そのプロトタイプに紐づくベクトルのリスト**(さらにそれが「どのチャンクIDや質問IDなのか」を記録しておく)。
たとえば、プログラムで扱う場合は下記のようなイメージです(あくまで例):
```python
# Keyが「プロトタイプID」、Valueが「(ベクトル, オリジナル質問ID or チャンクID)」一覧
inverted_index = {
0: [
(v_q_11, "question_id_11"),
(v_q_35, "question_id_35"),
(v_c_8, "chunk_id_8"),
...
],
1: [
(v_q_2, "question_id_2"),
(v_c_20, "chunk_id_20"),
...
],
...
}
```
- ここで「0, 1, ...」が各プロトタイプのインデックスIDとイメージしていただければよいです。
- 実際には、ChromaDB のような**ベクトルデータベース**を使って管理しているので、エンジン内部でクラスタリングや近似検索が行われるようになっています。
### (3) 検索時のフロー
- ユーザから来た「質問(クエリ)」も同様にベクトル化 → 近いプロトタイプを検索 → インデックスを辿る → そのプロトタイプに属している「質問ベクトル/チャンクベクトル」を取り出す → スコアが高い順に絞り込む
- こうして取り出したチャンクをもとに最終的な回答を生成します。
---
# 2. QAの形態も具体的に教えて
ここでいう「QA(質問応答)の形態」は大きく2段階あります。
1. **「学習用コーパス(QAデータセット)の作り方」**
- 研究では、サイトをスクレイピングして得られた長い文章を「チャンク」に分割します(例:1,000トークンに区切って重複を200トークン分持たせる等)。
- そのチャンクごとに「チャンク内容を聞くための質問群」を GPT-3.5-turbo-instruct で生成させます。
- 例:「このチャンクには就職相談の受付時間が書いてあるから、生成された質問としては『就職相談は何時から何時まで受け付けているのですか?』のようなものができあがる」
- さらに、その「生成された質問」に対する答えとしては「そのチャンクのテキストそのもの」を登録しておきます。
- 結果として、「Q:〇〇」「A:チャンクの原文」というペアが大量に出来上がるイメージです。
2. **「実際にユーザが問い合わせ(クエリ)を投げるとき」**
- ユーザ:自由に「知りたいこと」を自然言語で入力(例:「NDSUのキャリアセンターの住所は?」)
- システム:上記で作った「Q-Aペア」がたくさん詰まったインデックスを使って、
- (a) ユーザの質問と似た「作り置きの質問」を探す
- (b) そこから対応するチャンク(テキスト本体)を取り出す
- (c) さらに LLM に「これが文脈情報だよ」と渡して、回答を生成
- つまり最終的に回答するときは「A: 〜〜〜」と返し、その際に元となったソースリンクなども提示することで、信頼性・正確性を高める。
---
定量的な評価はやっているのかな?調べてみよう!
# 3. 実験内容は定量的な評価をしている?
### (1) している → 「BERTScore」 と「RAGAS」 で評価
論文では、**定量的な評価指標**として下記2つを使っています。
1. **BERTScore**
- BERT や RoBERTa などの大規模言語モデルの「単語埋め込み」を使って、
- 生成された回答と正解の回答(リファレンス)の類似度を測る手法。
- 従来の BLEU や ROUGE と違い、単なる表面的な n-gram 一致でなく「意味的な一致度」を測れます。
- 世界的にかなり広く使われているテキスト評価指標で、論文でも [32] (T. Zhang et al.) といった形で参照されています。
2. **RAGAS**
- 「Retrieval-Augmented Generation Assessment」 の略。
- RAG アーキテクチャ専用の評価フレームワークで、ここ数年で提案・発展している手法です。
- 下記の3つの観点で測定します:
1. **Faithfulness**: 生成された回答が、ちゃんと取得した文脈情報に沿っているか(でたらめじゃないか)
2. **Answer Relevance**: 回答が質問にしっかり合っているか
3. **Context Relevance**: 取得した文脈が本当にその質問に関係があるか
RAGAS はまだ比較的新しめの指標ですが、**LangChain や llama-index などの人気ライブラリにも組み込まれ始めており**、RAGを評価する上で注目されている手法です。
### (2) なぜこれらを使うのか?
- **BLEU や METEOR, ROUGE** は機械翻訳や要約の評価に強い指標ですが、**QAタスクでの正確な回答評価** には必ずしも適していません。
- そのため、**BERTScore**(意味レベルでの類似を見たい場合)や、**RAGAS**(RAG特化)を用いているというわけです。
- 世界的にも、**「QAなどの自由回答でBLEUやROUGEをそのまま使うのは不適」** という声が多く、BERTScoreのほうが広く認められています。
---
## 再度、おまとめ
- **インデックス(検索表)の形態**: 「プロトタイプID」→「近いベクトル(質問/チャンク)の一覧」を格納するいわゆる“ベクトルの反転インデックス”風の構造。
- 実装上は ChromaDB などを用いており、クラスタリング/量子化の結果をもとに「近いプロトタイプ」をキーに高速に検索できるようになっています。
- **QAの形態**:
1. データセット作成段階で「チャンクから可能な質問をたくさん生成→それぞれの答えとしてチャンク原文を持つ」形式の Q-A を用意。
2. 実際のユーザ質問をベクトル検索して最も近い Q-A ペアを取り出し、そのチャンクを使ってLLMに回答生成させる形。
- **定量的な評価**:
- **BERTScore** という埋め込みベースの類似度指標(テキスト生成の評価で著名)、
- **RAGAS** という RAG システム特化型の評価フレームワーク(世界的にも注目度上昇中)
- といった評価手法を使い、従来システムとの比較を行っている。
---
# RAGのコンテキストに入れるQAについて、冗長な方がいいのでは?という考えについて
この文脈にもある通り、RAGに確実に近いコンテキストをヒットさせるためには、ソースとなるQAを(内容が被ったとしても)複数作ったほうが良いと判断できるよね。
これは、結論から言うと、**「内容が似通っていても、多少バリエーションのある質問を複数用意しておくことが望ましい」** という考え方があります。以下では、その理由を詳しく整理してみます。
## 1. RAG全体の流れのおさらい
RAG(Retrieval-Augmented Generation)は、
1. **索引(インデックス)** や **ベクトル検索** でユーザの質問に合った文脈(チャンク)を探す
2. その文脈を使って大規模言語モデル(LLM)に最終回答を生成させる
という流れです。
---
## 2. なぜ「重複っぽい質問」でもたくさん作ると良いのか
### (1) いろいろな聞き方に対応しやすくなる
- ユーザが本質的に同じことを聞いていても、言い回しが違う場合が多々あります(例:「営業時間は?」と「何時からやってますか?」はほぼ同じ意味)。
- システムとしては、「“営業時間は?” に対応する質問は持っているけれど、“何時からやってますか?” には対応していない」状況を避けたい。
- そのため、**ユーザがいろいろな表現で聞いてきてもヒットしやすいように、少しずつ違う形の質問を多数用意しておく**のが効果的です。
### (2) ベクトル検索において「言い回しの違い」を埋めやすい
- 質問をベクトル化して検索するときに、微妙に違う言い回しの質問をたくさんインデックスに登録しておけば、類似ベクトルとして引っかかりやすくなります。
- 結果として、**「ユーザの質問」に近い埋め込みを持つ「登録済みの質問」** が見つかりやすくなり、正確なチャンクを引き出しやすくなるわけです。
### (3) RAGの利点を最大化する
- RAG は「最適な文脈を探す」ことが肝ですが、事前に用意する Q-A が少ないと、ベクトル検索のカバー範囲が狭くなってしまいます。
- **似た意味の Q-A を多めに登録しておくほど、ベクトル空間での検索の精度・網羅性が上がりやすい** という傾向があります。
---
## 3. ただし「全く重複した質問」を無制限に作るのは注意
- 上記の理由で、**「似ているが微妙に違う言い回しの質問」** をある程度用意しておくのは有用です。
- しかし、**文面が完全に重複している質問** や、意味にほぼ差のない質問を過剰に量産するだけでは、逆にインデックスが膨れ上がってノイズになる可能性もあります。
- どの程度のバリエーションを作るかは、
1. ドメインの広さ
2. ユーザが実際にどう質問してくるか
3. データベースのサイズや検索速度とのバランス
- などを考慮して調整するのが一般的です。
---
## 4. まとめ
- **内容がかぶっていても多少表現が異なる質問は、RAG システム全体の精度を上げるために有効** です。
- 特に、ユーザがいろいろな言い回しで質問してきても適切に対応したい場合は、**バリエーション豊富な質問** をソース文書から作っておくと、検索精度や回答の的確性が高まります。
- ただし、全く同じ質問を無制限に大量生産するのは逆に効率を落とす場合もあるため、**バランス**が重要です。
---
以上のことから、「多少かぶり気味の質問であっても、ソース文書から様々なバリエーションを生成しておく」ことは **RAG の仕組みとしては望ましい** と言えます。