Every essential RAG pattern for production systems in one place. Covers document processing, embeddings, vector stores, retrieval strategies, generation patterns, advanced architectures like agentic RAG and self-RAG, plus evaluation with RAGAS. Copy-paste these Python examples and build reliable retrieval-augmented generation pipelines.
| Name | Syntax | Description |
|---|---|---|
| Basic RAG Pipeline | load -> chunk -> embed -> store -> retrieve -> generate | The core RAG loop: ingest documents, split into chunks, embed, store in a vector database, retrieve relevant chunks at query time, and generate an answer with context. |
| Chunking | RecursiveCharacterTextSplitter(chunk_size, chunk_overlap) | Split documents into smaller pieces for embedding. Chunk size and overlap control the granularity and continuity of retrieval units. |
| Embedding | model.encode(texts) -> List[List[float]] | Convert text into dense vector representations. Use the same model for both indexing documents and encoding queries. |
| Vector Search | collection.query(query_embedding, n_results=5) | Find the most similar document chunks to a query by comparing embedding vectors using cosine similarity or L2 distance. |
| Re-Ranking | CrossEncoder(model).predict([(query, doc) for doc in docs]) | Score and re-order retrieved documents using a cross-encoder model for higher precision than vector similarity alone. |
| Hybrid Search | alpha * vector_score + (1 - alpha) * bm25_score | Combine dense vector search with sparse keyword search (BM25) for better recall on both semantic and exact-match queries. |
| Multi-Query RAG | generate_queries(question) -> [q1, q2, q3] -> union(results) | Generate multiple query variations with an LLM, retrieve for each, and merge results to improve recall on ambiguous questions. |
| Agentic RAG | agent.run(query, tools=[retriever, web_search, calculator]) | An LLM agent that decides when and how to retrieve, can reformulate queries, and chains multiple retrieval steps together. |
| Evaluation Metrics | evaluate(dataset, metrics=[faithfulness, relevancy, precision]) | Measure RAG quality with metrics like faithfulness (grounded in context), answer relevancy, and context precision using frameworks like RAGAS. |
| Semantic Caching | cache.lookup(query_embedding, threshold=0.95) | Cache RAG responses keyed by query embedding similarity to avoid redundant retrieval and generation for semantically identical questions. |
CharacterTextSplitter(chunk_size=1000, chunk_overlap=200)The simplest chunking strategy: split text into fixed-size windows with overlap to preserve context across chunk boundaries.
Tips
RecursiveCharacterTextSplitter(chunk_size, separators=[...])Recursively splits using a hierarchy of separators (paragraphs first, then sentences, then words). Respects document structure better than fixed-size splitting.
Tips
SemanticChunker(embeddings, breakpoint_threshold_type)Groups consecutive sentences into chunks based on embedding similarity. Creates semantically coherent chunks rather than arbitrary size-based splits.
Tips
Document(page_content, metadata={source, page, title, ...})Parse documents from various formats and attach metadata for filtering during retrieval. Metadata like source, page number, and custom tags enable precise scoped search.
Tips
SentenceTransformer(model_name).encode(texts)Generate embeddings with open-source models from sentence-transformers. Normalize embeddings for cosine similarity and batch-encode for efficiency.
Tips
chroma_client.get_or_create_collection(name)Use ChromaDB as a lightweight vector store with built-in embedding support and metadata filtering. Great for prototyping and small-to-medium datasets.
Tips
CREATE INDEX ON items USING ivfflat (embedding vector_cosine_ops)Use pgvector to add vector similarity search to PostgreSQL. Ideal when you already use PostgreSQL and want to avoid a separate vector database.
Tips
qdrant_client.search(collection_name, query_vector, limit)Qdrant is a production-grade vector database with rich filtering, payload indexing, and horizontal scaling. Use it for large-scale RAG deployments.
Tips
vectorstore.similarity_search_with_score(query, k, score_threshold)Retrieve documents by vector similarity with optional score thresholds to filter out irrelevant results. Always set a threshold in production to avoid returning noise.
Tips
EnsembleRetriever(retrievers=[bm25, vector], weights=[0.4, 0.6])Combine BM25 keyword search with vector similarity for hybrid retrieval. BM25 catches exact term matches that vector search may miss, and vice versa.
Tips
CrossEncoder(model).predict([(query, doc) for doc in candidates])Re-rank retrieved candidates with a cross-encoder for higher precision. Cross-encoders jointly attend to the query and document, producing more accurate relevance scores than bi-encoder similarity.
Tips
vectorstore.max_marginal_relevance_search(query, k, fetch_k, lambda_mult)MMR selects documents that are both relevant to the query and diverse from each other. Prevents returning multiple chunks that say the same thing.
Tips
ChatPromptTemplate.from_template(template_with_context)Structure RAG prompts with explicit instructions to ground answers in retrieved context. Include citation formatting for traceability.
Tips
trim_context(docs, max_tokens, tokenizer)Manage context window limits by trimming retrieved documents to a token budget. Prevents exceeding model limits and controls cost.
Tips
extract_citations(answer, sources) -> List[Citation]Parse and verify citations from RAG-generated answers. Extract source references for traceability and enable users to verify claims against original documents.
Tips
agent = create_react_agent(llm, tools=[retriever_tool, ...])An LLM agent that decides when to retrieve, which tool to use, and can chain multiple retrieval steps. The agent reasons about when vector search alone is insufficient and takes corrective actions.
Tips
iterative retrieve -> extract entities -> retrieve again -> answerIteratively retrieve and refine context for complex questions that require connecting information from multiple documents. Each hop identifies missing information and generates targeted follow-up queries.
Tips
retrieve -> evaluate relevance -> web search fallback -> generateCorrective RAG evaluates retrieval quality and takes corrective action (query rewriting, additional retrieval) when initial results are irrelevant. Improves robustness for out-of-distribution queries.
Tips
decompose(question) -> [sub_q1, sub_q2] -> retrieve each -> mergeExpand a single query into multiple variations or decompose complex questions into sub-questions. Each variation retrieves independently, then results are merged and deduplicated for broader recall.
Tips
evaluate(dataset, metrics=[faithfulness, answer_relevancy, ...])Use the RAGAS framework to evaluate RAG pipeline quality across four dimensions: faithfulness (grounding), relevancy (answer quality), context precision, and context recall.
Tips
evaluate_rag(pipeline, test_cases) -> EvalResultsBuild a custom evaluation pipeline with LLM-as-a-judge for faithfulness and relevance scoring. Tracks latency and sources for each test case.
Tips
hit_rate, mrr, ndcg = compute_retrieval_metrics(results, ground_truth)Compute standard information retrieval metrics (Hit Rate, MRR, nDCG) to evaluate your retrieval component in isolation from generation.
Tips
A complete RAG pipeline from document ingestion to answer generation. Loads a PDF, chunks it with recursive splitting, embeds with a sentence-transformer model, stores in ChromaDB, and queries using a LangChain chain that retrieves context and generates grounded answers. This is the foundational pattern that all other RAG architectures build upon.
Combines BM25 keyword search with dense vector retrieval for broad recall, then applies a cross-encoder re-ranker for precision. The hybrid stage retrieves 10-20 candidates from each method, merges and deduplicates them, and the cross-encoder scores each (query, document) pair to produce a final top-k ranking. This two-stage approach (retrieve broadly, re-rank precisely) is the standard production pattern for high-quality RAG retrieval.
An agentic RAG system where the LLM autonomously decides which retrieval tools to call and when. Unlike basic RAG that always retrieves, the agent reasons about whether it needs documentation, code examples, or both. It can call multiple tools in sequence, reformulate queries based on initial results, and synthesize information from different sources into a coherent answer with citations. This pattern is ideal for complex questions that span multiple knowledge domains.
Chunk size too large returns unfocused context; too small loses surrounding meaning and creates fragments that lack sufficient context for the LLM
Start with 500-1000 tokens per chunk and 10-20% overlap. Evaluate with your actual queries: if answers miss details, reduce chunk size; if context lacks coherence, increase it. Tune chunk size as a hyperparameter using retrieval metrics like Hit Rate and MRR.
Using different embedding models for indexing and querying produces meaningless similarity scores because the vector spaces are incompatible
Always use the exact same embedding model (and version) for both indexing and querying. Store the model name in your vector store metadata. When upgrading the embedding model, re-embed your entire document corpus before serving queries.
Document updates and deletions are not reflected in the vector store, causing the RAG system to return stale or deleted information
Track document versions with metadata (e.g., indexed_at timestamp, doc_version). Implement an incremental indexing pipeline that detects changes, deletes old vectors by document ID, and re-indexes updated content. Schedule periodic full re-indexes as a safety net.
Ignoring metadata filtering leads to retrieving irrelevant documents from unrelated sections, departments, or document types
Attach rich metadata (source, section, date, category) during indexing. Apply metadata filters at query time to scope retrieval. For example, filter by doc_type='api_reference' for API questions. Metadata filtering is essentially free and dramatically improves precision.
Relying solely on vector similarity without re-ranking returns plausible-looking but subtly wrong documents, especially for nuanced or specific queries
Add a cross-encoder re-ranking stage after initial retrieval. Retrieve broadly (top 20-50 candidates) with vector search, then re-rank to the final top 3-5 using a cross-encoder like ms-marco-MiniLM. This two-stage approach typically improves precision by 10-20% with minimal latency increase.