RAG実装における次元の設定方法 | 768d vs 1536d vs 3072d一覧に戻るRAG実装における次元の設定方法 | 768d vs 1536d vs 3072d
RAG(Retrieval-Augmented Generation)システムを構築する際、Embeddingの次元数は、検索精度、ストレージコスト、検索速度に直接影響する重要なパラメータです。本記事では、768次元、1536次元、3072次元の実装上の違いと、ビジネス要件に応じた最適な選択方法を解説します。
Embedding次元数の基礎知識
次元数とは
Embeddingの次元数は、テキストを表現するベクトルの要素数です。次元数が高いほど、より細かな意味的ニュアンスを表現できる一方、ストレージや計算コストが増加します。
例えば、768次元のベクトルは以下のような形式になります:
python
[0.023, -0.156, 0.891, ..., 0.234] # 768個の浮動小数点数
主要なEmbeddingモデルと次元数
| モデル | 次元数 | 用途 |
|---|
| all-MiniLM-L6-v2 | 384 | 軽量・高速 |
| nomic-embed-text | 768 | バランス型 |
| text-embedding-3-small | 1536 (可変) | OpenAI標準 |
| text-embedding-3-large | 3072 (可変) | 最高精度 |
| mxbai-embed-large | 1024 |
ご紹介
弊社では下記プロダクトを取り扱いしております。ご興味ありましたらご覧ください。
OpenAIのtext-embedding-3-small/largeは、dimensionsパラメータで次元数を動的に調整可能な点が特徴です。
次元数による違いの詳細比較
1. ストレージコスト
次元数はベクトルDBのストレージサイズに直接影響します。
1万チャンクを格納した場合の容量(pgvectorの場合):
# 計算式: チャンク数 × 次元数 × 4バイト(float32)
768次元: 10,000 × 768 × 4 = 30.72 MB
1536次元: 10,000 × 1,536 × 4 = 61.44 MB
3072次元: 10,000 × 3,072 × 4 = 122.88 MB
- 768次元: 約3 GB
- 1536次元: 約6 GB
- 3072次元: 約12 GB
これに加えて、インデックス(HNSW、IVFFlat等)の容量も必要です。一般的にインデックスはベクトルデータの20-40%程度を追加で消費します。
2. 検索速度
次元数が増えると、類似度計算(コサイン類似度、内積等)のコストが線形に増加します。
実測パフォーマンス(10万ベクトルから類似トップ10を検索):
| 次元数 | 平均検索時間 | インデックス作成時間 |
|---|
| 768d | 12ms | 45秒 |
| 1536d | 23ms | 92秒 |
| 3072d | 48ms | 185秒 |
※環境: PostgreSQL 15 + pgvector、HNSW index (m=16, ef_construction=64)
検索速度は次元数にほぼ比例しますが、インデックスの最適化により影響を軽減できます。
3. メモリ使用量
ベクトル検索時、候補ベクトルをメモリに展開するため、次元数が高いとメモリ消費が増加します。
- 768次元: 約300 MB
- 1536次元: 約600 MB
- 3072次元: 約1.2 GB
大規模システムでは、この違いがサーバースペック選定に影響します。
4. 検索精度
次元数と精度の関係は線形ではありません。多くの場合、1536次元で十分な精度が得られ、3072次元への増加は限定的な改善にとどまります。
MTEB(Massive Text Embedding Benchmark)スコア例:
- text-embedding-3-small (512d): 61.2
- text-embedding-3-small (1536d): 62.3
- text-embedding-3-large (1024d): 62.8
- text-embedding-3-large (3072d): 64.6
512次元→1536次元で約1.1ポイント、1536次元→3072次元で約2.3ポイントの改善です。
OpenAI Embeddingsでの次元削減実装
OpenAIのtext-embedding-3-small/largeでは、dimensionsパラメータで次元数を指定できます。
基本的な実装
from openai import OpenAI
client = OpenAI()
# 1536次元(デフォルト)
response = client.embeddings.create(
model="text-embedding-3-small",
input="RAGシステムの実装方法"
)
# 768次元に削減
response = client.embeddings.create(
model="text-embedding-3-small",
input="RAGシステムの実装方法",
dimensions=768
)
# 3072次元(text-embedding-3-large)
response = client.embeddings.create(
model="text-embedding-3-large",
input="RAGシステムの実装方法",
dimensions=3072
)
バッチ処理での実装
# 複数チャンクを効率的に処理
chunks = ["チャンク1", "チャンク2", ..., "チャンク100"]
response = client.embeddings.create(
model="text-embedding-3-small",
input=chunks,
dimensions=768 # コスト削減のため768次元を指定
)
embeddings = [data.embedding for data in response.data]
次元削減のメカニズム
OpenAIのモデルは、高次元ベクトルから重要な次元を選択するのではなく、Matryoshka Representation Learningという手法を使用しています。これにより、削減後も情報の損失を最小化できます。
- 後から次元を増やすことはできない
- 異なる次元数のベクトルは比較できない
- 一度決めた次元数は、そのコレクション全体で統一する必要がある
コスト・パフォーマンス分析
OpenAI APIのコスト比較
text-embedding-3-smallは次元数に関わらず同一料金($0.02/1M tokens)ですが、ストレージコストと検索速度が変わります。
10万チャンクのRAGシステム(月間100万クエリ想定):
| 次元数 | Embedding費用 | ストレージ費用/月 | 検索コスト/月 | 合計/月 |
|---|
| 512d | $20 | $5 | $30 | $55 |
| 768d | $20 | $8 | $40 | $68 |
| 1536d | $20 | $15 | $80 | $115 |
※ストレージ: AWS RDS PostgreSQL、検索: Lambda実行コスト概算
Ollamaのリソースコスト
ローカルLLMの場合、次元数による処理時間の違いがサーバーコストに影響します。
100万チャンク処理時間(M1 Max、GPU使用):
- 768d (nomic-embed-text): 約14時間
- 1024d (mxbai-embed-large): 約18時間
- 1536d (カスタムモデル): 約25時間
GPU時間単価を考慮すると、初期Embedding生成で次元数が大きな影響を与えます。
ベクトルDB別の実装例
pgvectorでの実装
import psycopg2
from pgvector.psycopg2 import register_vector
conn = psycopg2.connect(database="vectordb")
register_vector(conn)
# テーブル作成(次元数を指定)
cur = conn.cursor()
cur.execute("""
CREATE TABLE embeddings_768 (
id SERIAL PRIMARY KEY,
content TEXT,
embedding vector(768), -- 次元数を明示
metadata JSONB
)
""")
# HNSWインデックス作成
cur.execute("""
CREATE INDEX ON embeddings_768
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64)
""")
# データ挿入
cur.execute(
"INSERT INTO embeddings_768 (content, embedding) VALUES (%s, %s)",
("テキスト", embedding_768d)
)
# 検索
cur.execute("""
SELECT content, 1 - (embedding <=> %s) as similarity
FROM embeddings_768
ORDER BY embedding <=> %s
LIMIT 10
""", (query_embedding, query_embedding))
ChromaDBでの実装
import chromadb
client = chromadb.Client()
# コレクション作成(次元数は自動検出)
collection = client.create_collection(
name="docs_768d",
metadata={"dimension": 768} # 管理用
)
# データ追加
collection.add(
embeddings=embeddings_768d, # [[...], [...], ...]
documents=documents,
metadatas=metadatas,
ids=ids
)
# 検索
results = collection.query(
query_embeddings=[query_embedding_768d],
n_results=10
)
Pineconeでの実装
import pinecone
pinecone.init(api_key="YOUR_API_KEY")
# インデックス作成(次元数を指定)
pinecone.create_index(
name="rag-768d",
dimension=768, # 必須パラメータ
metric="cosine"
)
index = pinecone.Index("rag-768d")
# Upsert
index.upsert(
vectors=[
("id1", embedding_768d, {"text": "内容"}),
("id2", embedding_768d, {"text": "内容"})
]
)
# 検索
results = index.query(
vector=query_embedding_768d,
top_k=10,
include_metadata=True
)
選択基準とユースケース別推奨
768次元を選ぶべきケース
- 大規模データ(100万チャンク以上)を扱う
- 検索速度を最優先(リアルタイム応答)
- ストレージコストを抑えたい
- モバイル・エッジデバイスでの動作
- ECサイトの商品検索(数百万商品)
- リアルタイムチャットボット
- 組み込みデバイスでのローカルRAG
# OpenAI API使用時
response = client.embeddings.create(
model="text-embedding-3-small",
input=texts,
dimensions=768 # 明示的に指定
)
# Ollama使用時
ollama.embeddings(
model='nomic-embed-text', # 768次元モデル
prompt=text
)
1536次元を選ぶべきケース
- 中規模データ(10万〜100万チャンク)
- 精度とコストのバランス重視
- 一般的なビジネスアプリケーション
- 社内ナレッジベース検索
- カスタマーサポートFAQ
- 技術ドキュメント検索
デフォルト推奨:
OpenAIのtext-embedding-3-smallはデフォルトで1536次元であり、多くのユースケースで最適なバランスです。
3072次元を選ぶべきケース
- 最高精度が必要(数パーセントの改善が重要)
- データ量が比較的小規模(10万チャンク未満)
- コストよりも品質を優先
- 法律文書の精密検索
- 学術論文のセマンティック検索
- 高度な推薦システム
# text-embedding-3-largeを使用
response = client.embeddings.create(
model="text-embedding-3-large", # largeモデル
input=texts,
dimensions=3072 # フル次元
)
実践的なアーキテクチャ設計
ハイブリッドアプローチ
class HybridRAGSystem:
def __init__(self):
# 第1段階: 768次元で高速フィルタリング
self.fast_index = ChromaDB(dimension=768)
# 第2段階: 1536次元で精密ランキング
self.precise_index = ChromaDB(dimension=1536)
def search(self, query, top_k=10):
# Step 1: 768次元で候補を1000件に絞る
fast_results = self.fast_index.query(
query_768d,
n_results=1000
)
# Step 2: 上位候補を1536次元で再ランキング
precise_results = self.precise_index.query(
query_1536d,
filter={"id": {"$in": fast_results.ids}},
n_results=top_k
)
return precise_results
このアプローチにより、精度を維持しながら検索速度とコストを最適化できます。
段階的な移行戦略
- プロトタイプ段階: 768次元で迅速に実装・検証
- β版リリース: 1536次元で精度向上
- スケール段階: データ増加に応じて768次元に戻す、またはハイブリッド化
# 移行スクリプト例
def migrate_dimensions(old_dim=1536, new_dim=768):
# 既存データを再Embedding
for batch in get_all_documents(batch_size=1000):
new_embeddings = client.embeddings.create(
model="text-embedding-3-small",
input=batch.texts,
dimensions=new_dim
)
# 新しいコレクションに保存
new_collection.add(
embeddings=new_embeddings,
documents=batch.texts,
metadatas=batch.metadatas
)
まとめ
RAGシステムにおける次元数の選択は、検索精度、処理速度、ストレージコストのトレードオフです。一般的な推奨は以下の通りです:
- デフォルト選択: 1536次元(OpenAI text-embedding-3-small)
- 大規模・高速重視: 768次元
- 最高精度重視: 3072次元(OpenAI text-embedding-3-large)
重要なのは、プロジェクト初期から過度に最適化せず、実際のデータとクエリで検証しながら調整することです。A/Bテストにより、自社のユースケースで次元数の違いが実際にどの程度の影響を与えるかを測定し、データに基づいた意思決定を行いましょう。
次元数は一度決めると変更が困難なため、将来のスケールを見据えた設計が重要です。不確実性が高い場合は、768次元または1536次元から始め、段階的に最適化する柔軟なアプローチを推奨します。