0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Jevで複数の文書をたどって回答する!Multi-hop RAGを実装してみた

0
Posted at

はじめに

前回は、Jevを使った「DecisionRAG」について学び、文書の階層構造をたどりながら、必要な情報を段階的に取得する仕組みを実装しました。

今回は、複数の文書から情報を取得し、それらを組み合わせて回答する Multi-hop RAG(マルチホップRAG) について学んでいこうと思います。

Multi-hop RAGでは、検索で得られた情報をもとに、次に必要な情報を判断して検索します。今回は、この判断にJevを使い、複数の検索結果を組み合わせて正しく回答できるかをNaive RAGと比較していきます。

今回がRAG学習シリーズの最後となります。

これまでの記事・実装

Multi-hop RAGとは?

Multi-hop RAGとは、複数の文書から情報を段階的に取得し、得られた情報を組み合わせて回答するRAGの構成です。

Naive RAGでは、質問をもとに1回検索し、取得した上位文書をLLMに渡して回答を生成します。一方、Multi-hop RAGでは、検索結果を確認し、必要な情報が不足していれば次の検索を行います。

比較 Naive RAG Multi-hop RAG
文書の検索 基本1回 必要に応じて複数回
検索文 最初の質問 取得済みの情報と不足項目を反映
情報の収集 上位文書を取得 段階的に必要な情報を収集
Jevの役割 なし 次に必要な情報を判断
特徴 シンプルで高速 複数の情報を組み合わせられる

Multi-hop RAGの特徴は、単に検索回数を増やすのではなく、前の検索結果を踏まえて次の検索を決めることです。

この考え方に関連する研究として、2023年に発表されたIRCoT(Interleaving Retrieval with Chain-of-Thought Reasoning)があります。検索と段階的な推論を交互に行い、複数の情報を必要とする質問に対応する手法です。

今回はこの考え方を参考に、Jevで回答に不足している情報を判断し、段階的に文書を収集する簡易版Multi-hop RAGを実装します。

Multi-hop-rag.png

※ 図はプラン・請求・データ削除の順に情報を取得するイメージです。実際の検証では、最初に請求の文書が取得され、データ削除、プランの順に検索が進みました。

Adaptive RAGとの違い

Step3のAdaptive RAGでも複数回検索を実装しましたが、着目する部分が異なります。

比較 Adaptive RAG Multi-hop RAG
主な役割 検索戦略を選択する 複数の情報を段階的に取得する
Jevの判断 検索なし・1回・複数回 次に何を調べるべきか
重視すること 質問に合った処理の選択 検索結果を使った次の情報収集

Adaptive RAGは検索方法の選択に、Multi-hop RAGは段階的な情報収集に重点を置いています。両者は組み合わせることもできます。

なお、今回の実装は不足している規定を順番に収集する構成です。前の検索で特定した具体的な値を次の検索条件として必須にする、より依存関係の強いMulti-hop検索とは区別します。

処理の流れ

今回は、検索した文書をJevで評価し、不足している情報があれば検索文を作り直します。

処理の内容は以下のとおりです。

処理 役割
初回検索 質問に関連する文書を取得
Jevによる判断 回答に不足している情報を選択
追加検索 不足情報を検索して文書を蓄積
Generation 収集した文書をもとに回答を生成

今回の実装では、Jevは次に必要な情報を判断し、検索文の生成はLLMが担当します。

検索は初回を含め最大3回とし、必要な根拠が揃わなければ、確認できない情報を断定しないようにします。

成果物

今回も、架空のSaaS「TaskFlow」の問い合わせ回答システムを使用します。

Naive RAGとMulti-hop RAGを比較し、段階的な検索によって必要な文書を揃えられるかを検証します。

質問 検証する内容
SSOが使えるプランを月の途中で退会した場合、当月の請求額とデータ削除までの日数は? 複数の規定を取得して回答できるか
退会後、データはいつ削除されますか? 不要な追加検索を行わないか

① 複数の文書が必要な場合

SSOが使えるプランを月の途中で退会した場合、当月の請求額とデータ削除までの日数は?

正解を得るには、次の情報が必要です。

必要な情報 マニュアルの節 内容
SSO対応プラン Proプラン SSOに対応
月額料金 Proプラン 12,000円(税別)
退会月の請求 退会後の請求 満額請求・日割りなし
データ削除 退会後のデータ削除 退会完了から30日後

正解は、**「SSOが使えるのはProプランで、当月の請求額は12,000円(税別)。月途中の退会でも日割りにはならず、データは退会完了から30日後に削除される」**です。

Naive RAGでも1回の検索で必要な文書が揃えば正しく回答できます。今回は、実際の検索結果を比較して違いを確認します。

② 単純な質問の場合

