はじめに
前回は、最も基本的なRAGの構成である「Naive RAG」について学び、TypeScriptで実装しました。今回は、検索精度を改善する手法の一つである Reranking RAG(リランキングRAG) について学んでいこうと思います。Reranking RAGは、検索した文書を再評価して並べ替えることで、LLMに渡す情報の品質を高める手法です。
今回は、この再評価の処理に Jev を使用します。Jevは自然言語で判断基準を与えられる意思決定モデルで、検索した文書が質問への回答に役立つかを評価することで、Rerankingに活用できます。前回実装したNaive RAGをベースに、Jevを使ってRerankingを実装し、検索順位や回答品質がどのように変化するのかを実験していきます。
前回の記事・実装
Reranking RAGとは?
Reranking RAGとは、検索した文書を再評価し、質問への関連性や回答への有用性に基づいて順位を並べ替えてから、LLMに渡すRAGの構成です。Naive RAGでは、Embeddingなどによる検索結果の上位文書をそのままLLMに渡します。
一方、Reranking RAGでは、検索結果を別のモデルで再評価してからLLMに渡します。
| 比較 | Naive RAG | Reranking RAG |
|---|---|---|
| 文書の検索 | Embeddingなど | Embeddingなど |
| 検索後の再評価 | なし | あり |
| LLMに渡す文書 | 検索上位の文書 | 再評価後の上位文書 |
| 特徴 | シンプルで高速 | 検索順位の改善が期待できる |
このように、基本的なRAGに Reranking(再順位付け)という処理を追加するのが特徴です。Reranking自体はJev固有の技術ではなく、Cross-Encoderなどのモデルでも実現できます。
処理の流れ
Naive RAGとReranking RAGの違いは、RetrievalとGenerationの間にRerankingが追加されることです。
処理の内容は以下のとおりです。
| 処理 | 役割 |
|---|---|
| Retrieval | 質問に関連する文書を幅広く取得する |
| Reranking | Jevで取得文書を再評価して順位を並べ替える |
| Generation | 再評価後の文書をもとにLLMが回答を生成する |
今回は、既存のNaive RAGにJevを使ったReranking処理を追加します。
検索候補は上位10件、LLMに渡す文書は上位3件とし、Rerankingの有無によって検索結果と回答品質がどう変化するかを比較します。
成果物
今回は、Naive RAGでは正しい回答が取れず、Reranking RAGでは取れるケースを実装します。
質問は「Standardプランを月の途中で解約したら、日割りになりますか?」です。正解は「日割りにならない。解約した月は満額」で、根拠は「退会後の請求」です。
Embeddingは、意味空間で質問に近い節を上位にします。質問の「日割り」「月の途中」に近い「プラン変更時の日割り」が高くなり、正解の「退会後の請求」は上位3件に入りません。Naive RAGは解約時の日割りを判断できず、「分からない」と答えます。Rerankingでは、Jevが各節の意味をもう一度判断し、「退会後の請求」を上位に戻します。回答は「日割りにならない」になります。
検索の評価フロー
比べる条件は、検索候補が上位10件、LLMに渡す文書が上位3件、回答を書くLLMは同じ、という3つです。変えるのは、10件から3件を選ぶ方法だけです。
左側が、前回までのNaive RAGです。ベクトルの近さ順を、そのまま回答の材料にします。この質問では「プラン変更時の日割り」や「日割り請求のルール」が残り、解約時の日割りが書いてある節は上位3件から外れます。
右側が、今回足すRerankingです。候補の10件は左側と同じです。Jevには、検索スコアではなく次の判断を文書ごとにさせます。
この文書は、月の途中で解約したときに料金が日割りになるかを判断する根拠になるか。
| 点数 | 基準 | 当てはまる節 |
|---|---|---|
| 0 | 質問と関係がない | 領収書、ログインなど |
| 1 | 料金や退会には触れるが、解約時の日割りは判断できない | 契約更新のルール、請求日 |
| 2 | 日割りや満額には触れるが、解約時のルールとは限らない | プラン変更時の日割り、日割り請求のルール |
| 3 | 解約した月の料金が日割りか満額かを判断できる | 退会後の請求 |
「プラン変更時の日割り」は、月の途中と日割り請求の両方が書いてあります。ただし対象はプラン変更です。解約した月が満額かどうかは、この節からは決まりません。点数は2です。
「退会後の請求」には、月の途中で解約しても日割りにならないと書いてあります。点数は3です。並べ替え後の上位3件にこの節が入ると、LLMへ渡す材料が「日割りで請求する」から「日割りにならない」に変わります。
評価では、次の2つをNaive RAGとReranking RAGで並べます。
| 見ること | Naive RAG | Reranking RAG |
|---|---|---|
| 上位3件に「退会後の請求」が入るか | 入りにくい | 入る |
| その3件から作った回答 | 解約時の日割りは分からない | 日割りにならない。解約した月は満額 |
検索で取る10件は同じなので、差が出るとすれば、Jevの採点で3件の中身が入れ替わったときです。
Jevのリクエストとレスポンス
候補1件ごとに、POST https://api.typesafe.ai/v1/systemone を1回送ります。モデルは jev-latest です。state に質問と節を入れ、questions.usefulness で4段階の点数を聞きます。
「退会後の請求」を送ったリクエストです。
{
"state": "質問: Standardプランを月の途中で解約したら、日割りになりますか?\n\n文書:\n# 退会\n## 退会後の請求\n\n退会手続きが完了した月の料金は満額請求されます。月の途中で解約しても日割りにはなりません。退会の翌月以降、月額料金は請求されません。年払いの未経過分は返金しません。",
"questions": {
"usefulness": {
"type": "score",
"instructions": "この文書は、月の途中で解約したときに料金が日割りになるかを判断する根拠になるか。",
"criteria": [
"質問と関係がない",
"料金や退会には触れるが、解約時の日割りは判断できない",
"日割りや満額には触れるが、解約時のルールとは限らない",
"解約した月の料金が日割りか満額かを判断できる"
]
}
},
"model": "jev-latest"
}
返ってきたレスポンスです。score が 3 なので、この節は解約した月の料金を判断できる文書です。probabilities は 3 が 1 で、ほかの点数は 0 です。
{
"model": "jev-1.14.0",
"answers": {
"usefulness": {
"type": "score",
"score": 3,
"confidence": 1,
"legend": {
"0": "質問と関係がない",
"1": "料金や退会には触れるが、解約時の日割りは判断できない",
"2": "日割りや満額には触れるが、解約時のルールとは限らない",
"3": "解約した月の料金が日割りか満額かを判断できる"
},
"probabilities": {
"0": 0,
"1": 0,
"2": 0,
"3": 1
}
}
},
"usage": {
"input_tokens": 544,
"output_tokens": 19
}
}
実行結果
比較は npm run rerank で実行します。検索候補は上位10件、LLMに渡すのは上位3件です。
Naive RAGの上位3件は、類似度 0.9200 の「プラン変更時の日割り」、0.8600 の「日割り請求のルール」、0.8000 の「請求日」です。「退会後の請求」は入っていません。回答は、プラン変更の日割りは書いてあるが、解約時の日割りは判断できない、というものでした。
Reranking RAGでは、同じ候補を Jev の関連度で並べ替えています。1位は関連度 3.00 の「退会後の請求」です。類似度は 0.6800 で、Naive RAGの3件より低い節です。2位は関連度 2.41 の「日割り請求のルール」、3位は関連度 1.72 の「プラン変更時の日割り」です。回答は「日割りにはなりません。解約した月の料金は満額で請求されます」でした。
| 1位 | 回答 | |
|---|---|---|
| Naive RAG | プラン変更時の日割り(類似度 0.9200) | 解約時の日割りは分からない |
| Reranking RAG | 退会後の請求(関連度 3.00) | 日割りにならない。解約した月は満額 |
まとめ
今回は、Jevを使ってReranking RAGを実装し、Naive RAGとの違いを比較しました。
Naive RAGでは、質問と意味的に近い文書が上位に表示され、回答に必要な「退会後の請求」が検索上位3件から漏れていました。一方、Reranking RAGでは、Jevが文書の有用性を再評価することで、必要な文書を1位にでき、正しい回答を生成できました。
検索結果の類似度が高いことと、質問への回答に役立つことは必ずしも同じではないと、実装を通して理解できました。
ただし、Rerankingは取得済みの文書を並べ替える仕組みのため、最初の検索で必要な文書が取得できていることが前提です。


