実験日: 2026-08-24
環境: RTX 5070 Ti 16GB / WSL2 / Ollama 0.32.15 / EmbeddingGemma / Qwen 3 8B
RAGを作るとき、「TF-IDFは古い、embeddingなら意味で検索できる」と考えがちです。では、日本語と英数字が混ざった実験記事から正確な測定値を探す場合、本当にembeddingが勝つでしょうか。
embeddingの方が新しい手法でも、この検索条件でTF-IDFより強いとは限りません。
前回と同じ13記事、198 heading chunk、20問を固定し、character 2~4 gram TF-IDFと768次元のEmbeddingGemmaを比較しました。結果はTF-IDFがsource hit@3で20/20、embeddingは19/20。RAG回答はTF-IDF 19/20、embedding 16/20でした。
EmbeddingGemmaが弱いmodelという意味ではありません。今回のqueryはbatch 8192や11,244 tokensのようなexact identifier・数値検索が多く、lexical matchが強いtaskです。「意味が近いchunk」と「答えの数値が書かれたchunk」は同じとは限りません。
今回はTF-IDFが勝った
| metric | TF-IDF | EmbeddingGemma |
|---|---|---|
| 期待source hit@1 | 17/20 | 17/20 |
| 期待source hit@3 | 20/20 | 19/20 |
| source-level MRR | 0.925 | 0.9125 |
| 平均query時間 | 1.03 ms | 496.2 ms |
| index作成 | 0.189秒 | 12.45秒 |
| 同じQwen 3 8BのRAG正解 | 19/20 | 16/20 |

