cloudflare-vectorize について
Cloudflare Vectorizeでベクトルを管理し、Workersアプリケーションにセマンティック検索やRAGを実装するためのガイドです。メタデータフィルター、ベクトル取り込み、埋め込み、テスト設定を扱います。
主な機能
- 01ベクトルインデックスの作成と管理
- 02ベクトルの登録、検索、削除
- 03メタデータによる検索結果の絞り込み
- 04セマンティック検索とRAGの構築
- 05文書の分割と一括取り込み
活用シーン
- 01Workersアプリケーションにセマンティック検索を追加
- 02検索拡張型の質問応答を構築
- 03文書を分割してベクトルを一括取り込み
- 04カテゴリや状態で検索結果を絞り込み
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jezweb/ claude-skills --skill cloudflare-vectorizeインストール後、Claude Code で/cloudflare-vectorizeを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
README.md.claude-plugin/plugin.jsonreferences/embedding-models.mdindex-operations.mdintegration-openai-embeddings.mdintegration-workers-ai-bge-base.mdmetadata-guide.mdvector-operations.mdwrangler-commands.mdrules/cloudflare-vectorize.mdtemplates/basic-search.tsdocument-ingestion.tsmetadata-filtering.tsrag-chat.ts詳細
Cloudflare Vectorize
Cloudflare Workers を使用して、セマンティック検索、RAG(検索拡張生成)、AI 搭載アプリケーションを構築するための、グローバルに分散されたベクトルデータベース、Cloudflare Vectorize の完全な実装ガイドです。
ステータス: 本番環境対応 ✅ 最終更新日: 2026-01-21 依存関係: cloudflare-worker-base(Worker のセットアップ用)、cloudflare-workers-ai(埋め込み用) 最新バージョン: [email protected]、@cloudflare/[email protected] トークン削減率: 約70% 防止できるエラー: 14 節約できる開発時間: 約4時間
このスキルでできること
主な機能
- ✅ インデックス管理:ベクトルインデックスの作成、設定、管理
- ✅ ベクトル操作:ベクトルの挿入、アップサート、クエリ、削除、一覧表示(list-vectors は2025年8月に追加)
- ✅ メタデータフィルタリング:インデックスごとに10個のメタデータインデックスを使用した高度なフィルタリング
- ✅ セマンティック検索:コサイン、ユークリッド、または内積の指標を使用した類似ベクトルの検索
- ✅ RAG パターン:検索拡張生成ワークフロー一式
- ✅ Workers AI との統合:@cf/baai/bge-base-en-v1.5 によるネイティブな埋め込み生成
- ✅ OpenAI との統合:text-embedding-3-small/large モデルに対応
- ✅ ドキュメント処理:テキストのチャンク分割とバッチ取り込みパイプライン
- ✅ テスト環境のセットアップ:Vectorize バインディングを使用した Vitest 設定
含まれるテンプレート
- basic-search.ts - Workers AI を使用したシンプルなベクトル検索
- rag-chat.ts - コンテキスト検索機能を備えた完全な RAG チャットボット
- document-ingestion.ts - ドキュメントのチャンク分割と埋め込みパイプライン
- metadata-filtering.ts - 高度なフィルタリングパターン
⚠️ Vectorize V2 の破壊的変更(2024年9月)
重要: Vectorize V2 は2024年9月に一般提供が開始され、大幅な破壊的変更が導入されました。
V2 での変更点
パフォーマンスの改善:
- インデックス容量:インデックスごとに200,000 → 500万ベクトル
- クエリレイテンシ:中央値549ms → 31ms(18倍高速)
- TopK の上限:クエリあたりの結果数が20 → 100
- スケール上限:アカウントごとのインデックス数が100 → 50,000
- 名前空間の上限:インデックスごとの名前空間数が100 → 50,000
API の破壊的変更:
-
非同期ミューテーション - すべてのミューテーションが非同期になりました:
// V2: Returns mutationId const result = await env.VECTORIZE_INDEX.insert(vectors); console.log(result.mutationId); // "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" // Vector inserts/deletes may take a few seconds to be reflected -
returnMetadata パラメーター - Boolean から String 列挙型に変更:
// ❌ V1 (deprecated) { returnMetadata: true } // ✅ V2 (required) { returnMetadata: 'all' | 'indexed' | 'none' } -
挿入前にメタデータインデックスが必要:
- V2 では、ベクトルを挿入する前にメタデータインデックスを作成する必要があります
- メタデータインデックスの作成前に追加されたベクトルは、インデックス化されません
- メタデータインデックスを作成した後、ベクトルを再度アップサートする必要があります
V1 の非推奨化スケジュール:
- 2024年12月:V1 インデックスを新規作成できなくなります
- 既存の V1 インデックス:引き続き動作します(その他の操作への影響はありません)
- 移行:V1 操作には
wrangler vectorize --deprecated-v1フラグを使用してください
必要な Wrangler バージョン:
- 最小:V2 コマンドには [email protected] が必要です
- 推奨:[email protected] 以降(最新)
ミューテーションのステータスを確認する
// Get index info to check last mutation processed
const info = await env.VECTORIZE_INDEX.describe();
console.log(info.mutationId); // Last mutation ID
console.log(info.processedUpToMutation); // Last processed timestamp
重要なセットアップルール
⚠️ ベクトルを挿入する前に必ず実行してください
# 1. Create the index with FIXED dimensions and metric
npx wrangler vectorize create my-index \
--dimensions=768 \
--metric=cosine
# 2. Create metadata indexes IMMEDIATELY (before inserting vectors!)
npx wrangler vectorize create-metadata-index my-index \
--property-name=category \
--type=string
npx wrangler vectorize create-metadata-index my-index \
--property-name=timestamp \
--type=number
理由:ベクトルを挿入する前に、必ずメタデータインデックスを作成してください。メタデータインデックスの作成前に追加されたベクトルは、そのプロパティでフィルタリングできません。
インデックス設定(後から変更できません)
# Dimensions MUST match your embedding model output:
# - Workers AI @cf/baai/bge-base-en-v1.5: 768 dimensions
# - OpenAI text-embedding-3-small: 1536 dimensions
# - OpenAI text-embedding-3-large: 3072 dimensions
# Metrics determine similarity calculation:
# - cosine: Best for normalized embeddings (most common)
# - euclidean: Absolute distance between vectors
# - dot-product: For non-normalized vectors
Wrangler の設定
wrangler.jsonc:
{
"name": "my-vectorize-worker",
"main": "src/index.ts",
"compatibility_date": "2025-10-21",
"vectorize": [
{
"binding": "VECTORIZE_INDEX",
"index_name": "my-index"
}
],
"ai": {
"binding": "AI"
}
}
TypeScript の型
export interface Env {
VECTORIZE_INDEX: VectorizeIndex;
AI: Ai;
}
interface VectorizeVector {
id: string;
values: number[] | Float32Array | Float64Array;
namespace?: string;
metadata?: Record<string, string | number | boolean | string[]>;
}
interface VectorizeMatches {
matches: Array<{
id: string;
score: number;
values?: number[];
metadata?: Record<string, any>;
namespace?: string;
}>;
count: number;
}
メタデータフィルター演算子(V2)
Vectorize V2 は、範囲クエリを含む高度なメタデータフィルタリングに対応しています。
// Equality (implicit $eq)
{ category: "docs" }
// Not equals
{ status: { $ne: "archived" } }
// In/Not in arrays
{ category: { $in: ["docs", "tutorials"] } }
{ category: { $nin: ["deprecated", "draft"] } }
// Range queries (numbers) - NEW in V2
{ timestamp: { $gte: 1704067200, $lt: 1735689600 } }
// Range queries (strings) - prefix searching
{ url: { $gte: "/docs/workers", $lt: "/docs/workersz" } }
// Nested metadata with dot notation
{ "author.id": "user123" }
// Multiple conditions (implicit AND)
{ category: "docs", language: "en", "metadata.published": true }
メタデータのベストプラクティス
1. カーディナリティに関する考慮事項
カーディナリティが低い場合($eq フィルターに適しています):
// Few unique values - efficient filtering
metadata: {
category: "docs", // ~10 categories
language: "en", // ~5 languages
published: true // 2 values (boolean)
}
カーディナリティが高い場合(範囲クエリでは避けてください):
// Many unique values - avoid large range scans
metadata: {
user_id: "uuid-v4...", // Millions of unique values
timestamp_ms: 1704067200123 // Use seconds instead
}
2. メタデータの上限
- メタデータインデックスは最大10個:Vectorize インデックスごと
- メタデータは最大10 KiB:ベクトルごと
- 文字列インデックス:先頭64バイト(UTF-8)
- 数値インデックス:Float64 精度
- フィルターサイズ:最大2048バイト(コンパクトな JSON)
3. ベクトルの次元数の上限
現在の上限:ベクトルあたり1536次元 出典:GitHub Issue #8729
対応している埋め込みモデル:
- Workers AI
@cf/baai/bge-base-en-v1.5:768次元 ✅ - OpenAI
text-embedding-3-small:1536次元 ✅ - OpenAI
text-embedding-3-large:3072次元 ❌(次元数の削減が必要)
対応していないモデル(1536次元超):
nomic-embed-code:3584次元Qodo-Embed-1-7B:1536次元超
回避策: 次元削減(例:PCA)を使用して、埋め込みを1536次元以下に圧縮します。ただし、意味的な品質が低下する可能性があります。
機能リクエスト:より高い次元数への対応が検討されています。これがユースケースの妨げとなる場合は、上限引き上げリクエストフォームを使用してください。
4. 主な制限事項
// ❌ INVALID metadata keys
metadata: {
"": "value", // Empty key
"user.name": "John", // Contains dot (reserved for nesting)
"$admin": true, // Starts with $
"key\"with\"quotes": 1 // Contains quotes
}
// ✅ VALID metadata keys
metadata: {
"user_name": "John",
"isAdmin": true,
"nested": { "allowed": true } // Access as "nested.allowed" in filters
}
ベストプラクティス
バッチ挿入のパフォーマンス
重要:最適なパフォーマンスを得るには、バッチサイズを5000ベクトルにしてください。
パフォーマンスデータ:
- 個別挿入:250万ベクトルに36時間以上(未完了)
- バッチ挿入(5000):400万ベクトルに約12時間
- 適切なバッチ処理により18倍高速化
5000が最適な理由:
- Vectorizeの内部Write-Ahead Log(WAL)がこのサイズに最適化されています
- Cloudflare APIのレート制限を回避できます
- スループットとメモリ使用量のバランスが取れます
最適なパターン:
const BATCH_SIZE = 5000;
async function insertVectors(vectors: VectorizeVector[]) {
for (let i = 0; i < vectors.length; i += BATCH_SIZE) {
const batch = vectors.slice(i, i + BATCH_SIZE);
const result = await env.VECTORIZE.insert(batch);
console.log(`Inserted batch ${i / BATCH_SIZE + 1}, mutationId: ${result.mutationId}`);
// Optional: Rate limiting delay
if (i + BATCH_SIZE < vectors.length) {
await new Promise(resolve => setTimeout(resolve, 100));
}
}
}
出典:
クエリの精度モード
Vectorizeはデフォルトで近似最近傍(ANN)検索を使用し、厳密な検索と比較して約80%の精度です。
デフォルトモード:近似スコアリング(約80%の精度)
- レイテンシーが低い
- RAG、検索、レコメンデーションに適しています
- topKは最大100
高精度モード:ほぼ100%の精度
returnValues: trueで有効になります- レイテンシーが高い
- topK=20に制限されます
トレードオフの例:
// Fast, ~80% accuracy, topK up to 100
const results = await env.VECTORIZE.query(embedding, {
topK: 50,
returnValues: false // Default
});
// Slower, ~100% accuracy, topK max 20
const preciseResults = await env.VECTORIZE.query(embedding, {
topK: 10,
returnValues: true // High-precision scoring
});
高精度モードを使用する場面:
- 重要なアプリケーション(不正検出、法令遵守)
- 結果セットが小さい場合(topK < 20)
- レイテンシーより精度を優先する場合
出典:Cloudflareブログ - Vectorizeの構築
よくあるエラーと解決策
エラー1:ベクトル挿入後にメタデータインデックスを作成
Problem: Filtering doesn't work on existing vectors
Solution: Delete and re-insert vectors OR create metadata indexes BEFORE inserting
エラー2:次元数の不一致
Problem: "Vector dimensions do not match index configuration"
Solution: Ensure embedding model output matches index dimensions:
- Workers AI bge-base: 768
- OpenAI small: 1536
- OpenAI large: 3072
エラー3:無効なメタデータキー
Problem: "Invalid metadata key"
Solution: Keys cannot:
- Be empty
- Contain . (dot)
- Contain " (quote)
- Start with $ (dollar sign)
エラー4:フィルターが大きすぎる
Problem: "Filter exceeds 2048 bytes"
Solution: Simplify filter or split into multiple queries
エラー5:カーディナリティの高いデータに対する範囲クエリ
Problem: Slow queries or reduced accuracy
Solution: Use lower cardinality fields for range queries, or use seconds instead of milliseconds for timestamps
エラー6:insertとupsertの混同
Problem: Updates not reflecting in index
Solution: Use upsert() to overwrite existing vectors, not insert()
エラー7:バインディングがない
Problem: "VECTORIZE_INDEX is not defined"
Solution: Add [[vectorize]] binding to wrangler.jsonc
エラー8:名前空間とメタデータの混同
Problem: Unclear when to use namespace vs metadata filtering
Solution:
- Namespace: Partition key, applied BEFORE metadata filters
- Metadata: Flexible key-value filtering within namespace
エラー9:V2の非同期ミューテーションのタイミング(V2の新機能)
Problem: Inserted vectors not immediately queryable
Solution: V2 mutations are asynchronous - vectors may take a few seconds to be reflected
- Use mutationId to track mutation status
- Check env.VECTORIZE_INDEX.describe() for processedUpToMutation timestamp
エラー10:V1のreturnMetadata Boolean(V2で破壊的変更)
Problem: "returnMetadata must be 'all', 'indexed', or 'none'"
Solution: V2 changed returnMetadata from boolean to string enum:
- ❌ V1: { returnMetadata: true }
- ✅ V2: { returnMetadata: 'all' }
エラー11:Wrangler --jsonの出力にログのプレフィックスが含まれる
エラー:wrangler vectorize list --jsonの出力がログメッセージで始まり、JSONの解析に失敗する
出典:GitHub Issue #11011
影響を受けるコマンド:
wrangler vectorize list --jsonwrangler vectorize list-metadata-index --json
問題:
$ wrangler vectorize list --json
📋 Listing Vectorize indexes...
[
{ "created_on": "2025-10-18T13:28:30.259277Z", ... }
]
ログメッセージによって出力が無効なJSONとなり、jqやその他のツールへのパイプ処理に失敗します。
解決策:解析前に先頭行を削除します:
# Using tail
wrangler vectorize list --json | tail -n +2 | jq '.'
# Using sed
wrangler vectorize list --json | sed '1d' | jq '.'
エラー 12:TypeScript の型にフィルター演算子が不足
エラー:wrangler types が不完全な VectorizeVectorMetadataFilterOp 型を生成します
ソース:GitHub Issue #10092
ステータス:OPEN(内部では VS-461 として追跡中)
問題:
生成される型には $eq と $ne しか含まれておらず、V2 の演算子である $in、$nin、$lt、$lte、$gt、$gte が不足しています。
影響: 有効な V2 メタデータフィルター演算子を使用すると、TypeScript が誤ったエラーを表示します。
const vectorizeRes = env.VECTORIZE.queryById(imgId, {
filter: { gender: { $in: genderFilters } }, // ❌ TS error but works!
topK,
returnMetadata: 'indexed',
});
回避策:wrangler types が修正されるまで、型を手動で上書きします。
// Add to your types file
type VectorizeMetadataFilter = Record<string,
| string
| number
| boolean
| {
$eq?: string | number | boolean;
$ne?: string | number | boolean;
$in?: (string | number | boolean)[];
$nin?: (string | number | boolean)[];
$lt?: number | string;
$lte?: number | string;
$gt?: number | string;
$gte?: number | string;
}
>;
エラー 13:Windows の Dev レジストリでの失敗(修正済み)
エラー:Windows で wrangler dev を実行すると、ENOENT: no such file or directory が発生します
ソース:GitHub Issue #10383
ステータス:[email protected] で修正済み
問題: Wrangler がファイル名にコロンを含む外部 Worker ファイルを作成しようとしていました(Windows では無効です)。
Error: ENOENT: ... '__WRANGLER_EXTERNAL_VECTORIZE_WORKER:<project>:<binding>'
解決策: [email protected] 以降に更新します。
npm install -g wrangler@latest
エラー 14:topK の上限は returnValues/returnMetadata によって異なる
エラー:topK exceeds maximum allowed value
ソース:Vectorize Limits
問題:最大 topK 値はクエリオプションによって変わります。
| 設定 | 最大 topK |
|---|---|
returnValues: false、returnMetadata: 'none' | 100 |
returnValues: true または returnMetadata: 'all' | 20 |
returnMetadata: 'indexed' | 100 |
よくあるエラー:
// ❌ ERROR - topK too high with returnValues
query(embedding, {
topK: 100, // Exceeds limit!
returnValues: true // Max topK=20 when true
});
解決策:
// ✅ OK - respects conditional limit
query(embedding, {
topK: 20,
returnValues: true
});
// ✅ OK - higher topK without values
query(embedding, {
topK: 100,
returnValues: false,
returnMetadata: 'indexed'
});
V2 への移行チェックリスト
V1 から V2 に移行する場合:
- ✅ wrangler を 3.71.0 以降に更新します(
npm install -g wrangler@latest) - ✅ 新しい V2 インデックスを作成します(V1 → V2 へのアップグレードはできません)
- ✅ ベクトルを挿入する前に、メタデータインデックスを作成します
- ✅
returnMetadataをブール値から文字列の列挙値('all'、'indexed'、'none')に変更します - ✅ 非同期の変更を処理します(レスポンスに
mutationIdが含まれることを想定します) - ✅ V2 の制限でテストします(topK は最大 100、インデックスあたりベクトル 5M 個)
- ✅ 非同期動作に合わせてエラー処理を更新します
V1 の非推奨化:
- 2024 年 12 月以降:新しい V1 インデックスを作成できません
- 既存の V1 インデックス:引き続き動作します
- V1 の操作には
wrangler vectorize --deprecated-v1を使用します
テストに関する考慮事項
Vectorize バインディングを使用する Vitest
問題:@cloudflare/vitest-pool-workers で Vectorize または Workers AI のバインディングを使用すると、実行時エラーが発生します。
ソース:GitHub Issue #7434
エラー:wrapped binding module can't be resolved
回避策:
- Vectorize/AI バインディングを含まない
wrangler-test.jsoncを作成します - vitest の設定でテスト専用の wrangler ファイルを指定します
- テストでバインディングをモックします
例:
// wrangler-test.jsonc (no Vectorize binding)
{
"name": "my-worker-test",
"main": "src/index.ts",
"compatibility_date": "2025-10-21"
// No vectorize binding
}
// vitest.config.ts
import { defineWorkersProject } from '@cloudflare/vitest-pool-workers/config';
export default defineWorkersProject({
test: {
poolOptions: {
workers: {
wrangler: {
configPath: "./wrangler-test.jsonc"
}
}
}
}
});
// Mock in tests
import { vi } from 'vitest';
const mockVectorize = {
query: vi.fn().mockResolvedValue({
matches: [
{ id: 'test-1', score: 0.95, metadata: { category: 'docs' } }
],
count: 1
}),
insert: vi.fn().mockResolvedValue({ mutationId: "test-mutation-id" }),
upsert: vi.fn().mockResolvedValue({ mutationId: "test-mutation-id" })
};
// Use mock in tests
test('vector search', async () => {
const env = { VECTORIZE_INDEX: mockVectorize };
// ... test logic
});
コミュニティのヒント
注:これらのヒントは、コミュニティでの議論や公式ブログ記事に基づいています。ご利用の Vectorize のバージョンで確認してください。
ヒント 1:大規模な範囲クエリでは精度が低下する可能性があります(コミュニティ発)
ソース:Query Best Practices 信頼度:中 対象:ベクトル数が約 1,000 万個以上のデータセット
大規模なデータセットに対する範囲クエリ($lt、$lte、$gt、$gte)では、精度が低下する可能性があります。
最適化戦略:
// ❌ High-cardinality range at scale
metadata: {
timestamp_ms: 1704067200123
}
filter: { timestamp_ms: { $gte: 1704067200000 } }
// ✅ Bucketed into discrete values
metadata: {
timestamp_bucket: "2025-01-01-00:00", // 1-hour buckets
timestamp_ms: 1704067200123 // Original (non-indexed)
}
filter: {
timestamp_bucket: {
$in: ["2025-01-01-00:00", "2025-01-01-01:00"]
}
}
影響するケース:
- 数か月/数年にわたる時間ベースのフィルタリング
- ユーザー ID、トランザクション ID(UUID の範囲)
- カーディナリティの高い連続データ全般
代替策:値をバケット化し、等価フィルター($eq、$in)を使用します。
ヒント 2: List Vectors 操作 (2025年8月追加)
Vectorize V2 では、ベクター ID をページ単位で反復処理するための list-vectors 操作のサポートが追加されました。
ユースケース:
- ベクターコレクションの監査
- ベクターの一括操作
- インデックス内容のデバッグ
API:
const result = await env.VECTORIZE_INDEX.list({
limit: 1000, // Max 1000 per page
cursor?: string
});
// result.vectors: Array<{ id: string }>
// result.cursor: string | undefined
// result.count: number
// Pagination example
let cursor: string | undefined;
const allVectorIds: string[] = [];
do {
const result = await env.VECTORIZE_INDEX.list({
limit: 1000,
cursor
});
allVectorIds.push(...result.vectors.map(v => v.id));
cursor = result.cursor;
} while (cursor);
制限事項:
- ID のみを返します (値やメタデータは返しません)
- 1ページあたり最大 1000 ベクター
- ページネーションにはカーソルを使用してください
公式ドキュメント
- Vectorize V2 ドキュメント: https://developers.cloudflare.com/vectorize/
- V2 Changelog: https://developers.cloudflare.com/vectorize/platform/changelog/
- V1 から V2 への移行: https://developers.cloudflare.com/vectorize/reference/transition-vectorize-legacy/
- メタデータフィルタリング: https://developers.cloudflare.com/vectorize/reference/metadata-filtering/
- Workers AI モデル: https://developers.cloudflare.com/workers-ai/models/
ステータス: 本番環境対応 ✅ (Vectorize V2 GA - 2024年9月) 最終更新: 2026-01-21 トークン削減: 約70% 防止したエラー: 14件 (V2 の破壊的変更、テスト設定、TypeScript の型を含む) 変更点: 4件の新しいエラー (wrangler --json、TypeScript の型、Windows での開発、topK の制限)、バッチパフォーマンスのベストプラクティス、クエリ精度モード、テスト設定、範囲クエリと list-vectors 操作に関するコミュニティのヒントを追加しました。