LocalLens
アーキテクチャ

RAG と LLM

2 つの仕事、2 つのモデル — retrieval がエビデンスを見つけ、LLM が回答を書く。

RAG の 2 文字は、2 つの異なる仕事を指しています。Retrieval がエビデンスを見つけ、Generation が回答を書きます。 LocalLens ではこの 2 つの仕事を、別々のモデル、別々のモジュールに 意図的に分けています。

役割モデル何をするか
Retrieval (RAG)GTE_LARGE_FP16ドキュメントと質問を embed。最も近い top-K の chunks を返す。
Generation (LLM)QWEN3_1_7B_INST_Q4 (フォールバック QWEN3_600M_INST_Q4)質問 + retrieve した chunks を読み、引用付きで回答を書く。

RAG 側は機械的です。workspace に対するベクトル類似度のみで、 言語的な理解はありません。LLM 側は、推論文章生成 が起きる 場所です。retrieve された chunks はエビデンス。回答は、LLM が そのエビデンスを材料にして作るものです。

Retrieval がエビデンスを見つける

Retrieval は QVAC の RAG レイヤーの仕事で、embedding モデルが 担います。

  • ragChunk は文書を、オーバーラップ付きのトークン窓に分割します。
  • ragIngest はそれらの chunks を workspace に書き込みつつ、 GTE_LARGE_FP16 で 1 つずつ埋め込みます。
  • ragSearch は同じモデルで質問を embed し、最も近い top-K の chunks を返します。

Retrieval は回答ではありません。質問とのセマンティック類似度で ランク付けされた、回答を含む かもしれない excerpts のリストです。 何もマッチしなかった検索結果でも、それ自体が有用な信号です。LLM が それを根拠に「わかりません」と素直に言えるからです。自信たっぷりに 何かをでっち上げる必要はありません。

embedding モデルはチャット履歴を読まず、テキストを生成せず、 最終回答も見ません。出力はベクトルだけです。

Generation が回答を書く

Generation は チャット LLM の仕事です。LocalLens では既定で QWEN3_1_7B_INST_Q4、1.7B のロードに失敗した場合のフォールバックは QWEN3_600M_INST_Q4 です。

  • completion() はプロンプトビルダーが作った ChatMessage[] を受け取り、contentDelta トークンとして文字列を streaming で 返します。
  • system プロンプトが、retrieve した excerpts のみから答え、 ブラケットで引用するようにモデルを縛ります。
  • モデルはディスクに触れず、何も embed しません。読むのは context window — system のルール、番号付き excerpts、質問 — だけです。

実際に 回答 が生まれるのはこのステップです。これ以前はすべて 「エビデンス」と「パッケージ化されたプロンプト」を作っていただけ。 ここをスキップすれば、それは検索エンジンであってチャットではあり ません。

この分離が、プロンプトビルダーを小さく、QVAC gateway をきれいに 保つ理由です。プロンプトビルダーは embeddings も generation も 知りません。gateway は両方のモデルを抱えていますが、searchanswer という独立した 2 つのメソッドで公開しています。

2 つの間にある継ぎ目

buildGroundedHistory(question, hits) が継ぎ目です。質問と hits の リストを受け取り、次のようなプロンプトを作ります。

  • excerpts に番号がついていて ([1][2] …) LLM が引用できる ようになっている;
  • system ルールは明示的かつ短い;
  • ユーザーターンはちょうど 1 つ。会話履歴は再生されません。 すべての質問は新しい retrieval のラウンドとして扱われます。

検索が有効な結果を返さなかった場合、プロンプトはそのまま LLM に 渡りますが、excerpts の代わりに "No matching chunks were found." という文字列が入ります。 system プロンプトの第 1 ルールが効いて、LLM はそれを率直に 伝えます。

Only use facts that appear in the excerpts. If the answer is not in them, say so plainly.

これがハルシネーション対策のすべてです。モデル 2 つ、ルール 1 つ。 それで機能します。

なぜチャット履歴を持たないのか?

LocalLens は、すべての質問を独立した retrieval ラウンドとして扱い ます。retrieval は毎回新規、LLM のコンテキストも毎回新規、それゆえ follow-up が以前のターンの半端な情報を継承することはありません。 複数ターンの対話を実装したい場合は、buildGroundedHistory内部 ではなく に追加してください。

On this page