NVIDIA NeMo RetrieverのアジェンティックRAGがViDoRe v3で首位
NVIDIA NeMo Retrieverチームが、LLMエージェントと検索器を組み合わせたアジェンティック検索パイプラインを発表した。「アジェンティック」とは、LLMが自律的に判断・行動を繰り返すアプローチのことで、検索においては「一度のクエリで終わらず、結果を見て次のクエリを考える」動きを指す。ViDoRe v3(視覚的文書検索ベンチマーク)でNDCG@10: 69.22を達成して1位、BRIGHT(推論ベース検索ベンチマーク)でNDCG@10: 50.90の2位となり、同一パイプラインで複数ドメインにわたる汎用性を示した。
なぜセマンティック類似性では不十分か
従来の密な検索(Dense Retrieval)はセマンティック類似性、つまりテキストの「意味の近さ」をベクトル間の距離で測る手法でドキュメントをランク付けする。キーワードが一致しなくても意味が近ければヒットするため、単純なキーワード照合よりずっと賢い。ただし限界もある。複数ホップの推論(例: 「Aの著者が所属する大学の設立年は?」のように、複数の情報を連鎖的にたどる必要があるクエリ)や、意図が曖昧なクエリでは精度が落ちやすい。検索方式の違いは記事後半の検索方式の比較で整理した。
一方、LLMは推論が得意だが数百万件のドキュメントを一度に処理できない。
アジェンティック検索はこの両者の弱点を補うアーキテクチャだ。検索器が大規模ドキュメントを高速にさばき、LLMが推論しながら検索クエリを改善し続ける。
ReACTループによるパイプライン
パイプラインの中心はReACT(Reasoning + Acting)ループだ。LLMエージェントが検索器をツールとして使いながら、反復的にクエリを磨いていく。
flowchart TD
A[クエリ入力] --> B[LLMが計画立案<br/>think]
B --> C[検索実行<br/>retrieve: query, top_k]
C --> D{情報は十分か?}
D -- 不十分 --> E[クエリを改善<br/>言い換え・分解・絞り込み]
E --> C
D -- 十分 --> F[最終回答を生成<br/>final_results]
B2[ステップ上限・コンテキスト長超過] --> G[RRFでフォールバック<br/>軌跡全体でランク付け]
G --> F
エージェントが行う動作を整理するとこうなる。
| 動作 | 内容 |
|---|---|
| クエリの動的調整 | 新しく見つかった情報をもとに次のクエリを修正 |
| 継続的な言い換え | 有用な情報が見つかるまでクエリを変形し続ける |
| 複雑さの分解 | マルチパートクエリを複数のシンプルなクエリに分解 |
ループが上限に達した場合はRRF(Reciprocal Rank Fusion: 複数の検索結果リストを順位の逆数で統合するアルゴリズム)でフォールバックする。エージェントの軌跡全体でドキュメントをランク付けするため、上限超過後も精度が急落しない。
スレッドセーフシングルトン設計
当初はMCP Server(Model Context Protocol: LLMにツールやデータソースを接続するための標準プロトコル)として実装していたが、複数の問題が生じた。サーバー起動・停止のオーバーヘッド、ネットワーク往復のレイテンシ、GPU/メモリ管理の複雑さ、同時実行処理のボトルネック。これらが積み重なって実験スループットを下げていた。
改善策はプロセス内スレッドセーフシングルトン構造だ。モデルとコーパス埋め込みを起動時に一度だけロードし、再入可能ロック(RLock)で全アクセスを保護することで複数スレッドからの同時アクセスを可能にした。
# 概念的なシングルトン構造
class RetrieverSingleton:
_instance = None
_lock = threading.RLock() # 再入可能ロック
@classmethod
def get_instance(cls):
with cls._lock:
if cls._instance is None:
cls._instance = cls._create() # 一度だけ初期化
return cls._instance
ネットワークオーバーヘッドがなくなり、GPU VRAMを共有利用できるため、実験スループットが大幅に改善した。
ベンチマーク結果
ViDoRe v3
ViDoRe v3は視覚的なドキュメント(画像・チャート・表を含むPDF等)を対象とした検索精度ベンチマーク。
| パイプライン | NDCG@10 |
|---|---|
| NeMo Agentic(Opus 4.5 + colembed-vl-8b-v2) | 69.22 (#1) |
| Dense Retrieval(colembed-vl-8b-v2) | 64.36 |
| INF-X-Retriever(nemotron特化チューニング) | 62.31 |
BRIGHT
BRIGHTは推論が必要な複雑なクエリを対象としたベンチマーク。
| パイプライン | NDCG@10 |
|---|---|
| INF-X-Retriever | 63.40 (#1) |
| NeMo Agentic(Opus 4.5 + reasoning-3b) | 50.90 (#2) |
| Dense Retrieval(reasoning-3b) | 38.28 |
INF-X-RetrieverはViDoRe v3に特化チューニングしているためBRIGHTでの精度が大きく下がる。NeMo Agenticは両ベンチマークで安定した成績を出しており、ドメイン特化最適化なしの汎化能力が強みだ。
詳細アブレーション(ViDoRe v3)
| エージェント | 埋め込みモデル | NDCG@10 | 平均時間 | 検索呼び出し数 |
|---|---|---|---|---|
| Opus 4.5 | colembed-vl-8b-v2 | 69.22 | 136.3秒 | 9.2回 |
| gpt-oss-120b | colembed-vl-8b-v2 | 66.38 | 78.6秒 | 2.4回 |
| gpt-oss-120b | llama-nemotron-embed-vl-1b-v2 | 62.42 | 78.1秒 | 2.5回 |
| なし(Dense) | colembed-vl-8b-v2 | 64.36 | 0.67秒 | — |
Opus 4.5が最高精度を出しているが1クエリあたり136.3秒かかる。Denseの0.67秒と比べると203倍遅い。
BRIGHTではOpus 4.5 vs gpt-oss-120bの精度差が9.52ポイント(ViDoRe v3では2.84ポイント)と拡大する。深い推論が必要なタスクほど高性能エージェントの価値が大きい。
コストとトレードオフ
ViDoRe v3でのOpus 4.5利用時、入力760Kトークン、出力6.3Kトークン/クエリ。Opus 4.5の料金(75 per M tokens)で計算すると、1クエリあたり約$11.90になる。
密な検索がほぼゼロコストで動くのと対照的だ。アジェンティック検索は精度が最優先の場面(法的文書の検索、医療記録の照合など)でコストに見合うが、大量処理には向かない。
チームはこのトレードオフを認識しており、フロンティアモデルから蒸留した軽量エージェントへの移行を次のステップとして挙げている。
実装はGitHubのNeMo Retriever Libraryで公開されている。
検索方式の比較
この記事で「従来の検索」「密な検索」「アジェンティック検索」と複数の検索方式が登場した。それぞれの違いを整理する。
キーワード検索(疎な検索)
最も古典的な方式。文書中に検索語が含まれるかどうかで判定する。代表的な実装はTF-IDF(単語の出現頻度と希少性でスコアリング)やBM25(TF-IDFの改良版で、文書長の正規化を加えたもの)。Elasticsearchの全文検索エンジンがこの方式を採用している。
仕組みは転置インデックス(単語→出現文書のマッピング)で、「この単語を含む文書はどれか」を高速に引ける。
高速で正確なキーワードマッチができ、「エラーコード E-4021」のような固有の文字列検索に強い。一方で言い換えや同義語には弱く、「犬の飼い方」で検索しても「ペットの育て方」はヒットしない。
ベクトル検索(密な検索 / Dense Retrieval)
テキストを数百〜数千次元のベクトル(埋め込み表現)に変換し、ベクトル間の距離で類似度を測る方式。埋め込みモデル(Embedding Model)がテキストの「意味」を数値ベクトルに圧縮するため、表記が違っても意味が近ければヒットする。
「犬の飼い方」 → [0.23, -0.81, 0.45, ...] ─┐
├─ コサイン類似度: 0.91(近い)
「ペットの育て方」 → [0.21, -0.78, 0.42, ...] ─┘
「自動車の修理」 → [-0.65, 0.33, -0.12, ...] → コサイン類似度: 0.12(遠い)
代表的な実装はpgvectorやHNSW(近似最近傍探索アルゴリズム)、Pinecone、Weaviateなどの専用ベクトルDB。
同義語や言い換えに強く、「意味的に近い」文書を見つけられる。ただし「類似度が高い ≠ 質問の答えがある」という根本的な問題がある。PageIndexの記事でも触れたが、質問と文書が意味的に似ていても、実際に答えを含んでいるとは限らない。複数の情報を組み合わせる推論が必要なクエリにも対応できない。
ハイブリッド検索
キーワード検索とベクトル検索を組み合わせる方式。両方の結果をRRFなどでマージしてランク付けする。現在のRAGシステムではこれが主流。
アジェンティック検索(本記事の手法)
ハイブリッド検索をさらに拡張し、LLMエージェントが検索プロセス全体を制御する方式。人間がGoogle検索するときと似ている。最初のクエリで見つからなければ言い換え、部分的な情報が見つかればそれをもとに次のクエリを組み立てる。この試行錯誤をLLMが自動化する。
| 方式 | 同義語対応 | 推論 | 反復改善 | 速度 | コスト |
|---|---|---|---|---|---|
| キーワード検索 | x | x | x | 最速 | ほぼゼロ |
| ベクトル検索 | o | x | x | 速い | 低い |
| ハイブリッド検索 | o | x | x | 速い | 低い |
| アジェンティック検索 | o | o | o | 遅い | 高い |
同じクエリで結果がどう変わるか
「NVIDIAのGPUアーキテクチャの変遷で、CUDAコア数が最も増加した世代間の違いを説明して」というクエリを各方式で処理した場合の違いを見てみる。
| 方式 | 挙動 |
|---|---|
| キーワード検索 | 「NVIDIA」「GPU」「CUDAコア」を含む文書を返す。ヒットはするが、「最も増加した世代間」という比較・推論は処理できない。関係ありそうな文書が大量に返ってくるだけ |
| ベクトル検索 | GPUアーキテクチャに意味的に近い文書を返す。「CUDAコア」と書いていなくても「並列演算ユニット」のような文書もヒットする。ただし比較推論はできず、個々のアーキテクチャの文書がバラバラに返ってくる |
| ハイブリッド検索 | キーワードとベクトルの結果をマージ。カバー範囲は広がるが、推論できない点は同じ |
| アジェンティック検索 | LLMが「まずGPUの世代一覧を検索」→「各世代のCUDAコア数を検索」→「増加率を計算」→「最大の増加が起きた世代を特定」と段階的にクエリを分解・実行する |
本記事のベンチマーク結果が示す通り、アジェンティック検索は精度が高い反面、1クエリに136秒・$11.90というコストがかかる。すべての検索をアジェンティックにする必要はなく、簡単なクエリはキーワード検索やベクトル検索で処理し、複雑なクエリだけアジェンティック検索にルーティングする、という使い分けが現実的だ。
検索系の過去記事: 検索データ構造総まとめ / PageIndex: ベクトル検索なしのツリーRAG / AliSQL: MySQLにベクトルサーチ統合