この結果からの実務的な判断です。
- model名、数値、error code、parameter名が重要ならlexical baselineを必ず測る
- 自然な言い換えや概念検索はembeddingが有利な可能性がある
- どちらか一方と決めず、scoreを融合するhybrid検索を候補にする
- source fileが当たっただけで成功とせず、answerを支持するchunkを確認する
- embedding APIの計算costをlatency budgetへ含める
前回と同じ評価集合を使う
比較で最も大切なのは、retriever以外の条件を変えないことです。
documents 13
heading chunks 198
questions 20
top-k 3
generator Qwen 3 8B Q4
temperature 0
seed 42
質問は、このPCで測った未知の数値です。
12BモデルのGPU peak使用量は何GiBだった?
Digitsの小型NNではCPUとCUDAのどちらが何倍速かった?
augmentationありDataLoaderで0 workerのthroughputはいくつ?
TF-IDF用とembedding用でquestionやchunk sizeを変えると、公平な比較になりません。今回は前回のPython moduleからARTICLE_NAMES、QUESTIONS、chunking関数、採点関数をimportしました。
embeddingは文章をvectorへ変える
embedding modelは、文章を固定長の実数vectorへ写像します。今回、Ollamaへ次のrequestを送りました。
{
"model": "embeddinggemma",
"input": ["検索対象の文章"],
"truncate": true
}
/api/embedのresponseを実測すると、1入力につき768個のfloatが返りました。
embedding shape = (number of chunks, 768)
corpus 198 chunkを16件ずつ13 batchで変換しました。downloadしたmodel payloadは621 MBです。ここでの621 MBはpull時の表示であり、runtime VRAMやparameter数ではありません。
cosine similarityを計算する
document vectorとquery vectorをL2 normalizeします。
arr /= np.maximum(
np.linalg.norm(arr, axis=1, keepdims=True),
1e-12,
)
単位vector同士なら、dot productがcosine similarityです。
scores = document_embeddings @ query_embedding
top_idx = np.argsort(scores)[::-1][:3]
cosine similarityはvectorの向きを比べ、長さの影響を除きます。値が大きいほどembedding空間で近いと見なします。ただし「近い」が何を意味するかはmodelのtraining objectiveに依存します。
TF-IDFは文字列の一致を数える
baselineは日本語tokenizerなしのcharacter n-gramです。
TfidfVectorizer(
analyzer="char_wb",
ngram_range=(2, 4),
sublinear_tf=True,
)
例えばqueryにCUDA peak allocatedがあれば、その連続文字を含むchunkが強くなります。意味の言い換えには弱い反面、model名、version、数値、関数名をそのまま探すtaskでは強力です。
実装と計算の性質も違います。
| 方式 | 表現 | index |
|---|---|---|
| TF-IDF | 語彙数次元のsparse vector | corpus統計から計算 |
| embedding | 768次元dense vector | neural modelで推論 |
198 chunk程度なら両方ともmemory上に置けます。大規模化するとTF-IDFはinverted index、embeddingはapproximate nearest neighbor indexが一般的です。
retrieval結果はほぼ同点、TF-IDFがわずかに上
期待source fileが最初に現れる順位を測りました。
hit@1 hit@3 MRR
TF-IDF 17/20 20/20 0.9250
EmbeddingGemma 17/20 19/20 0.9125
MRRはMean Reciprocal Rankです。正解sourceがrank 1なら1、rank 2なら1/2、rank 4なら1/4を与え、20問で平均します。上位へ来るほど高くなります。
差は20問で1件なので、一般的な優劣を断定する規模ではありません。しかし「embeddingへ変えれば自動的に改善する」という仮説は、このtaskでは支持されませんでした。
embeddingが改善した質問
次の質問ではTF-IDFの期待sourceがrank 2、embeddingはrank 1でした。
12BモデルのGPU peak使用量は何GiBだった?
TF-IDF top 1はQ4/Q8のquantization記事でした。GPU、peak、GiBが強く一致したためです。EmbeddingGemmaは4B・8B・12B比較記事を1位へ上げました。
RAG回答も正解です。
12BモデルのGPU peak使用量は約9.7GiBだった。
[article_ollama_4b_8b_12b.md#4]
語の重なりだけでなく「12B modelのresource measurement」という意味を捉えた可能性があります。ただし1例から内部表現を断定はできません。
embeddingが落とした質問
次の質問では、TF-IDFの期待sourceはrank 1、embeddingはrank 4でした。
Digitsの小型NNではCPUとCUDAのどちらが何倍速かった?
embedding top 3にはFashionMNIST CNNのCPU/GPU比較とNumPy NN記事が入り、期待したPyTorch Digits記事は外れました。意味的にはどれも「small neural network、CPU/GPU、speed comparison」に近い文書です。
幸いFashionMNIST記事の比較tableにDigitsの4.38倍が再掲されていたため、answer自体は正解しました。
CPUはCUDAに対して約4.38倍速かった。
[article_fashion_cnn_cpu_gpu.md#7]
expected source citationは不合格ですが、別sourceが同じ測定値を支持しています。これはevaluation設計上の重要点です。正解sourceを1ファイルに限定すると、重複した正しい根拠を誤って罰する場合があります。
source hitでもevidence chunkを外す
Embedding RAGが不正解だった4問のうち、代表例です。
質問:
code生成で4Bの修正後合格数はいくつ?
retrieval:
article_llm_codegen_pytest.md#2
article_llm_codegen_pytest.md#8
article_llm_codegen_pytest.md#12
回答:
資料内に記載なし
source fileはrank 1です。しかし7/10がある#1を選べませんでした。source-level hit@1は成功でも、evidence retrievalは失敗です。
DataLoader質問も同様でした。
augmentationありDataLoaderで0 workerのthroughputはいくつ?
期待sourceはrank 2に入りましたが、上位chunkには8,830 images/sがありません。LLMは資料内に記載なしを返しました。
RAGをdebugするときはdocument filenameだけでなく、top-kの本文を保存しなければ原因を特定できません。
回答正解は19/20対16/20
retrievalした上位3 chunkを同じQwen 3 8Bへ渡しました。
TF-IDF RAG 19 / 20
Embedding RAG 16 / 20
source hit@3の差は1問ですが、answer正解は3問差です。source fileの中でどのheadingを取ったかが効いたためです。
Embedding RAGの期待source引用は18/20、平均generation時間は0.640秒でした。前回TF-IDF RAGは0.376秒でしたが、promptに入ったchunkの文字量が同じとは限らないため、generator speedの厳密な比較にはしません。
query latencyは1.0 ms対496 ms
このPCでの平均値です。
TF-IDF transform + sparse score 1.03 ms
Ollama EmbeddingGemma API 496.2 ms
embeddingは約480倍ですが、実装経路が公平ではありません。TF-IDFは同じPython process内、embeddingはHTTPでOllamaへrequestし、neural modelを実行しています。cold/warm状態、batching、GPU schedulingも含みます。
したがって「embeddingは常に480倍遅い」と一般化できません。ここから言えるのは、この単発query API構成では約0.5秒をlatency budgetへ追加した、ということです。
index作成もTF-IDF 0.189秒、embedding 12.45秒でした。corpus embeddingは文書更新時に一度計算してcacheできます。query embeddingはrequestごとに必要です。
hybrid検索で両方式を補完する
exact tokenに強いTF-IDFと言い換えに強いembeddingは補完関係にあります。
単純なrank fusionなら、score scaleを直接混ぜず順位を使えます。
RRF(d) = Σ 1 / (k + rank_retriever(d))
Reciprocal Rank Fusionは、各retrieverで上位のdocumentへ加点します。kは上位1件が過度に強くなるのを和らげるconstantです。
実験順序としては次が堅実です。
TF-IDF baseline
↓
embedding単体
↓
hybrid / RRF
↓
reranker
↓
answer + citation評価
いきなり複雑な構成へ進むと、どの追加が改善したか分かりません。
この比較の限界
20問は小さく、exact numeric lookupに偏っています。自然なparaphrase question、長文要約、概念横断検索では結果が変わる可能性があります。
また、EmbeddingGemmaのprompt prefix、chunk長、title付与、query expansionを調整していません。defaultのOllama modelをそのまま使うbaselineです。model固有の推奨形式を適用すると改善する余地があります。
評価はsource-file levelです。同じfactが複数記事へ再掲された場合、期待source以外でも正しい根拠になりえます。より厳密に評価するなら、answer span単位のground truthが必要です。
再現手順
ollama pull embeddinggemma
cd /mnt/c/Users/user/Documents/Codex/2026-08-24/ko/work/ai_lab
/opt/ai-lab/venv/bin/python -u experiment_embedding_search.py
/opt/ai-lab/venv/bin/python plot_embedding_search.py
artifactです。
work/ai_lab/experiment_embedding_search.py
work/ai_lab/results/embedding_search.json
work/ai_lab/plot_embedding_search.py
work/figures/tfidf-vs-embeddinggemma.png
JSONには両retrieverのrankとtop 3 ID、embedding側のchunk全文とscore、query time、Qwen回答、正誤、citationを保存しました。
検索方式の判断基準
retrieverを選ぶ前に、質問の性質を見ます。
| 質問の性質 | 最初に試すもの |
|---|---|
| 型番、数値、error code、固有名詞 | TF-IDF / BM25 |
| 言い換え、概念、自然文の意味 | embedding |
| 両方が混在 | hybrid |
| 候補は取れるが順序が悪い | reranker |
このPCのexact measurement検索では、621 MBのembedding modelを追加してもTF-IDFを超えませんでした。これは失敗ではなく、baselineを置いたから得られた判断です。
「新しい手法だから採用」ではなく、固定question set、retrieval metric、downstream answer accuracy、latencyで選ぶ。それが研究としてもsystem開発としても、再現可能なRAG改善になります。
