Retrieval-Augmented Generation (RAG) has become the de facto architecture for grounding large language models (LLMs) in external knowledge. While building a basic RAG prototype is straightforward—connect a vector store to an LLM and query—shifting that system to production introduces a host of engineering challenges: latency, cost, reliability, retrieval accuracy, and security. This guide walks through the essential considerations and trade-offs for deploying RAG at scale.
The quality of your RAG system is bounded by the quality of your indexed data. Production indexing requires careful attention to document processing, chunking, and embedding.
Fixed-size chunking (e.g., 512 tokens with overlap) is simple but often loses semantic boundaries. Better approaches include:
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200,
separators=["\n\n", "\n", ".", " "]
)
chunks = text_splitter.split_documents(documents)
Choose embedding models that balance quality, dimensionality, and cost:
| Model | Dimensions | Pros | Cons |
|---|---|---|---|
text-embedding-3-small (OpenAI) |
|||
| 1536 | Good quality, cheap | Vendor lock-in, rate limits | |
intfloat/e5-mistral-7b-instruct |
|||
| 4096 | High accuracy | Large, slower inference | |
BAAI/bge-small-en-v1.5 |
|||
| 384 | Fast, small | Lower quality on very specific domains |
For production, consider self-hosting an embedding model (e.g., via ONNX or Triton) to reduce latency and avoid API costs, but weigh the infrastructure overhead.
The vector store is the heart of your retrieval pipeline. Key considerations:
source
, date
, or author
to pre-filter before ANN search. This drastically improves relevance.
from qdrant_client import QdrantClient
client = QdrantClient(url="https://your-cluster.qdrant.io")
client.search(
collection_name="docs",
query_vector=vector,
query_filter=Filter(must=[FieldCondition(key="date", Range(gte=1700000000))]),
search_params=SearchParams(
hnsw_ef=128,
quantization=QuantizationSearchParams(
rescore=True
)
),
limit=10
)
Simply retrieving the top-k similar vectors is rarely sufficient for production. You need a multi-stage retrieval pipeline.
ms-marco-MiniLM-L-6-v2
) to score and reorder the candidates. This adds 50–200ms but significantly improves relevance.
from sentence_transformers import CrossEncoder
reranker = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')
candidates = [
{"query": query, "text": chunk.page_content}
for chunk in top_chunks
]
scores = reranker.predict(candidates)
reranked = sorted(zip(scores, top_chunks), key=lambda x: x[0], reverse=True)
Users don’t always ask well-formed questions. Common techniques:
The LLM consumes retrieved context and generates the final answer. Here, latency, cost, and safety controls matter.
Structure the prompt to separate instructions, context, and user query. Use clear delimiters.
prompt_template = """You are a helpful assistant. Use the following context to answer the question. If you cannot find the answer, say "I don't know".
Context:
{context}
Question: {question}
Answer:"""
Cache exact queries (with expiry) to reduce LLM calls. For high-traffic scenarios, batch similar queries and use model parallelism.
Production RAG without evaluation is flying blind. You need both offline metrics and online monitoring.
Use the RAGAS framework to measure:
from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy, context_precision
result = evaluate(
dataset=test_questions,
metrics=[faithfulness, answer_relevancy, context_precision]
)
Finally, consider the operational aspects that separate demo from production.
Building a production-ready RAG application is not about a single breakthrough technique—it’s about rigorously applying best practices across the entire pipeline: careful chunking, multi-stage retrieval, intelligent LLM integration, and continuous evaluation. Start simple, measure everything, and iterate. Your users will thank you.
This guide covers the most critical aspects, but every production system evolves. Stay current with the rapidly advancing field and always test changes against representative data.