Series · Production AI Notes
Real-time vector ingestion is a data platform problem
Fresh retrieval depends on unglamorous infrastructure: Kafka backpressure, idempotent upserts, embedding retries, DLQs, and freshness metrics.
- Vector Search
- Kafka
- RAG
- Data Engineering
Most RAG demos begin after the hard part has already happened. The documents are clean, embedded, chunked, and sitting in a vector database. Then the demo asks a question and retrieves the right context.
Production is not that tidy.
Documents arrive continuously. Some are duplicates. Some are malformed. Embedding providers throttle. A deploy changes chunking. The vector database slows down. Someone asks why the assistant missed a document that was updated five minutes ago.
That is the moment you realize vector ingestion is not a side script. It is a data platform problem.
Freshness is a user-facing feature
If retrieval is stale, the model can look wrong even when generation is behaving perfectly. That makes freshness a product concern, not just an internal metric.
For a streaming ingestion path, I care about:
- Time from document event to searchable vector
- Kafka consumer lag
- Embedding latency and error rate
- Upsert latency into pgvector
- DLQ volume by failure reason
- Duplicate-event rate
The nice thing about these metrics is that they give support and product teams a real answer. “The model is bad” becomes “the document was not searchable yet” or “the embedding provider was throttling for nine minutes.”
Idempotency is the boring superpower
Duplicate events happen. Retries happen. Workers crash after embedding but before the database write. If every retry creates another vector row, search quality quietly decays.
The ingestion path needs a stable document ID, a chunk ID, a content hash, and an upsert strategy. Reprocessing should converge on the same state. That sounds obvious, but it is the difference between a system you can replay and a system you are afraid to touch.
Backpressure beats optimism
Embedding providers and vector databases both have limits. Pretending otherwise only moves the failure downstream.
I prefer the consumer to slow down intentionally when embedding latency or upsert latency crosses a threshold. Kafka gives you a natural buffer. Use it. A controlled lag is better than a storm of retries that makes every component look unhealthy.
DLQs need context
A dead-letter queue that only stores the failed payload is better than losing the event, but not by much. The retry path needs enough context to make the failure actionable:
- Which validation failed?
- Which provider failed?
- Was the error permanent or transient?
- How many times has this event been retried?
- Which ingestion version processed it?
Without that metadata, the DLQ becomes a graveyard. With it, the DLQ becomes an operations surface.
The takeaway
RAG quality starts before retrieval. If the ingestion path is stale, lossy, duplicate heavy, or invisible, the model will inherit those failures and get blamed for them.
Treat vector ingestion like a streaming data platform. Your retrieval system will be calmer, your evaluations will be more honest, and your production incidents will be much easier to explain.