Build an Embeddings Pipeline

Khimananda Oli 8 min read Virtualization
Build an Embeddings Pipeline

By Khimananda Oli | Last reviewed: August 2026

Most teams fail when they build an embeddings pipeline not because the math is wrong, but because the data engineering is fragile. You cannot treat semantic search as a simple API call; it requires a disciplined ETL workflow that handles dirty text, schema drift, and versioned models. This guide bridges the gap between theoretical understanding of tokens and context windows and shipping a resilient system that actually improves retrieval accuracy in production.

Raw SourcesPDFs, DBs, APIsConfluence, S3ProcessingClean & ChunkEmbed ModelVector StoreIndex + MetadataVersion TagsRetrievalHybrid SearchRerankingEnd-to-End Embeddings Pipeline ArchitectureDecoupled stages allow independent scaling and model swapping without full re-indexing
Core architecture required to build an embeddings pipeline that scales beyond prototype stage

How do you design data ingestion and chunking for an embeddings pipeline?

The most common failure mode when engineers build an embeddings pipeline is naive chunking. Splitting text by character count or paragraph breaks destroys semantic coherence. If a chunk contains half a sentence or mixes two unrelated topics, the resulting vector represents neither concept accurately. Your retrieval quality is capped by your worst chunk.

Semantic vs. Fixed-Size Chunking

Fixed-size chunking (e.g., 512 tokens with 50-token overlap) is acceptable for prototyping but insufficient for production documentation or legal texts. Semantic chunking uses a lightweight NLP model or heuristic to detect topic shifts. In practice, I recommend a hybrid approach: use structural boundaries (headers, list items) as primary split points, then apply token limits only within those structures.

  • Recursive Character Splitting: Tries separators in order (\n\n, \n, ., space). Better than fixed size but still blind to meaning.
  • Document-Aware Splitting: Uses Markdown headers, HTML tags, or PDF layout analysis to respect document structure.
  • Semantic Similarity Splitting: Computes embedding similarity between adjacent sentences; splits where cosine distance exceeds a threshold. Computationally expensive but highest quality.
  • Agentic Chunking: Uses an LLM to propose chunk boundaries based on content. Best quality, highest cost/latency.
<!-- Example: LangChain RecursiveCharacterTextSplitter configuration -->
from langchain.text_splitter import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
    chunk_size=512,
    chunk_overlap=64,
    length_function=len,
    separators=["\n## ", "\n### ", "\n\n", "\n", ". ", " "]
)

# For structured docs, prefer MarkdownHeaderTextSplitter first
docs = splitter.split_documents(raw_docs)

Always preserve metadata during chunking. Every chunk must carry source_file, page_number, header_path, and last_modified timestamps. Without this, you cannot implement citation, filtering, or incremental updates later. When you build a RAG chatbot, missing metadata makes debugging hallucinations nearly impossible.

Which embedding model should you choose for production workloads?

Model selection dictates your vector dimension, storage costs, and retrieval ceiling. Do not default to OpenAI's text-embedding-3-small without evaluation. The Massive Text Embedding Benchmark (MTEB) leaderboard is the industry standard for comparison, but filter it by your specific task (retrieval, STS, classification) and language.

ModelDimensionsMTEB Retrieval AvgMax TokensBest ForLicensing
nomic-embed-text-v1.576856.88192Self-hosted, multilingualApache 2.0
bge-m3102459.28192Multilingual, dense+sparseMIT
text-embedding-3-large3072 (matryoshka)64.38191High-accuracy SaaSProprietary
gte-Qwen2-7B-instruct358467.132768Long-context, top-tierApache 2.0
e5-mistral-7b-instruct409666.532768Instruction-tuned retrievalMIT

For teams in Nepal or regions with high latency to US/EU API endpoints, self-hosted models like bge-m3 or nomic-embed-text eliminate network round-trips during ingestion. They also remove vendor lock-in and data residency concerns. If you are evaluating infrastructure trade-offs, read our comparison on vector databases for RAG to align model dimensions with storage backend capabilities.

Matryoshka Representation Learning

Modern models support Matryoshka embeddings, allowing you to truncate vectors to lower dimensions (e.g., 3072 → 1024 → 256) with minimal quality loss. This is critical for cost optimization: index full-precision vectors for high-value queries, but use truncated versions for bulk preprocessing or low-stakes search. Always validate truncation impact on your specific dataset before deploying.

