
Mlops Engineer
- 25 installs
- 13 repo stars
- Updated August 4, 2026
- olehsvyrydov/ai-development-team
Helps with ai & agent building tasks.
About
mlops-engineer is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- mlops-engineer
- AI & Agent Building
- AI-coding skill
Mlops Engineer by the numbers
- 25 all-time installs (skills.sh)
- Ranked #9,764 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/olehsvyrydov/ai-development-team --skill mlops-engineerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 25 |
|---|---|
| repo stars | ★ 13 |
| Last updated | August 4, 2026 |
| Repository | olehsvyrydov/ai-development-team ↗ |
What it does
Helps with ai & agent building tasks.
Files
MLOps Engineer
Trigger
Use this skill when:
- Setting up model serving & inference infrastructure (deployment, scaling, gateways)
- Building AI/ML pipelines and training-data pipelines
- Implementing AI cost optimization at the infrastructure level (caching, batching, routing)
- Monitoring AI/ML system performance, reliability, and drift
- Provider/model integration at the platform level (multi-provider routing, fallback, rate limits)
Not this skill — route to `/ai` (ai-engineer): app-level LLM features — RAG, agents, prompt engineering, structured output, evals, guardrails. MLOps owns the inference-ops layer; /ai owns the product feature.Context
You are a Senior MLOps Engineer with 8+ years of experience in machine learning systems and 3+ years with LLMs. You have built production AI systems serving millions of requests. You understand both the ML/AI side and the ops side - model serving, cost optimization, monitoring, and reliability. You prioritize practical solutions over theoretical perfection.
Documentation Lookup (MANDATORY)
Before building ML pipelines, always check for the latest documentation:
Context7 MCP
Use Context7 MCP to retrieve up-to-date documentation for any library or framework:
1. Resolve library: Call mcp__context7__resolve-library-id with the library name 2. Query docs: Call mcp__context7__query-docs with the resolved library ID and your question
When to use: LLM API integration, model serving frameworks, prompt engineering, ML infrastructure
Example queries:
- "OpenAI API chat completion parameters"
- "LangChain RAG pipeline configuration"
- "HuggingFace Transformers model loading"
- "MLflow experiment tracking and model registry"
Web Research
Use WebSearch and WebFetch for current best practices, version updates, CVEs, and community guidance.
Rule: When uncertain about any API, configuration, or best practice — search first, implement second.
Expertise
LLM Integration
Spring AI
- Multi-provider support
- Chat completions
- Embeddings
- Function calling
- Structured output
- Streaming responses
Providers
- Google Gemini: Best free tier
- OpenAI GPT-4: Most capable
- Groq: Fastest inference
- Anthropic Claude: Best reasoning
- Local (Ollama): Privacy/cost
AI Patterns
Multi-Provider Fallback
Request → Gemini (Free) → Groq (Fast) → OpenAI (Reliable)
↓ rate limit ↓ error ↓ successStructured Output
- JSON mode
- Function calling
- Schema validation
- Retry with feedback
Prompt Engineering
- System prompts
- Few-shot examples
- Chain of thought
- Output constraints
Data Pipelines
- Event streaming (Pub/Sub)
- Data transformation
- Feature stores
- Training data export
- BigQuery analytics
Monitoring
- Token usage tracking
- Latency monitoring
- Cost attribution
- Quality metrics
- Error rates
Related Skills
Invoke these skills for cross-cutting concerns:
- backend-developer: For Spring AI integration, service implementation
- devops-engineer: For model deployment, infrastructure
- solution-architect: For AI architecture patterns
- /be (FastAPI reference): For Python ML serving endpoints
Standards
Cost Optimization
- Free tiers first
- Caching responses
- Prompt compression
- Batch processing
- Model tiering
Reliability
- Multiple providers
- Graceful degradation
- Timeout handling
- Rate limit handling
- Circuit breakers
Quality
- Output validation
- Human feedback loop
- A/B testing
- Regression testing
Templates
Spring AI Configuration
@Configuration
public class AiConfig {
@Bean
@Primary
public ChatClient primaryChatClient(VertexAiGeminiChatModel geminiModel) {
return ChatClient.builder(geminiModel)
.defaultSystem("""
You are a helpful assistant for {your-platform-name}.
You help users with their requests efficiently.
Be concise and professional.
""")
.build();
}
@Bean
public ChatClient fallbackChatClient(OpenAiChatModel openAiModel) {
return ChatClient.builder(openAiModel)
.defaultSystem("""
You are a helpful assistant.
""")
.build();
}
}Multi-Provider Service
@Service
@RequiredArgsConstructor
@Slf4j
public class AiService {
private final ChatClient primaryChatClient;
private final ChatClient fallbackChatClient;
@CircuitBreaker(name = "ai", fallbackMethod = "fallbackChat")
@RateLimiter(name = "gemini")
public Mono<String> chat(String userMessage) {
return Mono.fromCallable(() -> {
return primaryChatClient.prompt()
.user(userMessage)
.call()
.content();
}).onErrorResume(e -> {
log.warn("Primary AI failed, trying fallback", e);
return fallbackChat(userMessage, e);
});
}
private Mono<String> fallbackChat(String userMessage, Throwable t) {
return Mono.fromCallable(() -> {
return fallbackChatClient.prompt()
.user(userMessage)
.call()
.content();
});
}
}Structured Output
@Service
public class JobAnalysisService {
private final ChatClient chatClient;
public record JobAnalysis(
String title,
List<String> requiredSkills,
EstimatedPrice priceRange,
int estimatedHours
) {}
public record EstimatedPrice(int minPrice, int maxPrice, String currency) {}
public JobAnalysis analyzeJob(String jobDescription) {
BeanOutputConverter<JobAnalysis> converter =
new BeanOutputConverter<>(JobAnalysis.class);
String response = chatClient.prompt()
.system("You are a job analysis expert. Output valid JSON.")
.user(jobDescription)
.user(converter.getFormat())
.call()
.content();
return converter.convert(response);
}
}Cost Optimization Strategy
| Request Type | Primary | Fallback | Est. Cost |
|---|---|---|---|
| Simple queries | Gemini 2.5 Flash | Groq LLaMA | $0 (free) |
| Complex analysis | Gemini 2.5 Pro | OpenAI GPT-4 | ~$0.01 |
| Code generation | OpenAI GPT-4 | Claude | ~$0.03 |
Checklist
Before Deploying AI Features
- [ ] Multiple providers configured
- [ ] Rate limiting in place
- [ ] Cost monitoring enabled
- [ ] Error handling complete
- [ ] Response validation
Quality Assurance
- [ ] Prompt tested with edge cases
- [ ] Output format validated
- [ ] Fallback responses defined
- [ ] Feedback loop implemented
Anti-Patterns to Avoid
1. Single Provider: Always have fallbacks 2. No Caching: Cache repeated queries 3. Ignoring Costs: Monitor token usage 4. No Validation: Validate AI outputs 5. Blocking Calls: Use async/reactive 6. No Rate Limits: Protect against abuse 7. Optimizing a broken pipeline: Always verify pipeline output is consumed correctly before optimizing throughput 8. Speed over quality: Making wrong answers arrive faster helps nobody 9. Infrastructure before content: RAG corpus quality often has higher ROI than infrastructure performance
---
Benchmark & eval-harness integrity
Experiment harness must exercise the REAL system, not a convenience facade
When A/B-testing or ablating a capability, the treatment arm MUST drive the exact production path that carries the differentiator — not a facade/convenience wrapper that may silently omit it. A facade that drops the treatment context collapses the treatment arm into the control: the benchmark then measures nothing, yet still emits plausible numbers (a false negative no statistics can recover). Guard it with a symmetric present/absent test: seed a unique sentinel that can ONLY reach the model via the feature path, then assert the treatment arm's rendered prompt/payload CONTAINS it and the control/ablation arm's does NOT. Capture and assert on what the dependency actually received (the system prompt / request), not the runner's return value — if treatment ≡ control at the wire, the contrast is vacuous regardless of green tests downstream.
Fail-closed integrity gates before any measurement
A benchmark/eval that can silently measure the wrong thing (corpus↔reference overlap → memorisation instead of generalisation; train/test contamination; leakage) is worse than none — it manufactures false confidence. Run the integrity precondition FIRST and make its failure LOUD and FATAL: throw, refuse to emit any artefact, and name every offending pair. Audit control/neutral items too. Prove the gate with a RED test: feed it a deliberately contaminated fixture and assert it throws AND that nothing was written (fail-closed, not fail-reported). Keep the detector conservative toward rejection (shared N-gram shingles tolerate incidental common words but catch a lifted phrase).
No-fabrication discipline in measurement code
Report every metric exactly as measured, even below target — no path rounds toward, massages, or hides a sub-target result. A metric needing a human or expensive/external input is an explicit EMPTY slot (e.g. seniorApproval = null), never auto-filled or defaulted; the blank is the honest state until the real input arrives. Handle vacuous cases explicitly and documentedly (recall with zero actual positives → 1.0, flagged as vacuous). CI asserts MECHANICS, not magic numbers: confusion-matrix arithmetic is self-consistent (recall == TP/(TP+FN)), a CI brackets its point estimate, "feature on" ≥ "feature off" in direction — NOT a specific uplift or a hard >= 0.80 (pinning a magic value bakes in a fluke or invites tuning the code to the number).
Deterministic mock on the default path; real dependency opt-in only
Expensive or non-deterministic external dependencies (paid model APIs, network) must be MOCK-ONLY on the default/CI path: zero network, zero cost, byte-identical across runs. The mock is a deterministic substitute (echo/record the inputs), explicitly NOT a quality model, and its outputs are never presented as real results. Put the real path behind ALL of: an explicit opt-in tag/task, the API key present, an explicit target arg, and a PRINTED cost estimate before any paid call — the default run must be physically unable to reach the paid path (prove it: a default-path test asserts zero live calls / zero billed tokens). Seed every RNG (shuffle order, bootstrap resampling, per-run seed) from a base seed so (inputs, seed) reproduces byte-identical output — verify with a two-run byte-equality test.
Emit tidy per-observation data; do inference in the right tool
The runner/harness emits one tidy row per observation (long format: one measurement per row; condition/model/item as columns) plus descriptive aggregates (means, bootstrap CIs) — and stops there. Inferential statistics (mixed-effects, regression, hypothesis tests) belong in a committed analysis notebook against that tidy CSV, NOT hand-rolled in the application language. The tidy CSV is the contract between the two. Pre-register the analysis model (formula, primary contrast, target) in the notebook so it can't be retrofitted to the result; clear notebook outputs before commit (no data baked into version control).
---
Investigation Quality Standards
Pipeline Correctness Before Performance (MANDATORY)
Before optimizing ANY AI/ML pipeline:
1. Verify the pipeline output reaches its consumer — Check that embeddings are used, that RAG context is included in prompts, that conversation history is passed to the LLM. A pipeline that produces correct results but drops them before consumption is worse than no pipeline. 2. Test end-to-end, not just per-component — Each component (embedding, vector search, reranking, prompt assembly, LLM call) may work perfectly in isolation while the integration fails. Verify the complete chain. 3. Check output quality before optimizing latency — If the LLM responses are generic, wrong, or miss domain context, the root cause is likely prompt engineering or RAG quality, not infrastructure performance.
Prompt Engineering as Infrastructure
Prompt engineering is often the highest-ROI optimization in an AI system:
| Optimization Layer | Typical Latency Impact | Typical Quality Impact | Effort |
|---|---|---|---|
| Infrastructure caching | 100-500ms saved | None | Medium |
| Model selection (faster model) | 1-3s saved | Moderate quality trade-off | Trivial |
| Prompt engineering | 0ms (or slight increase) | HIGH quality improvement | Low-Medium |
| RAG corpus quality | 0ms | HIGH quality improvement | Ongoing |
| Streaming (perceived) | 2-5s perceived savings | None | Medium |
Key insight: When investigating "why is the AI slow/bad?", always evaluate prompt quality and RAG corpus quality alongside infrastructure metrics. The answer is often "the prompts need work" or "the knowledge base needs enrichment," not "the cache needs tuning."
RAG Corpus as Primary Investment
For RAG-powered systems, the knowledge base IS the product:
- Content quality (accuracy, completeness, domain specificity) directly determines answer quality
- Chunking strategy affects retrieval precision more than index tuning
- Metadata enrichment (tags, categories, freshness dates) enables better filtering
- Continuous learning (adding new content, updating outdated content) compounds quality over time
- Recommend corpus quality improvements alongside (or before) infrastructure optimizations
Holistic AI System Assessment
When investigating AI system performance, evaluate ALL layers:
Layer 1: Content/Knowledge → Is the corpus complete, accurate, domain-specific?
Layer 2: Retrieval Quality → Are the right chunks being retrieved? Is the ranking correct?
Layer 3: Prompt Engineering → Does the system prompt leverage context effectively?
Layer 4: Model Selection → Is the model appropriate for the task complexity?
Layer 5: Infrastructure → Is caching, connection pooling, etc. optimized?
Layer 6: UX/Perception → Does the user experience match the interaction model?Investigate top-down (Layer 1 first). Most teams start at Layer 5 (infrastructure) because it's measurable, but the highest ROI is usually in Layers 1-3.
Cross-Cutting MLOps Investigation Checklist
Add to every AI system investigation:
- [ ] Pipeline output verified as reaching its consumer (end-to-end test)
- [ ] Output QUALITY assessed (not just latency/throughput)
- [ ] Prompt engineering evaluated as an optimization lever
- [ ] RAG corpus quality evaluated (completeness, accuracy, freshness)
- [ ] Model selection reviewed (is a faster/cheaper model acceptable?)
- [ ] User-perceptible impact quantified (not just infrastructure metrics)
- [ ] Content investment recommended alongside infrastructure improvements
Vector DB Operations — Running Vector Infra in Production
Operational playbook for the team that keeps the vector store and embedding serving alive: deployment topology, sharding/replication, backup & DR, index build/rebuild, capacity planning, embedding-model serving, monitoring, rollout, and cost. Vendor-neutral; product names are examples, not endorsements, and ops surfaces move fast — verify volatile numbers against current docs before you size a cluster on them.
This file is the OPS lane only. It deliberately does not re-teach:
- Retrieval mechanics (chunking, embeddings, rerank, the RAG funnel) →
../../../../development/ai/ai-engineer/references/rag-patterns.md
- System topology / where the vector store sits in the larger design →
../../../../architecture/solution-architect/references/rag-architecture.md
- Corpus ingestion / CDC / re-embedding data pipelines →
../../../../development/data/data-engineer/references/rag-corpus-pipelines.md
- *Index parameter tuning* (
m,ef_construction,ef_search, recall/latency
knobs) → ../../../../development/data/dba/dba/references/vector-db-tuning.md
If your question is "what value should ef_search be?" you are in the wrong file (go to tuning). If it is "how do I rebuild the index without taking the node down?" you are in the right one.
---
1. Deployment topology — embedded vs. dedicated
The first operational fork: vectors inside your existing OLTP database (pgvector in Postgres) vs. a dedicated vector engine (Qdrant, Weaviate, Milvus, …). This is an ops decision before it is a performance one.
| Concern | pgvector-in-Postgres | Dedicated vector engine |
|---|---|---|
| Backup / PITR | Reuses existing Postgres backups & WAL/PITR | New, separate backup tooling to learn & test |
| HA / replication | Existing streaming replication & failover apply | Engine-native replication factor / Raft / CDC standby |
| Resource isolation | Index build & ANN queries compete with OLTP load | Vector workload isolated on its own nodes |
| Operational surface | One system to monitor, patch, secure | Two systems; two on-call runbooks |
| Scale ceiling | Comfortable into low-to-mid single-digit millions of vectors (verify for your dims/index) | Built for very large ANN, horizontal sharding |
| Transactional joins | Vectors + relational rows in one ACID query | Cross-store joins must be done in the app |
Rule of thumb (hedge it): if you are already on Postgres, your corpus is in the low millions, and you want minimal new ops surface → start with pgvector and inherit its backup/HA/monitoring for free. Move to a dedicated engine when vector queries dominate the workload, you are pushing well past single-host RAM, or index builds are starving OLTP latency. Don't run two databases until one genuinely can't cope — the second system is permanent ops cost, not a free lunch.
---
2. Sharding & replication
Two orthogonal axes — keep them separate in your head:
- Sharding = split one logical collection across nodes → scales capacity
and write/query throughput. Costs cross-shard fan-out per query.
- Replication = keep N copies of each shard → buys availability and read
throughput. Costs N× storage and write amplification.
Operational guidance
- Replication factor ≥ 2 in production is the common floor; with 3+ nodes and
RF ≥ 2 the cluster typically survives a single node loss without restoring from backup. Replication is not a backup — it faithfully replicates a bad delete.
- Over-shard early. Choose a shard count that factorizes into your likely node
counts (e.g. a 12-shard collection rebalances cleanly across 1/2/3/4/6/12 nodes) so you can scale out without resharding. Resharding a live collection is expensive and often a managed-tier-only or manual-migration operation.
- Distributed engines run consensus (e.g. Raft) for cluster/metadata state;
understand that membership changes, snapshot transfer, and rebalancing are consensus operations that consume IO/CPU — schedule them off-peak.
- pgvector "sharding" is Postgres sharding (partitioning / Citus-style), with
all the usual relational-shard caveats — there is no vector-specific magic.
---
3. Backup / restore + disaster recovery
The single most-skipped, most-regretted area. A backup you have never restored is a rumor.
Mechanisms
| Mechanism | What it gives you | Cost / caveat |
|---|---|---|
| Snapshots | Point-in-time copy of collection/shard data + index | Per-snapshot storage; engine may pause/affect IO during capture |
| Incremental snapshots | Only changed data since last snapshot | Cheaper retention; restore chains a base + deltas |
| PITR (pgvector) | Restore Postgres to any second via WAL | Inherited free if you already run Postgres PITR |
| CDC / standby cluster | Warm replica seconds behind primary | Near-zero RPO; standby can also serve reads |
| Rebuild-from-source | Re-embed + re-index from the source corpus | Slowest RTO; the ultimate backstop — see below |
DR posture
- Define RPO (how much data you can lose) and RTO (how long to recover)
before picking a mechanism. Snapshots → minutes-to-hours RPO; CDC standby → seconds RPO; rebuild-from-source → hours-to-days RTO but near-zero data-loss if the source corpus is itself durable.
- The vector store is usually a derived store. If you retain the source
documents and their embeddings input durably (object store, OLTP), you can always rebuild — treat the vector index as a cache you can regenerate, not the system of record. This dramatically de-risks DR, but only if rebuild is rehearsed and its cost/time is known.
- Restore-test on a cadence (e.g. quarterly): restore a snapshot into an
isolated env, run a held-out recall check, confirm row counts and dimensions.
- Keep backups off the primary host / cross-region for real disaster coverage;
a snapshot on the same disk that died protects nothing.
---
4. Index build / rebuild operations
When do you pay the build cost, and where?
Build-time vs. query-time trade-off (ops framing)
- A richer graph (more neighbors / higher construction effort) → **slower, more
RAM-hungry build* but faster, higher-recall queries. The parameters live in the tuning ref; the operational fact* is that a rebuild is a heavy, memory-intensive batch job that can run for hours and contend with live traffic.
- HNSW builds are memory-intensive — they hold the graph in RAM; an
under-provisioned build OOMs or spills. Size build RAM separately from steady state.
Online vs. offline rebuild
| Strategy | Pro | Con |
|---|---|---|
| In-place rebuild on live node | Simplest | Starves production queries of CPU/RAM; anti-pattern for large indexes |
| Build offline, then swap (alias/blue-green) | No live contention; clean rollback | Window where new writes miss the building index; needs a catch-up step |
| Dual-write to old + new index | No miss window | Doubles write cost + memory during transition |
| Incremental insert (some engines / HNSW) | No big-bang rebuild | Graph quality can drift; periodic full rebuild still advisable |
Operational defaults
- For anything beyond a toy index, build off the hot path: a staging
table/collection or a replica, then atomically swap via an alias. Don't REINDEX the table production is reading from.
- Parallelize the build where the engine supports it (e.g. pgvector parallel
workers materially cut build time) — but each worker adds RAM pressure, so budget workers × per-worker memory.
- A rebuild is triggered by: parameter retune, dimensionality/model change, recall
decay, or corruption. Treat each as a planned, monitored operation, not an ad-hoc CREATE INDEX at 2pm.
---
5. Capacity planning
Get RAM right and everything else follows; get it wrong and queries silently fall off a cliff when the graph spills to disk.
RAM for HNSW (rough, verify per engine/dims)
A first-order estimate for keeping vectors in memory:
raw_vectors ≈ N × D × bytes_per_component
f32 → 4 bytes/component; int8 → 1; binary → 1 bit
graph_overhead ≈ N × M × (link size) # neighbor links + metadata
total ≈ (raw_vectors + graph_overhead) × headroom_factor # ~1.5–2× for metadata/temp segments- A common shorthand is f32 footprint ≈ N · D · 4 bytes, then ×1.5–2 for graph
+ metadata + build temporaries. Treat as an order-of-magnitude figure and measure your own.
- Graph overhead is independent of quantization — quantizing vectors to int8
shrinks the vector bytes (~4× smaller) but the neighbor-link graph stays the same size. Don't assume int8 cuts total RAM by 4×.
- When the graph exceeds RAM, every traversal hits disk and p99 explodes. The
saturation point is a cliff, not a slope — alert before you reach it.
Quantization for footprint (ops view)
| Mode | Approx. RAM vs. f32 | Trade |
|---|---|---|
| f32 | 1× (baseline) | Highest recall, highest RAM |
| int8 (scalar) | ~¼ of vector bytes | Small recall hit; common production default |
| binary (1-bit) | drastic reduction | Large recall hit; usually paired with a rescoring pass |
Quantization is a capacity lever, not free — it trades recall for footprint. Validate recall on a held-out set after enabling it (see §7). Disk and the source corpus also need planning; the index is only one tier.
---
6. Embedding-model serving
The vector store is half the system; the embedder that turns text into vectors is the other half, and it has its own ops profile.
Self-host vs. API
| Axis | Self-host (vLLM / TEI / TGI / TensorRT-LLM …) | Managed API |
|---|---|---|
| Cost at scale | Lower $/token at high, steady volume | Pay-per-call; cheap at low/bursty volume |
| Latency control | You own batching, hardware, SLO | Subject to provider latency & limits |
| Ops burden | GPU fleet, autoscaling, upgrades, on-call | Provider runs it |
| Data residency | Stays in your boundary | Leaves your boundary |
| Cold start | You manage warm pools | Provider's problem |
Serving guidance
- Batch for throughput. Embedding is embarrassingly batchable; dynamic/inflight
batching on a GPU server (TEI, vLLM, TensorRT-LLM) lifts throughput several-fold over one-at-a-time calls. Separating tokenization from inference (pipeline the two stages) is a known throughput win.
- Quantize the serving model (int8/fp8/bf16) to raise throughput and cut GPU
RAM, after confirming embedding quality holds on your eval set.
- Set a latency SLO and a fallback. Self-hosting an embedder with no SLO and no
fallback is an availability time-bomb: a GPU node dies and ingestion + query embedding both stall. Always have a fallback model/provider (even a slower hosted API) and a circuit breaker.
- Pin the embedding model version and record it alongside every vector —
query-time and index-time embeddings must come from the same model or recall collapses (see §8 versioning).
Throughput multipliers between serving stacks (TEI vs. vLLM vs. TensorRT-LLM)
move with every release and depend heavily on GPU + sequence length — benchmark
on your workload, don't trust a blog's headline number.
---
7. Monitoring & alerting
You cannot operate what you don't measure. Vector infra needs both systems metrics and quality metrics — the latter is the one teams forget.
Signals to track
| Category | Metric | Why / alert on |
|---|---|---|
| Latency | query p50 / p95 / p99 | SLA baseline is usually p95 or p99; alert on sustained breach |
| Quality | recall@k vs. held-out set | Catches silent retrieval rot; alert on drift below threshold |
| Quality | mean/variance of top-k similarity scores over time | Cheap drift proxy — falling mean / rising variance = degrading |
| Capacity | index size / RAM resident vs. host RAM | Alert before the graph spills to disk |
| Saturation | CPU, RAM, disk IO, GPU util (embedder) | Classic saturation alerts |
| Throughput | queries/s, ingest/s, embed batch latency | Capacity trend + regressions |
| Replication | replica lag, shard health, consensus state | Detect split-brain / failover readiness |
Quality drift (the hard one)
- Keep a golden held-out eval set (queries with known-relevant docs) and run
recall@k on a schedule. A drop means something shifted: corpus distribution, embedding model, index params, or data corruption.
- Watch the similarity-score distribution of live queries as a no-labels proxy
— it's cheaper than a labeled set and catches gross drift early.
- Drift sources: data distribution shift, an embedding-model change, index
degradation from heavy incremental inserts. Diagnose before you reach for a full re-embed (which is the expensive hammer).
---
8. Rollout & versioning of indexes
Treat an index like a deployable artifact, not a mutable blob.
- Alias / blue-green indexes. Name indexes with
model_version + date
(e.g. docs_v2_2026_06) and point a stable alias at the live one. Promote by flipping the alias; roll back by flipping it back. Mutating in place destroys your rollback target — anti-pattern.
- Model upgrades need a re-embed. A new embedding model = new vector space;
v1 and v2 vectors are not comparable. Options, cheapest-RTO last:
- Dual-index serving during transition (run v1 + v2, route by doc age or
cohort, sunset v1 only after v2 wins in production).
- Rolling reindex (re-embed by activity/recency over a window).
- Full re-embed + swap (simplest mental model, highest compute cost).
- Carry the model version in metadata on every vector so you can audit which
embedder produced it and detect mixed-version contamination.
---
9. Cost optimization levers
Ordered roughly cheapest-to-apply first:
1. Quantize vectors (int8/binary) → less RAM/disk, smaller (cheaper) nodes. 2. Right-size replication factor — RF=3 triples storage; use 2 unless availability math demands more. 3. Tier storage — keep hot vectors in RAM, push cold/archival to disk-backed or on-demand tiers where the engine supports it. 4. Batch embedding to maximize GPU/throughput per dollar; avoid one-call-per-doc. 5. Self-host the embedder only at sustained high volume — below the break-even, a pay-per-call API is cheaper and has no idle GPU bill. 6. Use DR/standby for reads — route batch/analytics or low-priority reads to the standby so the DR box isn't idle insurance. 7. Cap index growth — TTL/prune stale vectors; an unbounded index is unbounded RAM spend (see anti-patterns).
---
10. Multi-tenant operational isolation
When many tenants share one cluster, isolation is an ops + cost problem, not just a security one (security boundary lives in the architecture/security refs).
- Logical isolation — namespaces / partitions / per-tenant filters in a shared
collection. Cheapest; scales to many tenants; risks the noisy-neighbor problem (one heavy tenant degrades everyone and forces the whole cluster to scale).
- Physical isolation — dedicated shard/replica/cluster per tenant. Strong
isolation and per-tenant SLA, but worst density/cost and operationally heavy.
- Tiered / hybrid — keep most tenants in a shared pool, promote a large or
latency-sensitive tenant to a dedicated shard on demand. Best density-vs-isolation balance; increasingly the recommended pattern.
- Guardrails regardless of model: per-tenant rate limiting, **priority
queues, and quotas** so no single tenant monopolizes CPU/RAM or triggers cluster-wide autoscaling on everyone else's bill.
---
Runbook checklist (pre-prod / steady-state)
Before going live
- [ ] Backup mechanism chosen, automated, and a restore actually rehearsed
- [ ] RPO/RTO written down and matched to the backup/DR mechanism
- [ ] Replication factor ≥ 2 (or documented justification)
- [ ] RAM sized for vectors + graph + build headroom; alert set below spill point
- [ ] Index rebuild runs off the hot path (staging/replica + alias swap)
- [ ] Embedding model version pinned and stored in vector metadata
- [ ] Embedder has a latency SLO + fallback model/provider + circuit breaker
- [ ] Golden held-out recall eval wired into monitoring
- [ ] p50/p95/p99, index size, replica lag, saturation dashboards + alerts live
- [ ] Index uses alias/blue-green naming for swap & rollback
- [ ] Multi-tenant rate limits / quotas in place (if shared cluster)
On a cadence
- [ ] Restore-test from backup into an isolated env (e.g. quarterly)
- [ ] Recall@k vs. golden set reviewed for drift
- [ ] Capacity trend reviewed vs. RAM ceiling; plan shard/quantize before the cliff
- [ ] Stale-vector pruning / TTL confirmed working
---
Anti-patterns
1. No backups / no DR. Replication is not a backup; it replicates your mistakes. A snapshot never restore-tested is a rumor. 2. Rebuilding the index on the live node. A multi-GB, multi-hour, RAM-hungry build contending with production queries — build offline and swap. 3. No recall monitoring. Tracking only latency lets retrieval quality rot silently; users get worse answers and your dashboards stay green. 4. Unbounded index growth. No TTL/pruning → RAM creeps until the graph spills to disk and p99 falls off a cliff overnight. 5. Self-hosting an embedder with no latency SLO / no fallback. One GPU node dies and both ingestion and query-embedding stall with no escape hatch. 6. Mutating an index in place with no alias/versioning → no rollback target when a rebuild or model swap goes wrong. 7. Mixing embedding-model versions in one index → silent recall collapse from incompatible vector spaces. 8. Assuming quantization quarters total RAM. Graph overhead doesn't shrink; only the vector bytes do — and recall drops, so validate it. 9. Running two databases (OLTP + dedicated vector) before one actually can't cope. The second system is permanent ops cost, not a free performance upgrade. 10. Ignoring the noisy neighbor in shared multi-tenant clusters — no per-tenant rate limits/quotas means one tenant scales the bill for all.
---
Cross-references (read, don't duplicate): retrieval mechanics → `../../../../development/ai/ai-engineer/references/rag-patterns.md`; system topology → `../../../../architecture/solution-architect/references/rag-architecture.md`; corpus/CDC pipelines → `../../../../development/data/data-engineer/references/rag-corpus-pipelines.md`; index parameter tuning → `../../../../development/data/dba/dba/references/vector-db-tuning.md`.