Building Production-Ready RAG Pipelines: What the Tutorials Don't Tell You
Most RAG tutorials get you to a demo in 50 lines of code. None of them survive contact with real users. Here's what actually breaks — and how to fix it before it does.
The 50-line lie
Every RAG tutorial follows the same script: load a PDF, chunk it, embed it, stuff it into a vector store, retrieve top-K, pass to LLM. Demo works. You ship it. A week later your users are complaining that it confidently invents answers, can't find obvious information, and somehow gives a different answer to the same question on Tuesday than it did on Monday.
Welcome to production RAG. Here's what the tutorials skip.
Problem 1: Chunking destroys context
Naive 500-token chunks split mid-sentence, mid-table, mid-paragraph. The chunk that contained the answer is now half the answer, sitting next to a chunk that contains the other half — and your retriever picks neither.
Fixes that work:
- Semantic chunking: split on natural boundaries (headings, paragraphs, code blocks)
- Sliding windows with overlap: 20% overlap catches answers that span boundaries
- Document-aware chunking: tables stay as tables, code stays as code
- Parent-child chunking: embed small chunks for precision, retrieve the larger parent for context
LlamaIndex's SentenceWindowNodeParser is a solid starting point. Most teams build their own.
Problem 2: Vector search alone is not enough
Dense embeddings are great at semantic similarity. They're terrible at keyword precision. Ask "what's the 2024 API rate limit?" and a vector search might return docs about rate limits from 2019 because the embedding distance is small.
The fix: hybrid retrieval.
# Hybrid scoring: 0.7 vector + 0.3 BM25
final_score = 0.7 * vector_score + 0.3 * bm25_score
Then re-rank the top 50 with a cross-encoder (e.g., cohere/rerank-3 or bge-reranker-v2-m3) down to top 5. Cross-encoders are slower per pair but you're only ranking 50, not embedding millions. The quality jump is significant — often 20-30 points on retrieval precision in our internal evals.
Problem 3: You have no idea if your changes are improvements
This is the one nobody talks about. You tweak chunk size, retrieval K, or the prompt. The demo "feels better." Did it actually improve? You don't know, because you have no eval set.
Build evals on day one:
- 30-50 representative questions from real or synthetic users
- Expected answers (or expected source documents)
- Score retrieval (was the right doc in top-K?) and generation (was the answer correct?) separately
- Track scores on every change
Frameworks: Ragas, TruLens, Langfuse evals. Honestly a spreadsheet works fine for the first month.
Problem 4: Hallucinations under retrieval failure
If retrieval returns nothing relevant, most RAG systems happily hallucinate a confident-sounding answer. This is the single biggest source of user trust collapse.
Fixes:
- Retrieval confidence threshold: if no chunk scores above 0.7, refuse to answer
- Cite or refuse: prompt the model to cite the chunk it's using. If it can't cite, it shouldn't answer.
- Adversarial eval set: questions whose answer is NOT in your corpus. Track refuse rate.
Problem 5: Latency creeps in silently
A single RAG query in production touches: embedding API, vector DB, optional re-ranker, generation API. Each is 100-2000ms. Stack them and you're at 5+ seconds.
- Cache embeddings of user queries (a lot of users ask the same things)
- Use smaller embedding models where quality permits (
text-embedding-3-smallis often enough) - Stream generation so users see tokens immediately
- Pre-compute retrievals for predictable queries
Problem 6: Stale data
Your corpus changed three weeks ago. Your vector store hasn't. Users are getting answers based on old info.
Set up an indexing pipeline from day one — even if it's a cron job that re-indexes nightly. Track last_indexed_at per document. Surface it in your eval reports.
What good production RAG actually looks like
A real production RAG system, end-to-end:
- Query rewriting (decompose multi-part questions, expand abbreviations)
- Hybrid retrieval (dense + sparse)
- Cross-encoder re-ranking
- Context compression (remove irrelevant chunks before passing to LLM)
- Citation-required generation
- Confidence-based refusal
- Streaming output
- Logged everything for evals
That's not 50 lines. It's usually 2,000+ lines and a week of tuning per significant change.
TL;DR
RAG demos are easy. RAG products are hard. The gap is evals, hybrid retrieval, re-ranking, and refusal logic. Build those first, and the rest is mostly fine-tuning.
If you want to build this end-to-end with mentorship and a real project portfolio, our Applied GenAI programs walk you through exactly this stack.