Raw TextNormalize UTF-8ChunkerSemantic BoundariesBatch QueueRate Limit AwareEmbed ModelGPU / APIVectors+ MetadataError Handling & Retry LogicExponential Backoff • Dead Letter Queue • Idempotency KeysPartial Failure Recovery • CheckpointingCritical Processing StepsNever embed without batching, rate limiting, and checkpoint-based recovery
Processing flow with error handling when you build an embeddings pipeline for production reliability

How do you handle batch processing, rate limits, and failures?

Embedding generation is the bottleneck. Whether calling an external API or running local GPUs, you must treat it as a constrained resource. Naive sequential processing will either get you rate-limited or waste 90% of GPU capacity. Production pipelines require three non-negotiable patterns.

  1. Dynamic Batching: Group texts by token length to minimize padding waste. Most embedding libraries (sentence-transformers, litellm) handle this automatically, but verify max_batch_size against your GPU memory or API tier limits.
  2. Checkpointing: Never re-process completed chunks on restart. Store processing state (chunk_id → vector_id mapping) in a durable store separate from the vector DB. Use content hashes as idempotency keys so duplicate inputs produce identical outputs.
  3. Graceful Degradation: Separate transient errors (429, 503) from permanent ones (400, invalid input). Transient errors get exponential backoff with jitter. Permanent errors go to a dead-letter queue for manual inspection. Never let one bad document halt the entire pipeline.
# Pseudocode for resilient batch embedding
async def embed_with_retry(chunks, max_retries=5):
    for attempt in range(max_retries):
        try:
            vectors = await embedding_api.embed_batch(chunks)
            save_checkpoint(chunks, vectors)
            return vectors
        except RateLimitError as e:
            wait = min(2 ** attempt + random.uniform(0, 1), 60)
            logger.warning(f"Rate limited, waiting {wait:.1f}s")
            await asyncio.sleep(wait)
        except ValidationError as e:
            log_dead_letter(chunks, e)
            return None  # Skip bad chunks, don't retry
    raise MaxRetriesExceeded("Embedding failed after retries")

If you are self-hosting models, monitor GPU utilization and memory fragmentation. Embedding workloads are memory-bandwidth bound, not compute-bound. Using FP16 or INT8 quantization often doubles throughput with negligible quality loss for retrieval tasks.

What evaluation metrics prove your embeddings pipeline works?

You cannot improve what you do not measure. Many teams deploy embeddings pipelines and judge success by "vibes." This is unacceptable for production systems. Establish quantitative baselines before launch and track them continuously.

Offline Evaluation Metrics

  • Recall@K: Percentage of relevant documents appearing in top-K results. More important than precision for retrieval (you can rerank later).
  • NDCG@K: Normalized Discounted Cumulative Gain. Accounts for ranking position — relevant doc at position 1 scores higher than position 5.
  • MRR: Mean Reciprocal Rank. Simple metric for question-answer scenarios where only the first correct result matters.
  • Latency Percentiles: p50, p95, p99 end-to-end query time. Embedding lookup should be <50ms p95 for interactive applications.

Online Monitoring

Track user behavior signals: click-through rate on retrieved results, "regenerate" button frequency, explicit thumbs-up/down feedback. These are your ground truth. Set up alerts for regression: if Recall@10 drops more than 5% after a model update or data refresh, auto-rollback. Integrate these signals into your broader LLMOps monitoring strategy to catch drift early.

Query Latency (ms) →Recall@10 ↑pgvectorLow CostQdrantBalancedPineconeManaged ScaleWeaviateHybrid NativePerformance vs. Operational Complexity TradeoffsHigher latencyHigher recall
Tradeoff visualization to inform decisions when you build an embeddings pipeline and select storage backends

How do you manage model versions and incremental updates?

Embeddings are not static. Models improve, data changes, and schemas evolve. A pipeline that cannot handle updates without full re-indexing will become unmaintainable within months. Treat your vector index like any other production artifact: versioned, reproducible, and rollback-capable.

Versioning Strategy

Tag every vector with model_version and data_schema_version. When upgrading models, create a new collection or namespace rather than overwriting. Run shadow traffic against both versions, compare metrics, then promote. This zero-downtime approach mirrors blue-green deployments in traditional DevOps.

