Design and tune RAG pipelines end to end: chunking strategy, embeddings, hybrid retrieval with RRF, reranking, citation-enforced generation, and evaluation loops. Triggers on building a RAG system, fixing bad retrieval, choosing chunk sizes or embedding models, adding reranking, or setting up RAG evaluation.
name: "rag-pipeline-design" description: "Design and tune RAG pipelines end to end: chunking strategy, embeddings, hybrid retrieval with RRF, reranking, citation-enforced generation, and evaluation loops. Triggers on building a RAG system, fixing bad retrieval, choosing chunk sizes or embedding models, adding reranking, or setting up RAG evaluation."
RAG Pipeline Design
Purpose
Build a retrieval-augmented generation system where each layer has a defined job and a measurable quality bar. Covers the offline pipeline (ingest, chunk, embed, index), the online pipeline (retrieve, fuse, rerank, generate), and the eval loop that keeps all of it honest.
Default stance: hybrid retrieval (BM25 + dense) fused with RRF is the starting point, not a later optimization. Vector-only retrieval misses exact keyword matches; hybrid consistently outperforms either alone.
Workflow
1. Design the ingestion pipeline (offline)
Load documents -> clean and dedupe -> chunk -> embed -> index. Each chunk gets a stable ID and metadata: source, section, timestamp, tenant_id, and a content hash for idempotent re-ingestion.
- Chunk boundaries must be deterministic: same input, same chunks, same IDs. Non-deterministic chunking misaligns embeddings on reindex.
- Chunking strategy per document type, not one size for everything. See
references/chunking-strategies.md.
- Default starting point: recursive separator splitting (paragraphs -> sentences -> words), 512 tokens, 10-20% overlap for prose; 256 tokens for code or narrative text. Chunk size is a hyperparameter, not a constant: confirm it on your eval set.
- The embedding model used at index time MUST be the same one used at query time. Keep the model behind an abstraction layer so it can be swapped; pick by benchmark on your own domain, not leaderboard vibes.
2. Build the retrieval path (online)
Query -> enrich -> dense search + BM25 search (parallel) -> fuse -> rerank -> filter -> generate.
- Retrieve top-20 from each channel. Fuse with Reciprocal Rank Fusion:
score(d) = sum over lists of 1 / (k + rank(d)), ranks 1-indexed, k=60 (Cormack, Clarke, Buettcher, SIGIR 2009). Items absent from a list contribute zero. RRF discards raw scores, so BM25's unbounded scale and cosine's 0-1 scale never need calibration.
- Rerank the fused top-20 with a cross-encoder (Cohere Rerank, bge-reranker, or similar) and keep top-5.
- Apply metadata filters (tenant, date range, source) BEFORE fusion when the filter is a hard constraint. Enforce tenant isolation in retrieval, not in the prompt.
- Budget the context: dedupe near-duplicate chunks, cap total context tokens, and leave room for the model to think. Never hand the generator 40 chunks and hope.
Query enrichment (cheap, high leverage): expand abbreviations and synonyms before embedding, e.g. "max dose" -> the enriched form with the drug name and context. A bare query is the worst possible retriever input.
3. Enforce citation discipline in generation
See references/citation-discipline.md. The system prompt requires:
- Every factual claim in the answer must carry a citation marker pointing to a retrieved chunk ID.
- No citation, no claim. If the context does not contain the answer, the system says it does not know. Refusal is a feature.
- Conflicting sources get acknowledged with both cited. Never silently pick one.
- The generator must not use its own parametric knowledge for domain facts. Connecting tissue between cited facts (causal links, summaries, "therefore") is itself generated, so treat it as a claim, not a fact.
Post-generation verification (high stakes): verify citations deterministically in code — each marker must exist in the retrieved chunk set — before trusting the LLM. A second-model claim check (decompose into atomic claims, verify each against context) is the heavier option.
4. Run the eval loop
See references/eval-loop.md. Minimum viable eval:
- Keep a fixed set of golden questions with known-good answers.
- Measure per release: Faithfulness (supported claims / total claims in answer), Context Precision (relevant retrieved chunks / total retrieved), Context Recall (ground-truth facts found), Answer Relevancy (answer actually answers the question).
- Re-score the golden set every time the index, chunking, embeddings, or model changes. No re-score, no deploy.
- Tune top-K and the rerank cutoff on eval data, not on gut feel.
- Monitor retrieval and generation independently in production: log which chunks were retrieved per query, the similarity score distribution, and which chunks got cited vs ignored.
5. Plan freshness
- Reindex on a schedule that matches the domain: daily for docs, hourly for real-time content.
- Re-embed the whole corpus when the embedding model changes.
- Track embedding drift: if query-to-chunk similarity distributions shift over months, the index is going stale.
Output Contract
A finished RAG design produces:
ChunkConfig for each document type: strategy, size, overlap, separators, metadata schema.
- Retrieval architecture: channel list, fusion method and parameters (RRF k), candidate counts per stage, reranker choice, metadata filter rules.
- Grounding contract: the system prompt citation rules, refusal behavior, conflict handling, and the verification step.
- Eval plan: golden question set, metrics and thresholds, re-score triggers, monitoring dashboards.
- Freshness plan: reindex cadence, re-embed triggers, drift checks.
Operating Rules
- When retrieval quality is bad, fix chunking and embeddings first, then retrieval, then prompts. Prompt engineering moves quality last, not first.
- Never invent benchmark numbers, recall figures, or "typical improvement" claims for a design. Report measured numbers from the eval set or state that a value is an unvalidated starting point.
- Every chunk ID cited in a generated answer must resolve to a chunk actually retrieved for that query. Markers that point elsewhere get stripped or the answer gets rejected.
- Chunk size, overlap, top-K, and RRF k are hyperparameters. Write them into a config file, version the config, and re-evaluate after every change.
- Dense and sparse channels run in parallel and fuse by rank. Never mix raw scores from different scoring scales in one weighted sum without normalization.
- Keep the source documents authoritative: the index is a derived artifact. When a source document changes, re-chunk and re-embed from the source, never patch the index.
- Enforce authorization at retrieval time. A generator prompt that says "don't show the user this chunk" is not access control.
No ratings yet — be the first to rate it.