domains / data / embedding-model-selection / embedding-strategies
The three copies share the same model comparison table, pipeline diagram, and most templates, but they disagree on implementation details. The sickn33 copy adds input validation to chunk_by_tokens, fixes an infinite-loop edge case, and replaces the buggy BGE prefix check with an explicit query_prefix parameter. The foryourhealth111 and rmyndharis copies contain a bug in LocalEmbedder.embed_query (checking a string against an integer return value) and a potential infinite loop in chunk_by_tokens. Because the copies overlap but each has material steps or constraints the others lack, and they disagree on the correct way to handle model-specific prefixes and chunking edge cases, crowning one would hide a real alternative.
| Repository | Path |
|---|---|
| foryourhealth111-pixel/Vibe-Skills | bundled/skills/embedding-strategies/SKILL.md |
| rmyndharis/antigravity-skills | skills/embedding-strategies/SKILL.md |
| sickn33/agentic-awesome-skills | plugins/agentic-awesome-skills-claude/skills/embedding-strategies/SKILL.md |
| Role | Repository | Path |
|---|---|---|
| peer | foryourhealth111-pixel/Vibe-Skills | bundled/skills/embedding-strategies/SKILL.md |
| peer | rmyndharis/antigravity-skills | skills/embedding-strategies/SKILL.md |
| peer | sickn33/agentic-awesome-skills | plugins/agentic-awesome-skills-claude/skills/embedding-strategies/SKILL.md |
| adapter | sickn33/agentic-awesome-skills | plugins/agentic-awesome-skills/skills/embedding-strategies/SKILL.md |
| adapter | sickn33/agentic-awesome-skills | plugins/agentic-bundle-aas-data-engineering-platform/skills/embedding-strategies/SKILL.md |
| adapter | sickn33/agentic-awesome-skills | skills/embedding-strategies/SKILL.md |
---
name: embedding-strategies
description: Select and optimize embedding models for semantic search and RAG applications. Use when choosing embedding models, implementing chunking strategies, or optimizing embedding quality for specific domains.
---
# Embedding Strategies
Guide to selecting and optimizing embedding models for vector search applications.
## When to Use This Skill
- Choosing embedding models for RAG
- Optimizing chunking strategies
- Fine-tuning embeddings for domains
- Comparing embedding model performance
- Reducing embedding dimensions
- Handling multilingual content
## Core Concepts
### 1. Embedding Model Comparison
| Model | Dimensions | Max Tokens | Best For |
|-------|------------|------------|----------|
| **text-embedding-3-large** | 3072 | 8191 | High accuracy |
| **text-embedding-3-small** | 1536 | 8191 | Cost-effective |
| **voyage-2** | 1024 | 4000 | Code, legal |
| **bge-large-en-v1.5** | 1024 | 512 | Open source |
| **all-MiniLM-L6-v2** | 384 | 256 | Fast, lightweight |
| **multilingual-e5-large** | 1024 | 512 | Multi-language |
### 2. Embedding Pipeline
```
Document → Chunking → Preprocessing → Embedding Model → Vector
↓
[Overlap, Size] [Clean, Normalize] [API/Local]
```
## Templates
### Template 1: OpenAI Embeddings
```python
from openai import OpenAI
from typing import List
import numpy as np
client = OpenAI()
def get_embeddings(
texts: List[str],
model: str = "text-embedding-3-small",
dimensions: int = None
) -> List[List[float]]:
"""Get embeddings from OpenAI."""
# Handle batching for large lists
batch_size = 100
all_embeddings = []
for i in range(0, len(texts), batch_size):
batch = texts[i:i + batch_size]
kwargs = {"input": batch, "model": model}
if dimensions:
kwargs["dimensions"] = dimensions
response = client.embeddings.create(**kwargs)
embeddings = [item.embedding for item in response.data]
all_embeddings.extend(embeddings)
return all_embeddings
def get_embedding(text: str, **kwargs) -> List[float]:
"""Get single embedding."""
return get_embeddings([text], **kwargs)[0]
# Dimension reduction with OpenAI
def get_reduced_embedding(text: str, dimensions: int = 512) -> List[float]:
"""Get embedding with reduced dimensions (Matryoshka)."""
return get_embedding(
text,
model="text-embedding-3-small",
dimensions=dimensions
)
```
### Template 2: Local Embeddings with Sentence Transformers
```python
from sentence_transformers import SentenceTransformer
from typing import List, Optional
import numpy as np
class LocalEmbedder:
"""Local embedding with sentence-transformers."""
def __init__(
self,
model_name: str = "BAAI/bge-large-en-v1.5",
device: str = "cpu",
query_prefix: str = ""
):
self.model = SentenceTransformer(model_name, device=device)
self.query_prefix = query_prefix # Choose from the selected model card.
def embed(
self,
texts: List[str],
normalize: bool = True,
show_progress: bool = False
) -> np.ndarray:
"""Embed texts with optional normalization."""
embeddings = self.model.encode(
texts,
normalize_embeddings=normalize,
show_progress_bar=show_progress,
convert_to_numpy=True
)
return embeddings
def embed_query(self, query: str) -> np.ndarray:
"""Embed a query with the explicitly configured model prefix."""
return self.embed([self.query_prefix + query])[0]
def embed_documents(self, documents: List[str]) -> np.ndarray:
"""Embed documents for indexing."""
return self.embed(documents)
# E5 model with instructions
class E5Embedder:
def __init__(self, model_name: str = "intfloat/multilingual-e5-large"):
self.model = SentenceTransformer(model_name)
def embed_query(self, query: str) -> np.ndarray:
return self.model.encode(f"query: {query}")
def embed_document(self, document: str) -> np.ndarray:
return self.model.encode(f"passage: {document}")
```
### Template 3: Chunking Strategies
```python
from typing import List, Tuple
import re
def chunk_by_tokens(
text: str,
chunk_size: int = 512,
chunk_overlap: int = 50,
tokenizer=None
) -> List[str]:
"""Chunk text by token count."""
if not isinstance(chunk_size, int) or not isinstance(chunk_overlap, int):
raise ValueError("chunk size and overlap must be integers")
if chunk_size <= 0 or not 0 <= chunk_overlap < chunk_size:
raise ValueError("require chunk_size > 0 and 0 <= overlap < chunk_size")
if tokenizer is None:
import tiktoken
tokenizer = tiktoken.get_encoding("cl100k_base")
tokens = tokenizer.encode(text)
chunks = []
start = 0
while start < len(tokens):
end = start + chunk_size
chunk_tokens = tokens[start:end]
chunk_text = tokenizer.decode(chunk_tokens)
chunks.append(chunk_text)
if end >= len(tokens):
break
start = end - chunk_overlap
return chunks
def chunk_by_sentences(
text: str,
max_chunk_size: int = 1000,
min_chunk_size: int = 100
) -> List[str]:
"""Chunk text by sentences, respecting size limits."""
import nltk
sentences = nltk.sent_tokenize(text)
chunks = []
current_chunk = []
current_size = 0
for sentence in sentences:
sentence_size = len(sentence)
if current_size + sentence_size > max_chunk_size and current_chunk:
chunks.append(" ".join(current_chunk))
current_chunk = []
current_size = 0
current_chunk.append(sentence)
current_size += sentence_size
if current_chunk:
chunks.append(" ".join(current_chunk))
return chunks
```
## Conflicts
- sickn33/agentic-awesome-skills uses an explicit query_prefix parameter in LocalEmbedder, while foryourhealth111-pixel/Vibe-Skills and rmyndharis/antigravity-skills use a buggy check (if "bge" in self.model.get_sentence_embedding_dimension()) that compares a string to an integer.
- sickn33/agentic-awesome-skills adds input validation and an early break to chunk_by_tokens to prevent infinite loops, while the other two copies lack these safeguards.
- sickn33/agentic-awesome-skills references a resources/implementation-playbook.md file that the other copies do not mention.