退会後、データはいつ削除されますか?

正解は「退会完了から30日後」です。

この質問では、1回の検索で必要な文書を取得できるため、Multi-hop RAGが不要な追加検索を行わずに回答できるかを確認します。

検索の評価方法

同じ質問・マニュアル・回答生成モデルを使い、Naive RAGとMulti-hop RAGを比較します。

比較項目 Naive RAG Multi-hop RAG
検索方法 Embedding Embedding+段階的な再検索
検索回数 1回 最大3回
1回の検索候補 上位3件 上位3件
Jevによる判断 なし 不足情報を判断
回答モデル GPT-4.1-mini GPT-4.1-mini

確認するのは、必要な文書の取得状況、Jevの判断、検索文の変化、最終回答、処理時間とトークン数です。

なお、Multi-hop RAGでは検索回数だけでなく、Jevによる判断や検索文生成のコストも発生します。回答生成LLMへの入力トークン数と、システム全体のAPIコストは区別して評価します。

実装内容

今回はJevのchoiceを使い、取得済みの文書から次に不足している情報を1つ選択します。

送り先はPOST https://api.typesafe.ai/v1/systemone、モデルはjev-latestです。stateには元の質問と、それまでに収集した文書を渡します。

選択肢は質問ごとに変更します。1問目では次の4つを使用します。

選択肢 意味
plan SSO対応プランや月額料金が未確認
billing 退会月の請求ルールが未確認
deletion データ削除までの期間が未確認
done 必要な根拠がすべて揃っている

done以外が選ばれると、LLMが不足している項目について検索文を1つ生成し、再検索します。

各回の上位3件は重複を除いて蓄積します。検索は最大3回で、最後の判定でもdoneにならなければ「一部の情報をマニュアルから確認できません。」と回答します。

① Jevで最初に不足している情報を判断する

1問目の初回検索では、次の3件が取得されました。

  • 退会後の請求
  • 日割り請求のルール
  • プラン変更時の日割り

これらをJevに渡して、次に必要な情報を判断させます。

{
  "state": "質問: SSOが使えるプランを月の途中で退会した場合、当月の請求額とデータ削除までの日数は?\n\n取得済み文書:\n# 退会\n## 退会後\n### 退会後の請求\n\n退会手続きが完了した月の料金は満額請求されます。月の途中で解約しても日割りにはなりません。退会の翌月以降、月額料金は請求されません。年払いの未経過分は返金しません。\n\n# 請求\n## 日割り\n### 日割り請求のルール\n\n日割り請求は、月の途中で契約内容が変わった場合に使います。日割り額は、月額料金を30で割った1日あたりの金額に、残日数をかけて計算します。\n\n# 請求\n## 日割り\n### プラン変更時の日割り\n\n月の途中でプランを変更した場合、差額は日割りで請求します。Standardプランから上位プランへ変更したときも、変更日以降の料金は日割りになります。",
  "questions": {
    "next": {
      "type": "choice",
      "instructions": "質問への回答に必要な根拠を確認し、次に調べるべき情報を1つ選んでください。推測で情報が揃ったと判断せず、すべての項目を文書で確認できた場合だけdoneを選んでください。",
      "criteria": {
        "plan": "SSOに対応するプランや月額料金の根拠が不足している",
        "billing": "月途中で退会した場合の請求ルールが未確認",
        "deletion": "退会完了からデータ削除までの期間が未確認",
        "done": "プラン、料金、退会時の請求、データ削除の根拠がすべて揃っている"
      }
    }
  },
  "model": "jev-latest"
}

Jevから返ってきたレスポンスです。

{
  "model": "jev-1.14.0",
  "answers": {
    "next": {
      "type": "choice",
      "choice": "deletion",
      "confidence": 0.83,
      "probabilities": {
        "plan": 0.12,
        "billing": 0.01,
        "deletion": 0.87,
        "done": 0
      }
    }
  },
  "usage": {
    "input_tokens": 844,
    "output_tokens": 47
  }
}

choiceはdeletionでした。

「退会後の請求」により満額請求は確認できていますが、SSO対応プランとデータ削除日数はまだ不明です。今回は、そのうちデータ削除が選択されました。

比較実行でもdeletionが選択され、確率は0.87でした。

この判定を受けて、LLMが次の検索文を生成しました。

退会完了からデータ削除までの日数は何日ですか?

② 追加検索後、Jevの判断が変化する

2回目の検索では、「退会後のデータ削除」が取得されました。

これまでに集めた文書を再びJevへ渡すと、今度はplanが選択されました。

比較実行の確率は以下のとおりです。

選択肢 確率
plan 0.91
billing 0.04
deletion 0.01
done 0.04

