Retrieval-Augmented Generation (RAG) Workflow

Retrieval-augmented generation answers a question in two stages: first find the passages most likely to contain the answer, then have a language model write the answer using those passages as context. Retrieval gives the model current and private knowledge it was never trained on and lets the system cite sources; generation turns the retrieved fragments into a fluent, direct answer. This page describes the standard query-time workflow, the offline indexing pipeline it depends on, a minimal runnable implementation, and the design decisions that most affect answer quality.

1. Two pipelines: indexing and query

RAG indexing pipeline (offline) and query pipeline (online) Offline indexing Load docs HTML, PDF, DB rows Chunk 300-800 tokens, overlap Embed same model as queries Store FAISS ids + text DB Online query Prompt user question Embed query one vector Top-k search FAISS similarity Generate LLM with context Both pipelines must use the same embedding model, or query vectors and document vectors will not be comparable.

The workflow below describes only the online half, but its quality is mostly decided offline. How documents are split into chunks, which embedding model is used, and what metadata is stored with each chunk determine what similarity search can find. The FAISS index stores vectors and integer ids; the text itself lives in a separate store (MongoDB, Elasticsearch, SQLite, or a simple dictionary), which is why step 4 of the workflow fetches raw text by id.

Standard Workflow of RAG

  1. User Prompt
  2. Embedding Generation
  3. Similarity Search in FAISS
  4. Retrieval of Raw Text
  5. Contextual Generation

Why Similarity Search Comes First

When Text Search Might Be Used

5. Hybrid retrieval and reranking

Hybrid retrieval with rank fusion and reranking Query user question BM25 + vector two candidate lists (top 50 each) Fusion reciprocal rank fusion Rerank cross-encoder scores pairs Top 5 to LLM context window with citations Keyword search catches exact identifiers; vectors catch paraphrases; the reranker orders the union by actual relevance.

Vector search is strong on meaning and weak on exact tokens such as error codes, product SKUs, or rare names; BM25 is the opposite. Running both and merging the ranked lists with reciprocal rank fusion (score = sum of 1 / (k + rank), with k commonly 60) recovers most of the strengths of each without tuning score scales. A cross-encoder reranker then reads the query and each candidate together and produces a more accurate ordering, at higher cost, so it is applied only to the merged shortlist.

6. Worked example: minimal RAG in Python

# pip install sentence-transformers faiss-cpu numpy
import faiss
import numpy as np
from sentence_transformers import SentenceTransformer

docs = {
    0: "FAISS is a library for efficient similarity search over dense vectors.",
    1: "BM25 ranks documents by term frequency and inverse document frequency.",
    2: "MongoDB stores JSON-like documents in collections.",
}
model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")

# Offline: embed and index (normalized vectors + inner product = cosine similarity)
vecs = model.encode(list(docs.values()), normalize_embeddings=True).astype("float32")
index = faiss.IndexIDMap(faiss.IndexFlatIP(vecs.shape[1]))
index.add_with_ids(vecs, np.array(list(docs.keys()), dtype="int64"))

# Online: embed query, search, fetch text, build prompt
question = "How does vector similarity search work?"
q = model.encode([question], normalize_embeddings=True).astype("float32")
scores, ids = index.search(q, 2)
context = "\n".join(f"[{i}] {docs[i]}" for i in ids[0] if i != -1)

prompt = f"""Answer using only the context. Cite sources as [id].
Context:
{context}

Question: {question}"""
print(prompt)   # send this to any chat model API or a local model

The generation call is left out on purpose: any hosted or local model works, and the prompt is where the important behaviour is set. Instructing the model to answer only from context and to cite ids makes unsupported answers easier to detect.

7. Design choices and trade-offs

ChoiceSmaller / simplerLarger / more complex
Chunk sizePrecise matches, may lose surrounding contextMore context per hit, noisier similarity
Top-kCheaper prompts, risk missing the answerHigher recall, more distraction and cost
Index typeFlat: exact, fine to about a million vectorsIVF/HNSW: approximate, scales further
RetrievalVector onlyHybrid + reranker: better quality, more latency

8. Pitfalls

9. Conclusion