ローカルRAGツールをNemotron + vLLM + Tool Callingで構築した話
はじめに
単一GPUで完結するローカルファーストのRAGリサーチツールを構築しました。Tool calling + RAGの組み合わせにはかなり試行錯誤が必要でしたので、そのアプローチを共有します。
技術スタック
- Nemotron Nano 9B v2 Japanese on vLLM(FP16, RTX 5090)
- FastAPI + SQLite FTS5 + Jinja2 — バックエンド全体が1つのapp.pyで完結
- NVIDIAの公式パーサープラグインによるTool CallingとReasoning
設計上の重要な判断
Extract → Execute 2段階フロー
質問を投げると、システムはまずLLMを使ってバイリンガルキーワード(EN+JA)を抽出し、ローカルソースに対するFTS5検索とDuckDuckGoウェブ検索を並列実行します。そして見つかったソースをチェックボックス付きで表示。関連するものを選んでExecuteを押すと、そこで初めて生成が始まります。
これにより、100k+トークンのコンテキストを丸ごと投入して「モデルが何とかしてくれ」という方式を回避しています。
Tool Calling
Nemotron v2はTool Callingに対応していますが、カスタムパーサープラグインが必要です(vLLMの組み込みパーサーはv3用であり、v2には使えません)。--tool-call-parser nemotron_json と --tool-parser-plugin を指定すると、モデルがウェブ検索のタイミングを自律的に判断します。temp 0.1で驚くほどうまく動きます。
Prefix Cache ウォームアップ
ソース読み込み時にまとめてキャッシュするのではなく、ユーザーがソースプレビュー(ステップ3)を見ているタイミングでKVキャッシュをウォームアップします。Executeをクリックする頃にはprefixキャッシュが完了済み。vLLMの --enable-prefix-caching を使用。
バイリンガルFTS5検索
ユーザーのクエリ → Nemotronが英語と日本語の両方でキーワード抽出 → OR結合のFTS5 MATCHクエリ。シンプルですが、多言語の特許・研究データに対して効果的です。
パフォーマンス
- 出力速度:約80-120 tok/s
- 最大トークン:8192
- ソース抽出:約3-5秒(キーワード抽出 + FTS5 + DDG並列)
- 5ソース + 3ウェブ結果での完全回答:詳細な回答で約50秒
- RTX 5090使用
ソースコード
GitHub: https://github.com/soy-tuber/SoyLM
1ファイルアプリ。uv pip install -r requirements.txt で即起動。vLLMとNemotronパーサープラグインは別途必要。
投稿元
Reddit r/LocalLLaMA: https://www.reddit.com/r/LocalLLaMA/comments/1s0lsi8/