請求とデータ削除の情報が揃ったため、残る不足情報はSSO対応プランと料金です。

次の検索文は以下になりました。

SSOが使えるプラン名を教えてください。

この時点ではプラン名がまだ分からないため、検索文にも「Proプラン」は含まれません。

3回目の検索結果は以下のとおりです。

文書 類似度
ログイン 0.5630
Proプラン 0.4536
Freeプラン 0.4104

「Proプラン」を取得したことで、SSO対応プランと月額料金を確認できました。

その後、Jevはdoneを選択しました。比較実行におけるdoneの確率は0.99でした。

検索結果が増えることでJevの判断が変わり、次に探す情報も切り替わることを確認できました。

③ 単純な質問では追加検索しない

2問目では、次の質問を使用します。

退会後、データはいつ削除されますか?

この質問では、確認すべき情報がデータ削除日数だけなので、選択肢はdeletionとdoneの2つです。

初回検索では「退会後のデータ削除」「退会後の請求」「支払い失敗」が取得されました。

{
  "state": "質問: 退会後、データはいつ削除されますか?\n\n取得済み文書:\n# 退会\n## 退会後\n### 退会後のデータ削除\n\n退会が完了してから 30 日後に、ワークスペースのタスク、添付ファイル、メンバー一覧は完全に削除されます。30 日以内であれば、同じ管理者アカウントからワークスペースを再開できます。30 日を過ぎると再開はできません。\n\n# 退会\n## 退会後\n### 退会後の請求\n\n退会手続きが完了した月の料金は満額請求されます。月の途中で解約しても日割りにはなりません。退会の翌月以降、月額料金は請求されません。年払いの未経過分は返金しません。\n\n# 請求\n## 支払い\n### 支払い失敗\n\n支払いが失敗すると、7 日後と 14 日後に再試行します。14 日を過ぎても支払われない場合、ワークスペースは読み取り専用になります。データはすぐには削除されません。",
  "questions": {
    "next": {
      "type": "choice",
      "instructions": "質問への回答に必要な根拠を確認し、次に調べるべき情報を1つ選んでください。推測で情報が揃ったと判断せず、すべての項目を文書で確認できた場合だけdoneを選んでください。",
      "criteria": {
        "deletion": "退会完了からデータ削除までの期間が未確認",
        "done": "データ削除までの期間の根拠が文書で確認できている"
      }
    }
  },
  "model": "jev-latest"
}

返ってきたレスポンスです。

{
  "model": "jev-1.14.0",
  "answers": {
    "next": {
      "type": "choice",
      "choice": "done",
      "confidence": 0.98,
      "probabilities": {
        "deletion": 0.01,
        "done": 0.99
      }
    }
  },
  "usage": {
    "input_tokens": 797,
    "output_tokens": 32
  }
}

choiceはdoneでした。

必要な「退会後のデータ削除」が最初の検索結果に含まれていたため、追加検索せずに回答生成へ進みます。

比較実行でもdoneが選択され、確率は0.99でした。

実行結果

比較はnpm run multihopで実行します。

Naive RAGでは、類似度上位3件を1回検索して回答します。Multi-hop RAGでは、各検索の上位3件を重複なく蓄積し、Jevが必要な情報が揃ったと判断するまで検索します。

① SSOが使えるプランを月の途中で退会した場合、当月の請求額とデータ削除までの日数は?

Multi-hop RAGの実行結果(複数の規定)

Naive RAGの結果

検索上位3件は以下のとおりです。

文書 類似度
退会後の請求 0.5867
日割り請求のルール 0.5391
プラン変更時の日割り 0.5348

検索は1338 ms、回答生成LLMへの入力トークンは340、回答生成は1209 msでした。

回答は「退会した月は満額で、日割りにならない」という内容でした。

ただし、SSOが使えるプランとデータ削除までの日数は、確認できないという回答でした。

Multi-hop RAGの結果

1回目の検索結果はNaive RAGと同じ3件です。

Jevの判断と追加検索の結果は、次のようになりました。

段階 Jevの判断 次の検索
1回目 deletion(0.87) データ削除までの日数
2回目 plan(0.91) SSOが使えるプラン
3回目 done(0.99) 検索終了

これにより、「退会後のデータ削除」と「Proプラン」を追加で取得できました。

最終的に蓄積した文書は8件です。

  • 退会後の請求
  • 日割り請求のルール
  • プラン変更時の日割り
  • 退会後のデータ削除
  • 支払い失敗
  • ログイン
  • Proプラン
  • Freeプラン

回答生成LLMへの入力トークンは708、回答生成は1189 msでした。

各処理の時間は以下のとおりです。

処理 実行時間
検索3回 2370 ms
Jevによる判断3回 795 ms
検索文の生成2回 2531 ms
最終回答の生成 1189 ms

