はじめに
前回は、Jevを使った「Adaptive RAG」について学び、質問の内容に応じて検索方法を切り替える仕組みを実装しました。今回は、検索結果の品質を評価し、必要に応じて再検索する Corrective RAG(CRAG) について学んでいこうと思います。
Corrective RAGでは、検索した文書が質問への回答に十分な情報を含んでいるかを評価し、不十分な場合は追加検索などで情報を補います。今回は、この判断に Jev を使い、Naive RAGと比較して、検索に失敗した場合でも正しい情報を取得できるのかを実験していきます。
これまでの記事・実装
- Step0:Naive RAG
- Step1:Jevを使ったReranking RAG
- Step2:Jevを使ったFiltering RAG
- Step3:Jevを使ったAdaptive RAG
- GitHub:jev-rag-learning
Corrective RAGとは?
Corrective RAG(CRAG)とは、検索結果の品質を評価し、必要な情報が不足している場合に検索結果を修正・補完してから回答を生成するRAGの構成です。
Naive RAGでは、Embeddingによる検索結果の上位文書をそのままLLMに渡します。一方、Corrective RAGでは、検索結果が質問に回答するための根拠として十分かを評価し、必要に応じて再検索を行います。
| 比較 | Naive RAG | Corrective RAG |
|---|---|---|
| 文書の検索 | Embedding | Embedding |
| 検索結果の評価 | なし | Jevで品質を判断 |
| 検索結果が不十分な場合 | そのまま回答生成 | 再検索・情報の補完 |
| 特徴 | シンプルで高速 | 検索失敗からの回復を目指す |
Corrective RAGでは、検索結果の品質を主に以下の3つに分類します。
| 判定 | 意味 | 対応 |
|---|---|---|
| Correct | 回答に必要な情報が取得できている | 検索結果を利用 |
| Ambiguous | 検索結果が十分か判断しにくい | 情報を補完 |
| Incorrect | 必要な情報が取得できていない | 別の情報を検索 |
2024年に発表されたCorrective Retrieval Augmented Generationでは、検索結果の品質評価に加えて、Web検索による補完や、文書から必要な情報を抽出するKnowledge Refinementなどが提案されています。
今回は、Jevで検索結果の品質を評価し、不十分な場合に検索し直す仕組みに絞って実装します。
処理の流れ
Naive RAGとの大きな違いは、RetrievalとGenerationの間に検索結果の評価と修正処理が追加されることです。
処理の内容は以下のとおりです。
| 処理 | 役割 |
|---|---|
| Retrieval | 質問に関連する文書を検索 |
| Corrective | Jevで検索結果を評価し、必要に応じて再検索 |
| Generation | 取得した文書をもとに回答を生成 |
今回は、Jevのchoiceを使用して、「Correct」「Ambiguous」「Incorrect」の3つから検索結果の品質を判定します。
なお、Jevは検索結果の評価を担当し、実際の検索文の生成や再検索はアプリ側で実行します。
成果物
今回も、架空のSaaS「TaskFlow」の問い合わせ回答システムを使用します。Naive RAGとCorrective RAGを比較し、検索結果が不十分な場合に再検索で必要な文書を足せるかを見ます。
比較する質問は2つです。
| 質問 | 必要な節 | 上位3件 |
|---|---|---|
| クレジットカードの決済に失敗したままだと、いつタスクを編集できなくなりますか? | 支払い失敗 | 入る |
| Standardプランを月の途中で解約したら、日割りになりますか? | 退会後の請求 | 入らない |
1問目の正解は「14日を過ぎても支払われなければ、ワークスペースは読み取り専用になる」です。検索すると「支払い失敗」が1位になるので、再検索は不要です。
2問目の正解は「解約した月は満額で、日割りにならない」です。上位3件は「プラン変更時の日割り」「契約更新のルール」「日割り請求のルール」で、解約した月の料金が書いてある「退会後の請求」は入りません。こちらで再検索の効果を見ます。
検索の評価方法
同じ質問とマニュアルを使い、Naive RAGとCorrective RAGを比較します。違いは、検索結果を Jev が判定し、不足なら1回だけ検索し直すことです。
| 比較項目 | Naive RAG | Corrective RAG |
|---|---|---|
| 初期検索 | 上位3件 | 上位3件 |
| 検索結果の評価 | なし | Jevのchoice
|
| 不十分な場合 | そのまま回答 | 検索文を作り直して1回再検索 |
| 回答モデル | GPT-4.1-mini | GPT-4.1-mini |
見る項目は、選ばれた判定、再検索の有無、渡した文書、回答、入力トークン、処理時間です。
実装内容
品質の判定は、Jevのchoiceを1回送ります。POST https://api.typesafe.ai/v1/systemone で、モデルは jev-latest です。state に質問と上位3件を入れ、Correct、Ambiguous、Incorrect から1つ選びます。Correct 以外のときは、取得済みの文書を渡して LLM が検索文を1つ作り、再検索した文書を足します。検索文そのものは Jev のレスポンスには含まれません。
1問目のリクエストです。文書は「支払い失敗」「退会後のデータ削除」「請求日」です。
{
"state": "質問: クレジットカードの決済に失敗したままだと、いつタスクを編集できなくなりますか?\n\n文書:\n# 請求\n## 支払い失敗\n\n支払いが失敗すると、7 日後と 14 日後に再試行します。14 日を過ぎても支払われない場合、ワークスペースは読み取り専用になります。データはすぐには削除されません。\n\n# 退会\n## 退会後のデータ削除\n\n退会が完了してから 30 日後に、ワークスペースのタスク、添付ファイル、メンバー一覧は完全に削除されます。30 日以内であれば、同じ管理者アカウントからワークスペースを再開できます。30 日を過ぎると再開はできません。\n\n# 請求\n## 請求日\n\n有料プランの料金は毎月 1 日に、その月の月額料金として登録済みのクレジットカードへ請求されます。",
"questions": {
"grade": {
"type": "choice",
"instructions": "この検索結果は、質問への回答に十分な根拠を含んでいるか。文書が説明している操作と、質問が聞いている操作が違う場合は Incorrect。話題が近いだけでは Correct にしない。",
"criteria": {
"Correct": "回答に必要な情報が、渡された文書に含まれている",
"Ambiguous": "関連する情報はあるが、質問が聞いている操作の根拠としては十分か判断しにくい",
"Incorrect": "質問に答えるために必要な情報が、渡された文書に含まれていない"
}
}
},
"model": "jev-latest"
}
返ってきたレスポンスです。choice は Correct なので、この3件のまま回答します。probabilities は Correct が 0.39、Incorrect が 0.37 で、比較実行のときは 0.43 と 0.36 でした。選ばれたラベルは同じです。
{
"model": "jev-1.14.0",
"answers": {
"grade": {
"type": "choice",
"choice": "Correct",
"confidence": 0.09,
"probabilities": {
"Correct": 0.39,
"Ambiguous": 0.24,
"Incorrect": 0.37
}
}
},
"usage": {
"input_tokens": 812,
"output_tokens": 40
}
}
2問目は、文書を「プラン変更時の日割り」「契約更新のルール」「日割り請求のルール」に変えて送ります。判断基準は同じです。
{
"state": "質問: Standardプランを月の途中で解約したら、日割りになりますか?\n\n文書:\n# 請求\n## プラン変更時の日割り\n\n月の途中でプランを変更した場合、差額は日割りで請求します。Standardプランから上位プランへ変更したときも、変更日以降の料金は日割りになります。\n\n# 請求\n## 契約更新のルール\n\n有料プランの契約は毎月1日に自動更新されます。更新月の料金は満額です。更新の前に、継続するプランを確認してください。\n\n# 請求\n## 日割り請求のルール\n\n日割り請求は、月の途中で契約内容が変わった場合に使います。日割り額は、月額料金を30で割った1日あたりの金額に、残日数をかけて計算します。",
"questions": {
"grade": {
"type": "choice",
"instructions": "この検索結果は、質問への回答に十分な根拠を含んでいるか。文書が説明している操作と、質問が聞いている操作が違う場合は Incorrect。話題が近いだけでは Correct にしない。",
"criteria": {
"Correct": "回答に必要な情報が、渡された文書に含まれている",
"Ambiguous": "関連する情報はあるが、質問が聞いている操作の根拠としては十分か判断しにくい",
"Incorrect": "質問に答えるために必要な情報が、渡された文書に含まれていない"
}
}
},
"model": "jev-latest"
}
返ってきたレスポンスです。choice は Incorrect です。プラン変更の日割りは、解約した月の料金を説明していない、という判定です。probabilities は Incorrect が 0.66 で、比較実行のときは 0.68 でした。この判定のあと、再検索に進みます。
{
"model": "jev-1.14.0",
"answers": {
"grade": {
"type": "choice",
"choice": "Incorrect",
"confidence": 0.49,
"probabilities": {
"Correct": 0.1,
"Ambiguous": 0.24,
"Incorrect": 0.66
}
}
},
"usage": {
"input_tokens": 764,
"output_tokens": 40
}
}
実行結果
比較は npm run crag で実行します。Naive RAGは毎回、類似度の上位3件を1回検索して回答します。
① クレジットカードの決済に失敗したままだと、いつタスクを編集できなくなりますか?
Naive RAGの上位3件は、類似度 0.5159 の「支払い失敗」、0.3436 の「退会後のデータ削除」、0.3377 の「請求日」です。検索は 992 ms、入力トークンは 308、回答生成は 1035 ms です。回答は「14日を過ぎても支払われないと、ワークスペースは読み取り専用になる」でした。
Corrective RAGの判定は Correct です。信頼度は 0.14、確率は Correct 0.43、Ambiguous 0.21、Incorrect 0.36 です。Jev は 229 ms、検索回数は 1、文書数は 3、入力トークンは 308、回答生成は 1013 ms です。文書も回答も Naive RAG と同じです。
| 判定 | 検索回数 | 入力トークン | 回答 | |
|---|---|---|---|---|
| Naive RAG | なし | 1 | 308 | 14日後に読み取り専用 |
| Corrective RAG | Correct(0.43) | 1 | 308 | 14日後に読み取り専用 |
② Standardプランを月の途中で解約したら、日割りになりますか?
Naive RAGの上位3件は、類似度 0.7273 の「プラン変更時の日割り」、0.6144 の「契約更新のルール」、0.5796 の「日割り請求のルール」です。「退会後の請求」は入っていません。検索は 647 ms、入力トークンは 287、回答生成は 920 ms です。回答は「マニュアルには記載がないので、分からない」でした。
Corrective RAGの判定は Incorrect です。信頼度は 0.52、確率は Incorrect 0.68、Ambiguous 0.21、Correct 0.11 です。Jev は 147 ms です。再検索文は「解約した月の料金はどうなりますか」で、作成に 780 ms かかりました。2回目の1位は類似度 0.6405 の「退会後の請求」です。文書数は4件、検索は合計 1429 ms、入力トークンは 367、回答生成は 978 ms です。回答は「日割りにはならない。解約した月の料金は満額で請求される」でした。
| 検索回数 | 文書数 | 入力トークン | 回答 | |
|---|---|---|---|---|
| Naive RAG | 1 | 3 | 287 | 分からない |
| Corrective RAG | 2 | 4 | 367 | 日割りにならない。解約した月は満額 |
まとめ
今回は、Jevのchoiceで検索結果の品質を判定し、不足しているときだけ検索し直す Corrective RAG を Naive RAG と比較しました。
1問目は Correct でした。「支払い失敗」が最初の検索に入っているため、再検索はしていません。回答はどちらも、14日を過ぎると読み取り専用になる、です。入力トークンはどちらも 308 です。
2問目は Incorrect でした。最初の3件はプラン変更や日割り計算の節で、解約した月の料金は入っていません。再検索で「退会後の請求」が追加され、回答は「日割りにならない。解約した月は満額」になりました。Naive RAG は「分からない」と答えています。入力トークンは 287 から 367 に増えています。