For incremental updates, use content hashing. Before embedding a chunk, compute SHA-256(text + metadata). Query the vector store for existing hash. Only embed and upsert if hash differs. This reduces reprocessing costs by 80–95% for frequently updated documentation sets. Combine with soft deletes (is_active flag) rather than hard deletes to maintain audit trails for compliance frameworks like SOC 2 or ISO 27001.

Production Readiness Checklist

Shipping a reliable system to build an embeddings pipeline requires discipline beyond the core algorithm. Verify these items before going live:

  • Evaluation dataset with ≥200 labeled query-document pairs representative of production traffic
  • Automated regression tests running on every model or config change
  • Observability: trace IDs propagated from ingestion through retrieval, latency histograms, error rates by chunk type
  • Cost projections validated against real usage patterns (API tokens, GPU hours, storage GB)
  • Data retention and deletion policies implemented and tested
  • Runbook documenting re-indexing procedure, rollback steps, and escalation paths

If your team needs help architecting or auditing an embeddings pipeline for production, reach out to discuss your specific requirements. Getting the foundation right prevents costly rewrites six months down the line.

Frequently Asked Questions

You need a vector database like Qdrant or Weaviate, an embedding model such as nomic-embed-text-v2, and an orchestration tool like Apache Airflow or Prefect for scheduling batch jobs reliably.

Costs vary by volume. Self-hosted open-source models on GPU instances run fifty to two hundred dollars monthly, while managed API services charge per token, often totaling less for low-volume prototypes but scaling linearly with usage.

Yes. CPU inference works for small batches using quantized ONNX models. For production scale, use serverless GPU providers or managed embedding APIs to avoid hardware provisioning delays and maintenance overhead entirely.

Select based on your domain and language. General-purpose tasks suit nomic-embed-text-v2 or bge-m3. Code-specific pipelines benefit from starcoder2-embeddings. Always benchmark retrieval accuracy on your actual dataset before committing infrastructure resources to a specific model version.

Version your collection schemas explicitly. When adding fields, create a new collection and backfill existing vectors. Never modify live schemas in place, as this breaks downstream search queries and causes silent data inconsistencies during incremental sync operations.

Use semantic chunking over fixed-size splits. Tools like LangChain SemanticChunker preserve context boundaries. For technical docs, chunk by headers or paragraphs. Always include metadata like source file and section title to enable filtered retrieval and debugging.

Encrypt vectors at rest using AES-256 and enforce TLS in transit. Apply row-level access controls in the vector database. Never embed PII directly; hash or redact sensitive fields before ingestion and store references separately in a secured relational store.

Check chunk size, overlap settings, and model alignment. Mismatched domains cause poor recall. Validate with a labeled test set using metrics like NDCG@10. Also verify metadata filters are not accidentally excluding relevant documents during query time.

Track ingestion latency, error rates, and vector count drift using Prometheus and Grafana. Alert on failed batches and stale collections. Log embedding dimensions and model versions per batch to detect silent regressions caused by upstream dependency updates or config changes.

Batch processing suits historical data and nightly syncs due to higher throughput and lower cost. Real-time embedding is necessary for user-generated content requiring immediate searchability. Many pipelines combine both: batch for backfill, streaming for incremental updates via message queues.

Cache frequent queries with Redis, use approximate nearest neighbor indexes like HNSW, and precompute embeddings for static content. Optimize model inference with TensorRT or ONNX Runtime. Place vector databases in the same region as your application servers to minimize network round trips.

Re-embed all existing content or maintain dual collections during transition. New model versions produce incompatible vector spaces. Implement a canary deployment: route a percentage of queries to the new index, compare relevance metrics, then fully migrate once validated against business KPIs.

Create a golden dataset with known query-document pairs. Measure recall, precision, and MRR. Run integration tests that verify end-to-end flow from ingestion to retrieval. Automate regression checks in CI to catch breaking changes in chunking logic or model configuration early.

Yes, pgvector supports HNSW indexing and scales to millions of vectors. It simplifies architecture by combining relational and vector data. However, dedicated vector databases offer better performance at scale and advanced features like multi-tenancy and native filtering for complex embeddings pipelines.

Use multilingual models like bge-m3 or multilingual-e5-large that align languages in shared vector space. Normalize text encoding to UTF-8. Store language metadata per chunk to enable language-aware filtering. Test cross-lingual retrieval separately, as performance varies significantly between language pairs and domains.