Embeddingとは — 意味を座標に変換する
Embedding(埋め込み)とは、テキスト・画像・音声などの離散的な対象を、 数百〜数千次元の連続ベクトル空間に写像する操作です。 RAGで中心的に扱うのはテキスト埋め込みで、文や段落を1本の固定長ベクトルに変換します。
埋め込みモデルは「意味的に近いものはベクトル空間でも近くに配置される」ように学習されます。 たとえば「犬」「わんこ」「ワンちゃん」は、表記が違っても似たベクトルになります。 一方「犬」と「銀行」は遠く離れたベクトルになります。この距離を類似度として使うのが、ベクトル検索の根本原理です。
Dense vs Sparse — 密ベクトルと疎ベクトルの違い
埋め込みには大きく2種類あります。RAGを正しく設計するには、この違いを理解することが決定的に重要です。
| Dense(密ベクトル) | Sparse(疎ベクトル) | |
|---|---|---|
| 次元数 | 数百〜数千(固定) | 数万〜語彙サイズ(可変) |
| 値の分布 | ほぼ全次元が非ゼロ | 大部分がゼロ、一部だけ値を持つ |
| 生成元 | ニューラルネット(BERT, E5等) | BM25, TF-IDF, SPLADE |
| 強み | 意味的類似、言い換え、多言語 | キーワード一致、固有名詞、型番 |
| 弱み | ドメイン外劣化、固有名詞弱い | 同義語に弱い |
| 例 | 「犬」「わんこ」が近い | 「GPT-4o」の完全一致に強い |
現代のRAGは両者を組み合わせるハイブリッド検索が標準です(第7章で詳説)。 Denseだけだと「GPT-4o」のような固有名詞が「AI全般」に引き寄せられ、Sparseだけだと「バグを直す」と「欠陥を修正する」が別物になります。 両方の弱点を相互に補う構成が、実務での精度を大きく引き上げます。
類似度指標 — コサイン vs 内積 vs L2
2つのベクトルがどれくらい「近い」かを測る指標は複数あり、用途と埋め込みモデルに応じた選択が必要です。
| 指標 | 計算式 | 特徴 | 使いどころ |
|---|---|---|---|
| コサイン類似度 | cos(θ) = A·B / (|A|·|B|) | 方向のみを見る。ベクトル長の影響なし | テキスト埋め込みの事実上の標準 |
| ドット積(内積) | A·B = Σ aᵢbᵢ | 方向と大きさの両方。正規化済みならコサインと等価で最速 | 正規化前提の商用モデル(OpenAI等) |
| L2距離(ユークリッド) | √Σ(aᵢ-bᵢ)² | 絶対位置関係を見る | 画像埋め込みなど、大きさに意味があるケース |
graph LR
subgraph A[2次元の例]
direction TB
V1[ベクトルA]
V2[ベクトルB]
V3[ベクトルC]
end
A -.ほぼ同じ方向.-> B[高いコサイン類似度]
A -.近い距離.-> C[低いL2距離]
style B fill:#14b8a6,stroke:#0d9488,color:#fff
style C fill:#8b5cf6,stroke:#6d28d9,color:#fff次元の呪い — 高次元空間の直感に反する性質
埋め込みベクトルは数百〜数千次元という高次元空間に存在します。 この高次元性は、低次元の直感が通用しない奇妙な振る舞いを引き起こします。
- 次元が増えると、ランダムな2点間の距離が「ほぼ同じ」になり、距離のコントラストが失われる
- 空間の体積の大部分が「表面近く」に集中する(球体の体積が表面付近に偏る)
- ユークリッド距離が意味を失いやすく、コサイン類似度が好まれる理由の一つ
対策として、むやみに次元数を増やさないこと、そしてMatryoshka Representation Learningのように次元を切り詰めても性能が保たれるモデルを使うことが有効です。
OpenAIの text-embedding-3 シリーズは、3072次元を256次元に切り詰めてもコサ性能が保たれるMatryoshka対応です。
検索の評価指標 — Recall@k・nDCG・MRR
「良い埋め込み」とは、クエリに対して関連文書を高い順位で返せる埋め込みです。これを測る指標が複数あります。
| 指標 | 定義 | 特徴 |
|---|---|---|
| Recall@k | 正解のうち上位k件に含まれた割合 | RAGで最重要。正解漏れを測る |
| Precision@k | 上位k件のうち正解の割合 | ノイズ率を測る |
| MRR | 最初の正解の順位の逆数の平均 | 1つの正解を早く出せるか |
| nDCG@k | 順位に応じた割引利得の正規化スコア | 順位と関連度を同時評価 |
| Hit Rate@k | 1件でも正解が入っていれば1 | シンプル版Recall |
MTEB / JMTEB — 埋め込みモデルの標準ベンチマーク
どの埋め込みモデルが良いかを比較する共通ベンチマークがMTEB(Massive Text Embedding Benchmark)です。 Hugging Faceが運営し、100以上のデータセットで検索・分類・クラスタリング・STSなど8タスクを評価します。 MTEB Leaderboard でリアルタイムに最新スコアを確認できます。
日本語版としてJMTEBがあり、SB Intuitionsが整備しています。 28データセット × 5タスク(Classification/Clustering/STS/Retrieval/Reranking)で日本語埋め込みを評価でき、 日本語RAGを作るなら必ず参照すべきベンチマークです。
日本語RAGの2026年推奨モデル
日本語埋め込みモデルは2025〜2026年にかけて劇的に進化しました。 特に注目すべきは、Ruri-v3(cl-nagoya、ModernBERTベース)とSarashina-Embedding-v2(SB Intuitions、LLMベース)です。
| モデル | JMTEB平均 | 次元 | 特徴 | ライセンス |
|---|---|---|---|---|
| Ruri-v3-310m | 77.2 | 768 | ModernBERT、SentencePiece単独(MeCab不要)、8K対応 | Apache 2.0 |
| Sarashina-Embedding-v2-1B | 最上位級 | 非公開 | LLMベース、Instruction-tuned、8K対応 | Non-Commercial(商用不可) |
| Ruri-v3-30m | 高(37Mで3-large超え) | 非公開 | CPU実行可、8bit量子化で37MB | Apache 2.0 |
| BGE-M3 | 中〜高 | 1024 | Dense+Sparse+Multi-vector、100+言語、8K対応 | MIT |
| multilingual-e5-large | 中 | 1024 | 多言語の安定択、query:/passage:プレフィックス必須 | MIT |
| GLuCoSE-base-ja-v2 | 中 | 768 | PKSHA、512トークン、軽量 | Apache 2.0 |
| Gemini Embedding 001 | 68.32(英) | 可変 | Google、マルチモーダル対応 | 商用API |
| OpenAI text-embedding-3-large | 64.6 | 3072(可変) | Matryoshka、多言語◎ | 商用API |
実装例 — OpenAIとRuri-v3で埋め込みを生成する
実際の埋め込み生成は驚くほど簡単です。以下はVercel AI SDK(TypeScript)とsentence-transformers(Python)の例です。
// Vercel AI SDK + OpenAI
import { openai } from '@ai-sdk/openai';
import { embed, embedMany } from 'ai';
// 単一テキストを埋め込み
const { embedding } = await embed({
model: openai.embedding('text-embedding-3-small'),
value: '返品ポリシーについて教えてください',
});
// embedding は number[1536]
// 複数を一括(バッチでレート制限回避)
const { embeddings } = await embedMany({
model: openai.embedding('text-embedding-3-small'),
values: chunks.map(c => c.content),
}); # Ruri-v3をローカルで使う(日本語RAG向け)
from sentence_transformers import SentenceTransformer
model = SentenceTransformer('cl-nagoya/ruri-v3-310m')
# Ruri-v3は "検索クエリ: " / "検索文書: " プレフィックス推奨
queries = ['検索クエリ: 返品ポリシーは?']
docs = ['検索文書: 商品到着後30日以内なら返品可能です。']
query_emb = model.encode(queries, normalize_embeddings=True)
doc_emb = model.encode(docs, normalize_embeddings=True)
# コサイン類似度(正規化済みなので内積と等価)
similarity = (query_emb @ doc_emb.T).item() 次章では、埋め込みベクトルから高速に「近いK件」を取り出すANNアルゴリズムの内部構造を深掘りします。 HNSWがなぜ速いのか、パラメータ(M、ef_construction、ef_search)をどう設定すべきか、図解で理解していきましょう。
理解度チェック
Dense embedding(密ベクトル)とSparse embedding(疎ベクトル)の違いとして正しい記述はどれですか?
キーボード: 1〜4 で選択、Enter で回答