最終回答は、**「SSOが使えるのはProプランで、退会した月は満額、データは退会完了から30日後に削除される」**でした。

ただし、Proプランのマニュアルには月額12,000円(税別)と記載されているにもかかわらず、回答文にはこの金額が含まれていませんでした。

比較と考察

評価項目 Naive RAG Multi-hop RAG
検索回数 1回 3回
取得した主要な根拠 退会後の請求 退会後の請求、データ削除、Proプラン
Jevの判断 なし deletion → plan → done
最終回答 満額請求。プランと削除日数は不明 Proプラン、満額請求、30日後。金額は未回答
回答生成LLM入力トークン 340 708
検索時間 1338 ms 2370 ms
Jev+検索文生成 なし 3326 ms

Multi-hop RAGでは、Naive RAGが取得できなかった文書を段階的に収集できました。

ただし、回答生成LLMへの入力トークンは340から708に増加しています。さらに、Jevによる判断や検索文生成のトークンも別途発生します。

また、最終回答には請求額の12,000円が含まれていませんでした。

これは検索不足ではなく、必要な文書が揃っていても、回答生成時に一部の情報が抜け落ちることがあるという問題です。

Jevのdoneは検索に必要な根拠が揃ったという判断であり、生成された回答の完全性まで保証するものではありません。

② 退会後、データはいつ削除されますか?

Multi-hop RAGの実行結果(データ削除)

Naive RAGの結果

検索上位3件は以下のとおりです。

文書 類似度
退会後のデータ削除 0.6478
退会後の請求 0.5101
支払い失敗 0.4841

検索は799 ms、回答生成LLMへの入力トークンは343、回答生成は1106 msでした。

回答は「退会完了から30日後に削除される」でした。

Multi-hop RAGの結果

最初の検索で、Naive RAGと同じ3件を取得しました。

Jevはdone(確率0.99)を選択し、追加検索は行われませんでした。

検索は679 ms、Jevの判断は210 ms、回答生成LLMへの入力トークンは343、回答生成は915 msでした。

回答はNaive RAGと同じく「退会完了から30日後に削除される」でした。

比較と考察

評価項目 Naive RAG Multi-hop RAG
検索回数 1回 1回
Jevの判断 なし done(0.99)
最終回答 30日後に削除 30日後に削除
回答生成LLM入力トークン 343 343
検索時間 799 ms 679 ms
Jevの判断 なし 210 ms

必要な文書が最初の検索に含まれている場合は、Jevがdoneを選択して追加検索を終了できました。

一方で、追加検索をしなくてもJevの判断処理は発生します。この1回の計測では、検索は679 ms、Jevは210 ms、回答生成は915 msでした。1回だけでは、どちらが速いかは判断できません。

単純な質問では、追加検索を避けることに加えて、そもそもJevによる判断を実行する必要があるかも検討する余地があります。

まとめ

今回は、Jevのchoiceを使って次に必要な情報を判断し、検索結果を蓄積しながら回答するMulti-hop RAGを実装しました。

Naive RAGとの比較結果は以下のとおりです。

質問 Naive RAG Multi-hop RAG
複数の規定が必要 請求ルールのみ回答 プラン・請求・データ削除まで回答。ただし金額は欠落
単純な質問 正しく回答 追加検索せず正しく回答

1問目では、Jevがdeletion → plan → doneと判断し、検索文を変えることで「退会後のデータ削除」と「Proプラン」を取得できました。

1回の検索では見つからなかった情報を、段階的に収集できたことが今回の成果です。

ただし、Jevがdoneと判断したあとでも、最終回答から月額12,000円が抜け落ちていました。

ここから、必要な文書を取得できたことと、質問のすべての項目に回答できたことは別の問題だと分かります。

改善策としては、取得した文書から回答に必要な項目を構造化して保持する方法や、Step5で実装したSelf-RAGのような回答検証を組み合わせる方法が考えられます。

また、複数回検索すると関係の薄い文書も蓄積され、今回のように入力トークンが増加します。Step2のFiltering RAGなどを組み合わせ、必要な根拠だけを回答生成に渡す工夫も有効そうです。

2問目では、Jevが最初の検索でdoneを選択し、不要な追加検索を避けられました。一方、Jevへの問い合わせ分の処理時間は発生しています。

今回の学習を通じて、Multi-hop RAGでは**「次に何を探すか」だけでなく、「いつ検索を終えるか」「集めた情報をどう回答に反映するか」も重要**だと感じました。

これで、Naive RAGから始めたRAG学習シリーズは一区切りです。これまで学んだ各手法は独立して使うだけでなく、組み合わせることで、より複雑な質問にも対応できると考えています。

参考資料

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?