Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Guide to selecting and optimizing embedding models for vector search applications.
.claude/skills/sickn33-embedding-strategies/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 117% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 115% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 62% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 118% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 179% | 0% |
Guide to selecting and optimizing embedding models for vector search applications.
resources/implementation-playbook.md.| 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 |
Document → Chunking → Preprocessing → Embedding Model → Vector
↓
[Overlap, Size] [Clean, Normalize] [API/Local]pythonfrom 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 )
pythonfrom 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}")
pythonfrom 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 def chunk_by_semantic_sections( text: str, headers_pattern: str = r'^#{1,3}\s+.+$' ) -> List[Tuple[str, str]]: """Chunk markdown by headers, preserving hierarchy.""" lines = text.split('\n') chunks = [] current_header = "" current_content = [] for line in lines: if re.match(headers_pattern, line, re.MULTILINE): if current_content: chunks.append((current_header, '\n'.join(current_content))) current_header = line current_content = [] else: current_content.append(line) if current_content: chunks.append((current_header, '\n'.join(current_content))) return chunks def recursive_character_splitter( text: str, chunk_size: int = 1000, chunk_overlap: int = 200, separators: List[str] = None ) -> List[str]: """Bounded character chunks, preferring a separator inside each window.""" if chunk_size <= 0 or not 0 <= chunk_overlap < chunk_size: raise ValueError("require chunk_size > 0 and 0 <= overlap < chunk_size") separators = separators or ["\n\n", "\n", ". ", " "] chunks = [] start = 0 while start < len(text): end = min(start + chunk_size, len(text)) if end < len(text): for separator in separators: if not separator: continue boundary = text.rfind(separator, start + chunk_overlap + 1, end) if boundary >= 0: end = boundary + len(separator) break chunks.append(text[start:end]) if end == len(text): break start = end - chunk_overlap return chunks
pythonclass DomainEmbeddingPipeline: """Pipeline for domain-specific embeddings.""" def __init__( self, embedding_model: str = "text-embedding-3-small", chunk_size: int = 512, chunk_overlap: int = 50, preprocessing_fn=None ): self.embedding_model = embedding_model self.chunk_size = chunk_size self.chunk_overlap = chunk_overlap self.preprocess = preprocessing_fn or self._default_preprocess def _default_preprocess(self, text: str) -> str: """Default preprocessing.""" # Remove excessive whitespace text = re.sub(r'\s+', ' ', text) # Remove special characters text = re.sub(r'[^\w\s.,!?-]', '', text) return text.strip() async def process_documents( self, documents: List[dict], id_field: str = "id", content_field: str = "content", metadata_fields: List[str] = None ) -> List[dict]: """Process documents for vector storage.""" processed = [] for doc in documents: content = doc[content_field] doc_id = doc[id_field] # Preprocess cleaned = self.preprocess(content) # Chunk chunks = chunk_by_tokens( cleaned, self.chunk_size, self.chunk_overlap ) # Create embeddings embeddings = get_embeddings(chunks, self.embedding_model) # Create records for i, (chunk, embedding) in enumerate(zip(chunks, embeddings)): record = { "id": f"{doc_id}_chunk_{i}", "document_id": doc_id, "chunk_index": i, "text": chunk, "embedding": embedding } # Add metadata if metadata_fields: for field in metadata_fields: if field in doc: record[field] = doc[field] processed.append(record) return processed # Code-specific pipeline class CodeEmbeddingPipeline: """Specialized pipeline for code embeddings.""" def __init__(self, embed_fn): self.embed_fn = embed_fn # Supply a reviewed provider-specific embedding adapter. def chunk_code(self, code: str, language: str) -> List[dict]: """Chunk code by functions/classes.""" import tree_sitter # Parse with tree-sitter # Extract functions, classes, methods # Return chunks with context raise NotImplementedError("Supply the installed parser and language grammar") def embed_with_context(self, chunk: str, context: str) -> List[float]: """Embed code with surrounding context.""" combined = f"Context: {context}\n\nCode:\n{chunk}" return self.embed_fn(combined)
pythonimport numpy as np from typing import List, Tuple def evaluate_retrieval_quality( queries: List[str], relevant_docs: List[List[str]], # List of relevant doc IDs per query retrieved_docs: List[List[str]], # List of retrieved doc IDs per query k: int = 10 ) -> dict: """Evaluate embedding quality for retrieval.""" def precision_at_k(relevant: set, retrieved: List[str], k: int) -> float: retrieved_k = retrieved[:k] relevant_retrieved = len(set(retrieved_k) & relevant) return relevant_retrieved / k def recall_at_k(relevant: set, retrieved: List[str], k: int) -> float: retrieved_k = retrieved[:k] relevant_retrieved = len(set(retrieved_k) & relevant) return relevant_retrieved / len(relevant) if relevant else 0 def mrr(relevant: set, retrieved: List[str]) -> float: for i, doc in enumerate(retrieved): if doc in relevant: return 1 / (i + 1) return 0 def ndcg_at_k(relevant: set, retrieved: List[str], k: int) -> float: dcg = sum( 1 / np.log2(i + 2) if doc in relevant else 0 for i, doc in enumerate(retrieved[:k]) ) ideal_dcg = sum(1 / np.log2(i + 2) for i in range(min(len(relevant), k))) return dcg / ideal_dcg if ideal_dcg > 0 else 0 metrics = { f"precision@{k}": [], f"recall@{k}": [], "mrr": [], f"ndcg@{k}": [] } for relevant, retrieved in zip(relevant_docs, retrieved_docs): relevant_set = set(relevant) metrics[f"precision@{k}"].append(precision_at_k(relevant_set, retrieved, k)) metrics[f"recall@{k}"].append(recall_at_k(relevant_set, retrieved, k)) metrics["mrr"].append(mrr(relevant_set, retrieved)) metrics[f"ndcg@{k}"].append(ndcg_at_k(relevant_set, retrieved, k)) return {name: np.mean(values) for name, values in metrics.items()} def compute_embedding_similarity( embeddings1: np.ndarray, embeddings2: np.ndarray, metric: str = "cosine" ) -> np.ndarray: """Compute similarity matrix between embedding sets.""" if metric == "cosine": # Normalize norm1 = embeddings1 / np.linalg.norm(embeddings1, axis=1, keepdims=True) norm2 = embeddings2 / np.linalg.norm(embeddings2, axis=1, keepdims=True) return norm1 @ norm2.T elif metric == "euclidean": from scipy.spatial.distance import cdist return -cdist(embeddings1, embeddings2, metric='euclidean') elif metric == "dot": return embeddings1 @ embeddings2.T
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 18,856 | 22,492 | +19% | 1 | 1 | 0% | 3,651 | 7,939 | +117% | 0 | 0 | — |
case-02 | fail→fail | 23,876 | 25,995 | +9% | 1 | 1 | 0% | 4,880 | 9,546 | +96% | 0 | 0 | — |
case-03 | fail→fail | 21,339 | 20,543 | -4% | 1 | 1 | 0% | 3,925 | 7,981 | +103% | 0 | 0 | — |
case-04 | fail→pass | 15,578 | 13,820 | -11% | 1 | 1 | 0% | 3,178 | 6,833 | +115% | 0 | 0 | — |
case-05 | fail→fail | 19,545 | 16,092 | -18% | 1 | 1 | 0% | 4,145 | 7,497 | +81% | 0 | 0 | — |
case-06 | pass→pass | 10,329 | 10,162 | -2% | 1 | 1 | 0% | 2,037 | 6,118 | +200% | 0 | 0 | — |
case-07 | pass→pass | 10,458 | 8,105 | -22% | 1 | 1 | 0% | 2,048 | 5,467 | +167% | 0 | 0 | — |
case-08 | pass→pass | 7,029 | 9,131 | +30% | 1 | 1 | 0% | 1,259 | 5,727 | +355% | 0 | 0 | — |
case-09 | fail→pass | 16,675 | 5,319 | -68% | 1 | 1 | 0% | 3,099 | 5,008 | +62% | 0 | 0 | — |
case-10 | pass→pass | 12,728 | 6,864 | -46% | 1 | 1 | 0% | 2,468 | 5,287 | +114% | 0 | 0 | — |
case-11 | fail→pass | 14,158 | 8,875 | -37% | 1 | 1 | 0% | 2,655 | 5,784 | +118% | 0 | 0 | — |
case-12 | fail→pass | 10,030 | 5,793 | -42% | 1 | 1 | 0% | 1,824 | 5,097 | +179% | 0 | 0 | — |
case-13 | fail→fail | 15,657 | 8,024 | -49% | 1 | 1 | 0% | 2,812 | 5,450 | +94% | 0 | 0 | — |
case-14 | pass→pass | 7,350 | 4,606 | -37% | 1 | 1 | 0% | 1,373 | 4,910 | +258% | 0 | 0 | — |
case-15 | pass→pass | 6,409 | 6,911 | +8% | 1 | 1 | 0% | 1,226 | 5,256 | +329% | 0 | 0 | — |
case-16 | pass→pass | 14,121 | 9,526 | -33% | 1 | 1 | 0% | 2,374 | 5,643 | +138% | 0 | 0 | — |
case-17 | pass→pass | 3,712 | 4,525 | +22% | 1 | 1 | 0% | 652 | 4,883 | +649% | 0 | 0 | — |
case-18 | fail→fail | 6,823 | 5,224 | -23% | 1 | 1 | 0% | 1,289 | 5,036 | +291% | 0 | 0 | — |
case-19 | pass→pass | 15,168 | 11,433 | -25% | 1 | 1 | 0% | 3,013 | 6,360 | +111% | 0 | 0 | — |
case-20 | pass→pass | 10,947 | 13,522 | +24% | 1 | 1 | 0% | 2,059 | 6,691 | +225% | 0 | 0 | — |
case-21 | fail→fail | 14,337 | 7,386 | -48% | 1 | 1 | 0% | 2,650 | 5,460 | +106% | 0 | 0 | — |
case-22 | pass→pass | 6,098 | 9,009 | +48% | 1 | 1 | 0% | 1,148 | 5,793 | +405% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +23 percentage points is the difference between those two pass rates over the 22 comparable cases.
The publisher has shipped newer versions since this run, so these numbers describe v1, not the version currently listed.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.