Embedding APIの選択
概要
Embedding(埋め込み)は、テキストを数値ベクトルに変換する技術です。セマンティック検索やレコメンデーション、類似度計算などで使用されます。
Embedding APIには大きく分けて2つの選択肢があります:
| 選択肢 | 概要 |
|---|---|
| マネージドサービス | OpenAI、Cohere、Google等のAPIを利用 |
| セルフホスト | オープンソースモデルを自分のサーバーで実行 |
マネージドサービス
OpenAI Embeddings
最も広く使われているEmbedding API。高品質で多言語対応。
const response = await fetch('https://api.openai.com/v1/embeddings', {
method: 'POST',
headers: {
'Authorization': `Bearer ${OPENAI_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'text-embedding-3-small',
input: 'Dockerはコンテナ仮想化のプラットフォームです',
}),
})
const data = await response.json()
const embedding = data.data[0].embedding // 1536次元のベクトル
利用可能なモデル:
| モデル | 次元数 | 価格(1Mトークン) | 特徴 |
|---|---|---|---|
| text-embedding-3-small | 1536 | $0.02 | コスパ最良、十分な品質 |
| text-embedding-3-large | 3072 | $0.13 | 最高品質 |
| text-embedding-ada-002 | 1536 | $0.10 | 旧モデル(互換性維持用) |
推奨: 多くのユースケースでは text-embedding-3-small で十分。
Cohere Embed
多言語対応に優れたEmbedding API。
const response = await fetch('https://api.cohere.ai/v1/embed', {
method: 'POST',
headers: {
'Authorization': `Bearer ${COHERE_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'embed-multilingual-v3.0',
texts: ['Dockerはコンテナ仮想化のプラットフォームです'],
input_type: 'search_document', // または 'search_query'
}),
})
利用可能なモデル:
| モデル | 次元数 | 価格(1Mトークン) | 特徴 |
|---|---|---|---|
| embed-multilingual-v3.0 | 1024 | $0.10 | 100+言語対応 |
| embed-english-v3.0 | 1024 | $0.10 | 英語特化 |
Voyage AI
検索用途に特化したEmbedding API。
| モデル | 次元数 | 特徴 |
|---|---|---|
| voyage-large-2 | 1536 | 高品質、検索向け |
| voyage-code-2 | 1536 | コード検索向け |
| voyage-multilingual-2 | 1024 | 多言語対応 |
Google Vertex AI
Google CloudのEmbedding API。
| モデル | 次元数 | 特徴 |
|---|---|---|
| text-embedding-005 | 768 | 多言語対応 |
| text-multilingual-embedding-002 | 768 | 多言語特化 |
マネージドサービスの比較
| 観点 | OpenAI | Cohere | Voyage AI | |
|---|---|---|---|---|
| 品質 | ◎ | ○ | ◎ | ○ |
| 日本語 | ○ | ◎ | ○ | ○ |
| 価格 | ◎ | ○ | ○ | ○ |
| 導入の容易さ | ◎ | ○ | ○ | △ |
| ドキュメント | ◎ | ○ | ○ | ○ |
推奨: 日本語コンテンツには OpenAI text-embedding-3-small がコストパフォーマンス良好。
セルフホスト
自分のサーバーでEmbeddingモデルを実行する選択肢。
セルフホストの利点と欠点
利点:
- APIコストが不要(大量処理時に有利)
- データが外部に送信されない(プライバシー)
- オフライン環境でも動作
- レイテンシの制御が可能
欠点:
- サーバーの運用コスト
- GPUが必要な場合がある
- モデル更新の管理が必要
- 品質がマネージドに劣る場合がある
Sentence Transformers(Python)
最も広く使われているオープンソースのEmbeddingライブラリ。
from sentence_transformers import SentenceTransformer
# 多言語対応モデル(推奨)
model = SentenceTransformer('intfloat/multilingual-e5-large')
# 埋め込みを生成
texts = [
'Dockerはコンテナ仮想化のプラットフォームです',
'Kubernetesはコンテナオーケストレーションツールです',
]
embeddings = model.encode(texts)
print(embeddings.shape) # (2, 1024)
推奨モデル:
| モデル | 次元数 | サイズ | 特徴 |
|---|---|---|---|
| intfloat/multilingual-e5-large | 1024 | 2.2GB | 多言語、高品質 |
| intfloat/multilingual-e5-base | 768 | 1.1GB | 多言語、バランス |
| intfloat/multilingual-e5-small | 384 | 470MB | 多言語、軽量 |
| sentence-transformers/all-MiniLM-L6-v2 | 384 | 90MB | 英語、超軽量 |
Ollama
ローカルLLM実行環境。Embeddingにも対応。
# モデルをダウンロード
ollama pull nomic-embed-text
# REST APIで埋め込みを生成
curl http://localhost:11434/api/embeddings -d '{
"model": "nomic-embed-text",
"prompt": "Dockerはコンテナ仮想化のプラットフォームです"
}'
利用可能なEmbeddingモデル:
| モデル | 次元数 | 特徴 |
|---|---|---|
| nomic-embed-text | 768 | 軽量、汎用 |
| mxbai-embed-large | 1024 | 高品質 |
| all-minilm | 384 | 超軽量 |
Hugging Face TEI(Text Embeddings Inference)
本番環境向けの高性能Embeddingサーバー。
# Dockerで起動
docker run --gpus all -p 8080:80 \
ghcr.io/huggingface/text-embeddings-inference:latest \
--model-id intfloat/multilingual-e5-large
# REST APIで埋め込みを生成
curl http://localhost:8080/embed \
-X POST \
-H 'Content-Type: application/json' \
-d '{"inputs": "Dockerはコンテナ仮想化のプラットフォームです"}'
特徴:
- 高スループット
- バッチ処理対応
- GPU最適化
- OpenAI互換API
FastEmbed
ONNX Runtimeを使用した軽量・高速なEmbeddingライブラリ。
from fastembed import TextEmbedding
# モデルを初期化(自動ダウンロード)
model = TextEmbedding('BAAI/bge-small-en-v1.5')
# 埋め込みを生成
documents = ['Dockerはコンテナ仮想化のプラットフォームです']
embeddings = list(model.embed(documents))
特徴:
- CPUでも高速
- 軽量(依存関係が少ない)
- PyTorchなしで動作
マネージド vs セルフホストの判断基準
マネージドサービスが適しているケース
| 条件 | 理由 |
|---|---|
| 記事数が少ない(〜数千件) | APIコストが無視できるレベル |
| 開発速度を優先 | インフラ構築が不要 |
| 品質を最優先 | 最新の高品質モデルを使用可能 |
| 運用リソースが限られている | サーバー管理が不要 |
セルフホストが適しているケース
| 条件 | 理由 |
|---|---|
| 大量のデータ(数百万件以上) | APIコストが膨大になる |
| プライバシー要件が厳しい | データを外部に送信できない |
| オフライン環境 | インターネット接続がない |
| 低レイテンシが必須 | ネットワーク遅延を排除 |
コスト比較(目安)
前提: 1記事 ≈ 1,000トークン
| データ量 | OpenAI API | セルフホスト(GPU) |
|---|---|---|
| 100記事 | $0.002 | オーバーキル |
| 1,000記事 | $0.02 | オーバーキル |
| 10,000記事 | $0.20 | オーバーキル |
| 100,000記事 | $2.00 | 検討の余地あり |
| 1,000,000記事 | $20.00 | セルフホスト有利 |
検索クエリのコスト(月間):
| 検索回数/月 | OpenAI API |
|---|---|
| 1,000回 | 約$0.001 |
| 10,000回 | 約$0.01 |
| 100,000回 | 約$0.10 |
| 1,000,000回 | 約$1.00 |
→ 中小規模のサイトでは、ほぼ無料に近いコストで運用可能
実装のヒント
1. 埋め込みのキャッシュ
同じテキストに対して何度もEmbeddingを生成しないよう、ハッシュベースでキャッシュ:
import crypto from 'crypto'
function hashText(text: string): string {
return crypto.createHash('sha256').update(text).digest('hex')
}
async function getEmbedding(text: string) {
const hash = hashText(text)
// キャッシュをチェック
const cached = await cache.get(hash)
if (cached) return cached
// APIを呼び出し
const embedding = await generateEmbedding(text)
// キャッシュに保存
await cache.set(hash, embedding)
return embedding
}
2. バッチ処理
複数のテキストをまとめて処理することでAPI呼び出し回数を削減:
// OpenAI APIはバッチ処理に対応
const response = await fetch('https://api.openai.com/v1/embeddings', {
method: 'POST',
headers: {
'Authorization': `Bearer ${OPENAI_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'text-embedding-3-small',
input: [
'テキスト1',
'テキスト2',
'テキスト3',
// ... 最大2048個まで
],
}),
})
3. テキストの前処理
埋め込みの品質を向上させるための前処理:
function preprocessText(text: string): string {
return text
// HTMLタグを除去
.replace(/<[^>]*>/g, '')
// 連続する空白を1つに
.replace(/\s+/g, ' ')
// トークン数を制限(OpenAIは8191トークンまで)
.slice(0, 8000)
.trim()
}
4. 検索クエリと文書の区別
一部のモデル(Cohere、E5など)は検索クエリと文書で異なる処理を推奨:
# E5モデルの場合
# 検索クエリには "query: " プレフィックス
query_text = "query: Dockerの使い方"
# 文書には "passage: " プレフィックス
document_text = "passage: Dockerはコンテナ仮想化のプラットフォームです..."
関連トピック
- pgvector - PostgreSQLのベクトル検索拡張
- Supabase + pgvector - SupabaseでのセマンティックS検索
- セマンティック検索の実装パターン - 実装パターン詳細
- 検索技術の基礎 - ベクトル検索の基本概念