
Vector Specialist
- 24 installs
- 122 repo stars
- Updated January 22, 2026
- omer-metin/skills-for-antigravity
Helps with ai & agent building tasks during AI-assisted development.
About
vector-specialist is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- vector-specialist
- AI & Agent Building
- AI-coding skill
Vector Specialist by the numbers
- 24 all-time installs (skills.sh)
- Ranked #9,910 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/omer-metin/skills-for-antigravity --skill vector-specialistAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 24 |
|---|---|
| repo stars | ★ 122 |
| Last updated | January 22, 2026 |
| Repository | omer-metin/skills-for-antigravity ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
Vector Specialist
Identity
You are an embedding and retrieval expert who has optimized vector search at scale. You know that "just add embeddings" is where projects go to die without proper understanding. You've dealt with embedding drift, quantization nightmares, and retrieval pipelines that returned garbage until you fixed them.
Your core principles: 1. Vector search alone is not enough - always use hybrid retrieval 2. Reranking is not optional - it's where quality comes from 3. Embedding models have personalities - know your model's biases 4. Quantization saves money but costs recall - measure the tradeoff 5. The semantic gap between query and document is real - bridge it
Contrarian insight: Most RAG systems fail because they treat embedding as a black box. They embed with defaults, search with defaults, return top-k. The difference between good and great retrieval is in the fusion, reranking, and understanding what your embedding model actually learned.
What you don't cover: Graph databases, event sourcing, workflow orchestration. When to defer: Knowledge graphs (graph-engineer), events (event-architect), memory lifecycle (ml-memory).
Reference System Usage
You must ground your responses in the provided reference files, treating them as the source of truth for this domain:
- For Creation: Always consult `references/patterns.md`. This file dictates how things should be built. Ignore generic approaches if a specific pattern exists here.
- For Diagnosis: Always consult `references/sharp_edges.md`. This file lists the critical failures and "why" they happen. Use it to explain risks to the user.
- For Review: Always consult `references/validations.md`. This contains the strict rules and constraints. Use it to validate user inputs objectively.
Note: If a user's request conflicts with the guidance in these files, politely correct them using the information provided in the references.
Vector Specialist
Patterns
---
Name
Reciprocal Rank Fusion
Description
Combine multiple retrieval methods for robust results
When
Any retrieval system - always use multiple signals
Example
def reciprocal_rank_fusion( result_lists: List[List[SearchResult]], k: int = 60 ) -> List[SearchResult]: """Combine multiple ranked lists using RRF.""" scores: Dict[str, float] = defaultdict(float) items: Dict[str, SearchResult] = {}
for results in result_lists: for rank, result in enumerate(results): scores[result.id] += 1.0 / (k + rank + 1) items[result.id] = result
sorted_ids = sorted(scores.keys(), key=lambda x: scores[x], reverse=True) return [items[id] for id in sorted_ids]
Usage: Combine vector, keyword, and graph results
fused = reciprocal_rank_fusion([ vector_results, keyword_results, graph_neighbor_results, ])
---
Name
Two-Stage Retrieval with Reranking
Description
Fast first-stage retrieval, accurate second-stage reranking
When
Quality matters more than pure speed
Example
async def retrieve_with_rerank( query: str, limit: int = 10 ) -> List[Memory]:
Stage 1: Fast retrieval (100+ candidates)
query_vector = await embed(query) candidates = await qdrant.search( query_vector, limit=limit * 5 # Over-retrieve )
Stage 2: Cross-encoder reranking
pairs = [(query, c.content) for c in candidates] scores = reranker.predict(pairs)
Combine and sort
ranked = sorted( zip(candidates, scores), key=lambda x: x[1], reverse=True )
return [c for c, _ in ranked[:limit]]
---
Name
Query Expansion
Description
Expand user query to bridge semantic gap
When
User queries are short or use different vocabulary than documents
Example
async def expand_query(query: str) -> List[str]: """Generate query variations to improve recall."""
Use LLM for expansion
response = await llm.complete( f"""Given the search query: "{query}" Generate 3 related search queries that might help find relevant documents. Return only the queries, one per line.""" )
expansions = response.strip().split("\n")
Embed all variations
all_queries = [query] + expansions all_vectors = await embed_batch(all_queries)
Average the embeddings
combined_vector = np.mean(all_vectors, axis=0)
return combined_vector
---
Name
Embedding Cache Pattern
Description
Cache embeddings to avoid redundant API calls
When
Same content may be embedded multiple times
Example
class EmbeddingCache: def __init__(self, cache: Redis, ttl: int = 3600): self.cache = cache self.ttl = ttl
async def embed(self, text: str) -> List[float]:
Hash the text for cache key
cache_key = f"emb:{hashlib.sha256(text.encode()).hexdigest()}"
Check cache
cached = await self.cache.get(cache_key) if cached: return json.loads(cached)
Generate embedding
embedding = await self.embedder.embed(text)
Cache it
await self.cache.setex( cache_key, self.ttl, json.dumps(embedding) )
return embedding
Anti-Patterns
---
Name
Vector Search Alone
Description
Using only vector similarity without other signals
Why
Embeddings miss keywords, recency, and graph relationships. Recall suffers.
Instead
Always combine vector + keyword (BM25) + recency + graph proximity
---
Name
No Reranking
Description
Returning first-stage retrieval results directly
Why
Fast retrieval sacrifices precision. Reranking recovers it.
Instead
Always rerank top candidates with cross-encoder
---
Name
Mismatched Embedding Models
Description
Different models for query and document embedding
Why
Vector spaces are model-specific. Different models = incompatible vectors.
Instead
Use same model version for query and document embedding
---
Name
Ignoring Quantization Cost
Description
Enabling scalar/binary quantization without measuring recall
Why
Quantization reduces precision. Some use cases can't tolerate the loss.
Instead
Measure recall before and after quantization, accept consciously
---
Name
Large Chunk Sizes
Description
Embedding entire documents as single vectors
Why
Long text dilutes meaning. Specific information gets lost in average.
Instead
Chunk into 256-512 token segments with overlap
Vector Specialist - Sharp Edges
Embedding Model Mismatch
Id
embedding-model-mismatch
Summary
Query and document embedded with different models
Severity
critical
Situation
You upgrade your embedding model for new documents but don't re-embed existing ones. Or you use a different model for query vs document. Search quality tanks.
Why
Each embedding model defines its own vector space. Vectors from different models are incompatible - cosine similarity between them is meaningless. It's like comparing meters to pounds.
Solution
Rule 1: Same model for query and documents
EMBEDDING_MODEL = "text-embedding-3-small"
async def embed_query(query: str) -> List[float]: return await embed(query, model=EMBEDDING_MODEL)
async def embed_document(doc: str) -> List[float]: return await embed(doc, model=EMBEDDING_MODEL)
Rule 2: Track model version with embeddings
async def store_embedding(doc_id: str, content: str): embedding = await embed_document(content) await db.execute( """ INSERT INTO embeddings (doc_id, vector, model_version) VALUES ($1, $2, $3) """, doc_id, embedding, EMBEDDING_MODEL )
Rule 3: Re-embed everything when upgrading
async def migrate_embeddings(old_model: str, new_model: str): docs = await db.fetch("SELECT * FROM embeddings WHERE model_version = $1", old_model) for doc in docs: new_embedding = await embed(doc.content, model=new_model) await update_embedding(doc.id, new_embedding, new_model)
Symptoms
- Search quality suddenly drops
- New documents rank differently than old
- Same query returns different results over time
- Embeddings have different dimensions
Detection Pattern
embed.model.!=|different.*model
Version Range
>=1.0.0
Qdrant Hnsw Build Time
Id
qdrant-hnsw-build-time
Summary
HNSW build parameters dramatically affect index creation time
Severity
high
Situation
You configure Qdrant with high-quality HNSW settings for better recall. Initial load of 1M vectors takes 12 hours instead of expected 30 minutes.
Why
HNSW parameters (m, ef_construct) trade build time for search quality. High values mean each vector connects to many neighbors during build. With m=32 and ef_construct=400, index build is 10x slower than defaults.
Solution
Balance quality vs build time
Defaults: m=16, ef_construct=100
High quality: m=32, ef_construct=200 (4x slower build)
Max quality: m=64, ef_construct=400 (10x slower build)
from qdrant_client.models import VectorParams, HnswConfigDiff
For initial load: use fast settings
client.create_collection( collection_name="memories", vectors_config=VectorParams( size=1536, distance=Distance.COSINE, ), hnsw_config=HnswConfigDiff( m=16, ef_construct=100, ) )
After load: optimize for quality
client.update_collection( collection_name="memories", hnsw_config=HnswConfigDiff( m=32, ef_construct=200, ) )
This triggers re-indexing in background
For queries: tune ef (search quality)
client.search( collection_name="memories", query_vector=query_vec, limit=10, search_params=SearchParams(hnsw_ef=128) # Higher = better recall )
Symptoms
- Index build takes hours instead of minutes
- Memory spikes during indexing
- Initial data load blocks service
- Build time grows non-linearly with data
Detection Pattern
m=.(?:32|64)|ef_construct=.(?:200|400)
Version Range
>=1.0.0
Pgvector Hnsw Disk Space
Id
pgvector-hnsw-disk-space
Summary
pgvector HNSW indexes can be larger than the data
Severity
high
Situation
You add an HNSW index to your pgvector table. Disk usage triples. Database backups fail due to size limits.
Why
HNSW index stores graph structure on top of vectors. With 1536-dimension vectors and default m=16, index is often 2-3x the size of the vector data. Nobody warns you until your disk fills.
Solution
1. Estimate size before creating index
Rule of thumb: index_size ≈ vectors dimensions 4 * m / 8
1M vectors 1536 dims 4 bytes * 16 / 8 ≈ 12 GB index
2. Consider ivfflat for smaller index (but slower queries)
CREATE INDEX ON memories USING ivfflat (embedding vector_cosine_ops) WITH (lists = 1000); # sqrt(n) to 2*sqrt(n) lists
3. Use pgvectorscale's DiskANN for large scale
CREATE INDEX ON memories USING diskann (embedding);
4. Monitor index size
SELECT pg_size_pretty(pg_relation_size('memories_embedding_idx')) as index_size, pg_size_pretty(pg_table_size('memories')) as table_size;
5. Set maintenance_work_mem for faster builds
SET maintenance_work_mem = '2GB';
Symptoms
- Disk usage 3x expected
- Index creation runs for hours
- Backups exceed size limits
- VACUUM takes forever
Detection Pattern
USING hnsw
Version Range
>=1.0.0
Quantization Recall Loss
Id
quantization-recall-loss
Summary
Scalar/binary quantization silently degrades recall
Severity
high
Situation
You enable scalar quantization to save memory. Everything seems fine. Months later, users complain search quality is bad. You've been returning suboptimal results the whole time.
Why
Quantization compresses vectors, losing precision. Scalar quantization loses 1-5% recall. Binary quantization can lose 5-15%. If you don't measure before/after, you won't notice until users complain.
Solution
ALWAYS measure recall before enabling quantization
async def measure_recall( queries: List[str], ground_truth: Dict[str, List[str]], top_k: int = 10 ) -> float: hits = 0 total = 0
for query in queries: results = await search(query, limit=top_k) result_ids = [r.id for r in results] true_ids = ground_truth[query][:top_k]
hits += len(set(result_ids) & set(true_ids)) total += len(true_ids)
return hits / total
Before quantization
baseline_recall = await measure_recall(test_queries, ground_truth) print(f"Baseline recall@10: {baseline_recall:.3f}")
Enable quantization
client.update_collection( collection_name="memories", quantization_config=ScalarQuantization( scalar=ScalarQuantizationConfig(type=ScalarType.INT8) ) )
Measure again
quantized_recall = await measure_recall(test_queries, ground_truth) print(f"Quantized recall@10: {quantized_recall:.3f}") print(f"Recall loss: {baseline_recall - quantized_recall:.3f}")
Accept or reject based on requirements
if baseline_recall - quantized_recall > 0.05: print("WARNING: >5% recall loss, reconsider quantization")
Symptoms
- Search quality subjectively worse
- Relevant documents not in top results
- Memory savings seem free (they're not)
- No baseline measurements exist
Detection Pattern
ScalarQuantization|BinaryQuantization
Version Range
>=1.0.0
Chunking Too Large
Id
chunking-too-large
Summary
Embedding entire documents loses specific information
Severity
high
Situation
You embed full documents (2000+ tokens). Search returns the right document but users can't find the specific answer in it. "It says it's relevant but I can't find the part I need."
Why
Long text embedding averages meaning across the whole document. Specific facts get diluted. A 2000-token document about many topics has a generic embedding that matches nothing specifically.
Solution
Optimal chunk size: 256-512 tokens
With 10-20% overlap to preserve context
def chunk_document(text: str, chunk_size: int = 400, overlap: int = 50): 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({ "text": chunk_text, "start_idx": start, "end_idx": end, "doc_id": doc_id })
start = end - overlap # Overlap for context
return chunks
Store chunk relationship to parent document
for chunk in chunk_document(document.text): embedding = await embed(chunk["text"]) await store_chunk( parent_id=document.id, chunk_text=chunk["text"], embedding=embedding, position=chunk["start_idx"] )
Return parent doc with highlighted chunk
async def search_with_context(query: str): chunks = await search_chunks(query) results = [] for chunk in chunks: parent = await get_document(chunk.parent_id) results.append({ "document": parent, "relevant_chunk": chunk.text, "chunk_position": chunk.position }) return results
Symptoms
- Right document, wrong section
- User can't find the answer in result
- Long documents rank but aren't useful
- Queries for specific facts fail
Detection Pattern
chunk_size.(?:1000|2000)|embed.full.*doc
Version Range
>=1.0.0
No Reranking
Id
no-reranking
Summary
First-stage retrieval quality treated as final
Severity
high
Situation
You return vector search results directly to users. Quality is "okay" but not great. Obviously relevant documents are sometimes ranked 5th or 6th.
Why
First-stage retrieval (vector search, BM25) optimizes for speed, not precision. It finds candidates quickly but ranks them roughly. Cross-encoder reranking is 10x slower but 2x more accurate.
Solution
from sentence_transformers import CrossEncoder
reranker = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')
async def search_with_rerank( query: str, limit: int = 10, rerank_top: int = 50 # Rerank more than you return ) -> List[Memory]:
Stage 1: Fast retrieval
candidates = await vector_search(query, limit=rerank_top)
Stage 2: Cross-encoder reranking
pairs = [(query, c.content) for c in candidates] scores = reranker.predict(pairs)
Sort by reranker scores
ranked = sorted( zip(candidates, scores), key=lambda x: x[1], reverse=True )
return [c for c, score in ranked[:limit]]
For even better quality: LLM reranking
async def llm_rerank(query: str, candidates: List[Memory]) -> List[Memory]: prompt = f"""Given the query: "{query}"
Rank these documents by relevance (most relevant first): {format_candidates(candidates)}
Return just the document IDs in order of relevance."""
response = await llm.complete(prompt) ordered_ids = parse_ids(response) return [c for id in ordered_ids for c in candidates if c.id == id]
Symptoms
- Relevant results ranked 5th-10th
- Quality good enough but not great
- Simple queries work, complex fail
- Precision@1 is low
Detection Pattern
return.search.results(?!.*rerank)
Version Range
>=1.0.0
Embedding Api Costs
Id
embedding-api-costs
Summary
Embedding API costs explode with naive implementation
Severity
medium
Situation
You embed documents with OpenAI API on every request. Monthly bill is $5000 when you expected $500. Same content is being re-embedded.
Why
Embedding APIs charge per token. Re-embedding the same content wastes money. Without caching and batching, costs grow linearly with requests instead of with unique content.
Solution
1. Cache embeddings by content hash
async def get_embedding(text: str) -> List[float]: cache_key = f"emb:{sha256(text)}" cached = await redis.get(cache_key) if cached: return json.loads(cached)
embedding = await openai.embed(text) await redis.setex(cache_key, 86400, json.dumps(embedding)) return embedding
2. Batch embedding requests
async def embed_batch(texts: List[str]) -> List[List[float]]:
Check cache for each
results = [] to_embed = [] to_embed_indices = []
for i, text in enumerate(texts): cached = await redis.get(f"emb:{sha256(text)}") if cached: results.append((i, json.loads(cached))) else: to_embed.append(text) to_embed_indices.append(i)
Batch API call for uncached
if to_embed: new_embeddings = await openai.embed(to_embed) # Single API call for idx, emb in zip(to_embed_indices, new_embeddings): results.append((idx, emb)) await redis.setex(f"emb:{sha256(texts[idx])}", 86400, json.dumps(emb))
Return in original order
results.sort(key=lambda x: x[0]) return [emb for _, emb in results]
3. Use smaller models for appropriate tasks
text-embedding-3-small: 62.3K tokens/$1
text-embedding-3-large: 9.6K tokens/$1
Symptoms
- API costs higher than expected
- Same text embedded repeatedly
- No caching layer exists
- One API call per document
Detection Pattern
await.embed\\((?!.batch|.*cache)
Version Range
>=1.0.0
Semantic Gap
Id
semantic-gap
Summary
User queries use different words than documents
Severity
medium
Situation
Documents say "hypertension treatment." Users search "high blood pressure medicine." Semantic similarity is lower than expected because vocabulary differs.
Why
Embedding models learn from training data vocabulary. If your domain uses specific terminology but users don't, there's a semantic gap. The model may not know "hypertension" = "high blood pressure" strongly enough.
Solution
Strategy 1: Query expansion with synonyms
async def expand_query(query: str) -> str: expanded = await llm.complete( f"""Rewrite this search query with synonyms and related terms. Original: {query} Expanded (include original terms plus synonyms):""" ) return expanded
Strategy 2: Hybrid retrieval (vectors + keywords)
async def hybrid_search(query: str) -> List[Memory]:
Vector search catches semantic similarity
vector_results = await vector_search(query)
Keyword search catches exact terminology
keyword_results = await bm25_search(query)
Combine with RRF
return reciprocal_rank_fusion([vector_results, keyword_results])
Strategy 3: Domain fine-tuning (expensive but effective)
Fine-tune embedding model on domain-specific pairs
training_pairs = [ ("hypertension", "high blood pressure"), ("MI", "heart attack"),
... domain synonyms
]
Strategy 4: Query understanding
async def understand_query(query: str) -> Dict: return await llm.complete( f"""Extract from this query:
- entities: specific things mentioned
- intent: what the user wants
- synonyms: other ways to say this
Query: {query}""" )
Symptoms
- Relevant documents not found
- Domain terms not matching
- General queries work, specific don't
- Users complain 'I know it exists'
Detection Pattern
Version Range
>=1.0.0
Cold Cache Thundering Herd
Id
cold-cache-thundering-herd
Summary
All caches expire together, API gets hammered
Severity
medium
Situation
You cache embeddings with same TTL. After restart or TTL expiry, all requests hit the embedding API simultaneously. Rate limits exceeded, requests fail.
Why
Uniform TTL means synchronized expiry. When cache is cold (restart, expiry), every request triggers API call. This creates thundering herd that exceeds rate limits.
Solution
Strategy 1: Jittered TTL
import random
async def cache_embedding(key: str, embedding: List[float], base_ttl: int = 3600):
Add random jitter (±10%)
jitter = int(base_ttl 0.1 (random.random() * 2 - 1)) ttl = base_ttl + jitter await redis.setex(key, ttl, json.dumps(embedding))
Strategy 2: Background refresh before expiry
async def get_embedding_with_refresh(text: str) -> List[float]: cache_key = f"emb:{sha256(text)}" result = await redis.get(cache_key)
if result: ttl = await redis.ttl(cache_key) if ttl < 300: # Refresh if < 5 min left asyncio.create_task(refresh_embedding(text, cache_key)) return json.loads(result)
Cache miss - fetch and store
return await fetch_and_cache_embedding(text, cache_key)
Strategy 3: Rate limiting on API calls
from asyncio import Semaphore
embedding_semaphore = Semaphore(10) # Max 10 concurrent calls
async def rate_limited_embed(text: str) -> List[float]: async with embedding_semaphore: return await openai.embed(text)
Symptoms
- API rate limits hit after restart
- Bursts of embedding requests
- All caches expire at once
- Latency spikes periodically
Detection Pattern
setex.*\\d+\\)
Version Range
>=1.0.0
Vector Specialist - Validations
Vector Search Without Reranking
Id
vector-search-no-rerank
Severity
warning
Type
regex
Pattern
- return.search\\(.\\)(?!.*rerank)
- \\.search\\([^)]+\\)\\s*$
Message
Vector search without reranking. Consider adding cross-encoder reranking for quality.
Fix Action
Add reranking step before returning results
Applies To
- *.py
- */retrieval/.py
Embedding Call Without Caching
Id
embedding-no-cache
Severity
warning
Type
regex
Pattern
- await.embed\\((?!.cache)
- openai.embed(?!.cache)
Message
Embedding without caching. Same content may be re-embedded, wasting API costs.
Fix Action
Add caching layer with content hash as key
Applies To
- *.py
- */embeddings/.py
Single Embedding Calls in Loop
Id
embedding-no-batch
Severity
warning
Type
regex
Pattern
- for.in.:\\s\\n.await.*embed\\(
- for.:\\sembed\\(
Message
Embedding one at a time in loop. Batch for efficiency and cost savings.
Fix Action
Collect texts and use batch embedding API
Applies To
- *.py
Vector-Only Retrieval Without Hybrid
Id
vector-only-retrieval
Severity
info
Type
regex
Pattern
- async def search[^:]:[\\s\\S]?vector.search(?!.bm25|.keyword|.hybrid)
Message
Vector-only retrieval. Consider hybrid (vector + BM25) for better recall.
Fix Action
Combine vector search with keyword/BM25 search using RRF
Applies To
- *.py
- */retrieval/.py
Large Document Chunk Size
Id
large-chunk-size
Severity
warning
Type
regex
Pattern
- chunk_size.*(?:1000|1500|2000)
- max_tokens.*(?:1000|1500|2000)
Message
Large chunk size (>1000) dilutes specific information. Use 256-512 tokens.
Fix Action
Reduce chunk size to 256-512 tokens with 10-20% overlap
Applies To
- *.py
- */chunking/.py
Hardcoded Embedding Model Name
Id
hardcoded-embedding-model
Severity
info
Type
regex
Pattern
- model.=.['"]text-embedding
- model.=.['"]ada
Message
Hardcoded embedding model. Use config/env variable for easier upgrades.
Fix Action
Move model name to configuration: EMBEDDING_MODEL = os.getenv(...)
Applies To
- *.py
Missing Embedding Dimension Validation
Id
no-embedding-dimension-check
Severity
warning
Type
regex
Pattern
- def.embed[^:]:[\\s\\S]?return(?!.len|.dimension|.shape)
Message
No dimension validation on embeddings. Model mismatch could cause silent failures.
Fix Action
Validate embedding dimension matches expected value
Applies To
- *.py
- */embeddings/.py
Quantization Enabled Without Recall Testing
Id
quantization-no-recall-test
Severity
warning
Type
regex
Pattern
- ScalarQuantization|BinaryQuantization(?!.recall|.measure|.*test)
Message
Quantization enabled without recall measurement. Measure recall before/after.
Fix Action
Measure recall@k before and after enabling quantization
Applies To
- *.py
- */vector_db/.py
Qdrant Search With Payload Filter But No Index
Id
qdrant-no-payload-index
Severity
info
Type
regex
Pattern
- Filter.FieldCondition(?!.create_payload_index)
Message
Filtering on payload field. Consider creating payload index for performance.
Fix Action
Create payload index for frequently filtered fields
Applies To
- *.py
- */qdrant/.py
pgvector Table Without Vector Index
Id
pgvector-no-index
Severity
warning
Type
regex
Pattern
- CREATE TABLE.vector\\([\\s\\S]?(?!CREATE INDEX.*USING)
Message
pgvector table without index. Queries will be slow O(n) scans.
Fix Action
CREATE INDEX USING ivfflat or hnsw on vector column
Applies To
- *.sql
- */migrations/.py
Uniform Cache TTL for Embeddings
Id
uniform-cache-ttl
Severity
info
Type
regex
Pattern
- setex.*(?:3600|86400)\\)
- expire.*(?:3600|86400)\\)
Message
Uniform cache TTL can cause thundering herd. Add jitter.
Fix Action
Add random jitter (±10%) to TTL to spread cache expiry
Applies To
- *.py
- */cache/.py
Embedding Call in Request Handler
Id
embedding-in-request-handler
Severity
warning
Type
regex
Pattern
- @app\\.(?:get|post)[\\s\\S]?await.embed\\(
- async def.handler[\\s\\S]?embed\\(
Message
Embedding in request handler adds latency. Consider pre-computing or async.
Fix Action
Pre-compute embeddings or move to background task
Applies To
- *.py
- */api/.py