Vector Search Designer について
Vector Search Designerは、ベクトル類似検索システムの設計と実装を支援するスキルです。セマンティック検索、推薦、AIアプリケーションを構築するチーム向けに、データベース選定、インデックス設計、再現率とレイテンシの調整を案内します。
主な機能
- 01ベクトルデータベースの評価と選定
- 02ANNインデックス構造の設計
- 03検索速度と再現率の調整
- 04フィルターとシャーディングの計画
- 05検索性能のベンチマーク
活用シーン
- 01セマンティック検索用データベースの選定
- 02ベクトル規模に応じたインデックス設計
- 03検索レイテンシや再現率の問題調査
- 04メタデータフィルター用インデックスの計画
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jmsktm/ claude-settings --skill vector-search-designerインストール後、Claude Code で/vector-search-designerを入力して読み込まれたか確認します。
詳細
ベクトル検索の設計
ベクトル検索の設計スキルは、セマンティック検索、レコメンデーションエンジン、AI アプリケーションを支えるベクトル類似検索システムの設計と実装を支援します。適切なベクトルデータベースの選定、インデックス構造の設計、クエリパフォーマンスの最適化、数百万から数十億のベクトルへのスケーリングをガイドします。
ベクトル検索は、RAG パイプラインから製品のレコメンデーションまで、現代の AI システムの基盤となっています。このスキルでは、近似最近傍(ANN)アルゴリズムの理解、データベースの選択肢の比較、再現率とレイテンシのトレードオフの調整、本番環境に対応した検索インフラストラクチャの実装まで、スタック全体を扱います。
Pinecone、Weaviate、Qdrant、pgvector を使用する場合でも、独自のソリューションを実装する場合でも、このスキルによって、ベクトル検索システムがパフォーマンスと精度の要件を満たせるようになります。
主なワークフロー
ワークフロー 1:ベクトルデータベースを選択する
- 要件を収集します:
- 規模:ベクトルはいくつですか?
- クエリパターン:単一とバッチのどちらですか?フィルターは必要ですか?
- レイテンシ要件:リアルタイムとバッチのどちらですか?
- 更新頻度:静的と動的のどちらですか?
- インフラストラクチャ:マネージドとセルフホストのどちらですか?
- 選択肢を比較します:
データベース 規模 マネージド 機能 最適な用途 Pinecone 10億以上 はい ハイブリッド、名前空間 本番環境、運用不要 Weaviate 1億以上 両方 GraphQL、モジュール マルチモーダル、複雑なクエリ Qdrant 1億以上 両方 Rust のパフォーマンス、フィルタリング 高パフォーマンス、セルフホスト Milvus 10億以上 両方 GPU サポート、クラスタリング 大規模、ML チーム pgvector 1,000万 いいえ PostgreSQL ネイティブ 既存の Postgres、小規模 Chroma 100万 いいえ シンプルな API プロトタイピング、組み込み - 自分のデータで評価します
- 選定理由を記録します
ワークフロー 2:インデックスアーキテクチャを設計する
- ANN アルゴリズムを選択します:
- HNSW:再現率と速度のトレードオフに優れますが、メモリを大量に消費します
- IVF:非常に大きなデータセットに適していますが、トレーニングが必要です
- PQ:大規模化に向けて圧縮できますが、精度が多少低下します
- Flat:厳密な検索が可能ですが、小規模なデータセットに限られます
- インデックスパラメーターを設定します:
# HNSW example configuration hnsw_config = { "M": 16, # Connections per node (higher = better recall, more memory) "efConstruction": 200, # Build-time search depth "efSearch": 100, # Query-time search depth } # IVF example configuration ivf_config = { "nlist": 1024, # Number of clusters "nprobe": 32, # Clusters to search at query time } - 大規模化に向けたシャーディング戦略を計画します
- フィルタリング用のメタデータスキーマを設計します
ワークフロー 3:検索パフォーマンスを最適化する
- ベースラインのパフォーマンスを測定します:
- 1 秒あたりのクエリ数(QPS)
- レイテンシ(p50、p95、p99)
- Recall@k の精度
- ボトルネックを特定します:
- インデックスの読み込み時間
- 検索レイテンシ
- フィルターの計算
- ネットワークのオーバーヘッド
- 最適化を適用します:
- インデックスパラメーター(ef、nprobe)を調整します
- クエリキャッシュを実装します
- フィルター式を最適化します
- メモリ節約のために量子化を検討します
- 再現率とレイテンシのトレードオフを検証します
- 最適な構成を記録します
クイックリファレンス
| 操作 | コマンド/トリガー |
|---|---|
| データベースを選択する | 「[use case]にはどのベクトルデータベースが適していますか」 |
| インデックスを設計する | 「[scale]向けのベクトルインデックスを設計する」 |
| 検索を最適化する | 「ベクトル検索を高速化する」 |
| フィルタリングを追加する | 「ベクトル検索にメタデータフィルターを追加する」 |
| ベクトルをスケーリングする | 「ベクトルを[N]百万件にスケーリングする」 |
| 検索をベンチマークする | 「ベクトル検索のパフォーマンスをベンチマークする」 |
ベストプラクティス
-
データベースの規模を適切に設定する:必要のない規模まで過剰に設計しないでください
- 100 万ベクトル未満:pgvector または Chroma で十分な場合が多いです
- 1,000 万~1 億ベクトル:Qdrant、Weaviate、または Pinecone
- 1 億ベクトル以上:慎重に設計した Milvus または Pinecone
-
再現率と速度のトレードオフを理解する:ANN は設計上、近似検索です
- 再現率が高いほど、クエリは遅くなります
- 精度要件に基づいて調整してください
- 実際の再現率を測定し、思い込みで判断しないでください
-
必要に応じてハイブリッド検索を使う:ベクトル検索とキーワード検索を組み合わせます
- ベクトル:意味的類似性
- キーワード(BM25):正確な用語、名前、コード
- 異なる種類のクエリが混在する場合、通常は検索結果が改善します
-
フィルタリングを考慮してメタデータを設計する:フィルタリング戦略を事前に計画します
- 頻繁に使うフィルターのフィールドにはインデックスを設定します
- カーディナリティの高いフィールドでのフィルタリングは避けます
- 事前フィルタリングと事後フィルタリングのトレードオフを考慮します
-
可能な場合はバッチ処理を使う:ネットワークのオーバーヘッドを削減します
- データ取り込みには一括アップサートを使います
- レイテンシが許容される場合はクエリをまとめて処理します
- 非同期処理を使います
-
監視とアラートを設定する:本番環境の検索には可観測性が必要です
- クエリレイテンシのパーセンタイル
- インデックスのサイズとメモリ使用量
- 時間の経過に伴う再現率の低下
高度な手法
マルチベクトル検索
複数の表現を持つドキュメントを処理します:
class MultiVectorIndex:
def __init__(self):
self.title_index = VectorIndex(dim=768)
self.content_index = VectorIndex(dim=768)
self.summary_index = VectorIndex(dim=768)
def search(self, query_embedding, weights=None):
weights = weights or {"title": 0.3, "content": 0.5, "summary": 0.2}
results = {}
for field, weight in weights.items():
index = getattr(self, f"{field}_index")
field_results = index.search(query_embedding, k=20)
for doc_id, score in field_results:
results[doc_id] = results.get(doc_id, 0) + score * weight
return sorted(results.items(), key=lambda x: x[1], reverse=True)[:10]
フィルタリング付きベクトル検索の戦略
フィルターを使った検索を最適化します:
def filtered_search(query_embedding, filters, k=10):
# Strategy 1: Pre-filter (for selective filters)
if estimate_selectivity(filters) < 0.1:
candidate_ids = apply_filters(filters)
return vector_search_subset(query_embedding, candidate_ids, k)
# Strategy 2: Post-filter (for non-selective filters)
elif estimate_selectivity(filters) > 0.5:
results = vector_search(query_embedding, k * 3)
filtered = [r for r in results if matches_filters(r, filters)]
return filtered[:k]
# Strategy 3: Hybrid (general case)
else:
return vector_search_with_filters(query_embedding, filters, k)
スケールに対応する量子化
許容できる精度の低下でメモリを削減します:
# Product Quantization configuration
pq_config = {
"nbits": 8, # Bits per sub-quantizer
"m": 16, # Number of sub-quantizers
# 768-dim * 4 bytes = 3KB/vector -> 16 * 1 byte = 16 bytes/vector
}
# Binary quantization (extreme compression)
binary_config = {
"threshold": 0, # Values > 0 -> 1, else -> 0
# 768-dim * 4 bytes = 3KB/vector -> 768 bits = 96 bytes/vector
}
インクリメンタルなインデックス更新
動的なデータを効率的に処理します:
class DynamicVectorIndex:
def __init__(self, rebuild_threshold=10000):
self.main_index = build_optimized_index()
self.delta_index = [] # Recent additions
self.rebuild_threshold = rebuild_threshold
def add(self, vector, metadata):
self.delta_index.append((vector, metadata))
if len(self.delta_index) >= self.rebuild_threshold:
self.rebuild()
def search(self, query, k):
main_results = self.main_index.search(query, k)
delta_results = brute_force_search(self.delta_index, query, k)
return merge_results(main_results, delta_results, k)
def rebuild(self):
all_data = self.main_index.get_all() + self.delta_index
self.main_index = build_optimized_index(all_data)
self.delta_index = []
避けるべきよくある落とし穴
- 大規模環境で ANN ではなく、正確な(フラット)検索を使う
- ANN は「十分に良い」と思い込み、実際の再現率を測定しない
- メタデータのフィールドに過剰にインデックスを設定し、更新を遅くする
- HNSW インデックスのメモリ要件を無視する
- インデックスの再構築やメンテナンス時間を計画しない
- ベクトルデータベースですべてのユースケースに対応できると思い込む(Elasticsearch のほうが適している場合もあります)
- コサイン類似度の計算に向けてベクトルを正規化し忘れる
- 同じインデックス内で異なるモデルの埋め込みを混在させる