RAG Pipeline in PyTorch: Building AI That Cites Its Sources
Ameya Deshmukh builds a full retrieval-augmented generation pipeline in PyTorch, from chunking a PDF into overlapping passages to retrieving the right ones with a single matrix multiply and forcing the model to cite its sources.
Ask a language model a question about your own PDF, a contract, a research paper, a policy document, and it tends to do one of two things: admit it does not know, or worse, invent an answer that sounds plausible but has no basis in the actual document. The model never read your file, because it cannot. This build works through exactly how to fix that, constructing a retrieval-augmented generation pipeline in PyTorch that answers questions from a PDF the model has never seen, and cites the page it pulled the answer from.
Why retrieval beats memory
Retrieval-augmented generation solves the hallucination problem by changing what the model is allowed to rely on. Instead of trusting the model's internal memory, you hand it the exact passages it needs to answer a question and instruct it to answer only from those passages. The core question this build answers is a practical one: how do you find the right passages to hand over in the first place?
Reading, chunking, and embedding the document
The process starts by reading the PDF and splitting it into overlapping chunks of a few hundred words each. The overlap is not incidental, it keeps a sentence that straddles two chunks from being cut in half and losing meaning in the process. Each chunk is then embedded into a vector using a PyTorch sentence transformer, which produces a tensor with one row per chunk and 384 numbers representing each one. The one step that matters most here is normalization: making every vector exactly length one. Once vectors are normalized, a simple dot product between any two of them becomes equivalent to cosine similarity, which is the trick that makes the retrieval step fast later on.
Turning meaning into geometry
Once the document is indexed, it stops being text and becomes geometry. Each chunk becomes a point in a high-dimensional space, and passages about similar ideas naturally cluster near each other while unrelated ones drift apart. An index on its own does not answer any questions yet; it just organizes the document's meaning spatially so that the next step, retrieval, can work quickly.
Retrieving with a single matrix multiply
To answer a question, the question itself is embedded into a vector using the same process as the document chunks, then scored against every chunk at once with a single matrix multiply. Because every vector has already been normalized to unit length, this comparison, the question vector times the transpose of the chunk matrix, directly produces the cosine similarity of the question against every chunk simultaneously. Taking the top four highest-scoring chunks gives the passages that are most likely to actually answer the question, and those become the only context handed to the model.
The grounding prompt that stops hallucination
The final piece is the instruction given to the model alongside those retrieved passages: answer only from this context, and if the answer is not here, say so. That single instruction is what actually prevents the hallucination problem this build set out to solve. The model is not asked to recall facts from its training; it is asked to read four specific passages and answer strictly from what is in front of it, with the page number it used attached to the answer. That citation is the difference between an answer you have to trust blindly and one you can actually go check yourself.
What each piece contributes
PyTorch does the heavy lifting of turning text into vectors and finding the nearest ones through a single multiply, but the pipeline as a whole is what makes the result trustworthy. The model never has to memorize the PDF, it only has to read the four passages it is handed and answer from them. Same underlying model, but grounded in evidence you can point to rather than in whatever it happened to learn during training.
Key takeaways
- RAG fixes hallucination by handing the model specific passages to answer from instead of relying on its internal memory.
- Chunking a PDF with overlapping windows prevents sentences from being split across chunk boundaries.
- Normalizing every embedding vector to unit length turns a simple dot product into cosine similarity, making retrieval fast.
- Retrieval for a new question is a single matrix multiply that scores the question against every chunk simultaneously.
- A grounding prompt that instructs the model to answer only from retrieved context, and say so when it cannot, is what actually prevents hallucination.
- Citing the page a chunk came from turns the model's answer into something a reader can independently verify.
Try it yourself
Point this pipeline at a PDF you actually care about, a textbook chapter or a research paper, ask it a real question, and check the cited page yourself. Then push on it: raise the number of retrieved chunks and watch the answer get more complete but noisier, or ask something the document does not cover and confirm the model refuses rather than inventing an answer. This build is part of the Humanitarians AI Fellows program.
Chapters
- 0:00Intro: Why models hallucinate when they haven't read your PDF
- 0:25What is RAG? Grounding the model in evidence instead of memory
- 0:45The Build: Reading, chunking, and embedding with PyTorch
- 1:10The Geometric Trick: Turning document meaning into high-dimensional space
- 1:35Fast Retrieval: Scoring questions with a single matrix multiply
- 2:00The "Grounding" Prompt: Forcing the model to stay within the provided context
- 2:25The Citation Receipt: Why page-level citations change everything
- 2:50Your Turn: Auditing the pipeline with your own research papers
Full transcript(auto-generated, with timestamps)
Intro: Why models hallucinate when they haven't read your PDF
[0:00]Namaste, this is Liam in for Amia, Build It With Claude, Then Take It Apart. Today, a retrieval-augmented generation pipeline in PyTorch that answers questions from a PDF the model has never seen and cites the page it used. Ask a language model about your own PDF, a contract, a paper, a policy, and it does one of two things. Says it doesn't know, or worse, invents an answer that sounds right. It never read your document. Retrieval-augmented generation fixes that. Instead of trusting the model's
What is RAG? Grounding the model in evidence instead of memory
[0:26]Memory, you hand it the exact passages it needs and make it answer from those. The question this build answers, how do you find the right passages? Start with the index into Claude, write rag.py. Read the PDF, split it into overlapping chunks of a few hundred words, and embed every chunk into a vector with a PyTorch sentence transformer. The overlap
The Build: Reading, chunking, and embedding with PyTorch
[0:45]Matters. It keeps a sentence that straddles two chunks from being cut in half. Here's the real code. Sentence Transformers runs on PyTorch, so model.encode gives you a tensor, one row per chunk, 384 numbers each. The one line that matters is the normalize. Make every vector length one, and a dot product between two of them becomes cosine similarity. That trick is what makes retrieval fast in the next step. Run it, and the document stops being
The Geometric Trick: Turning document meaning into high-dimensional space
[1:10]Text. The PDF is sliced into chunks, and each chunk lands as a point in a high-dimensional space, shown here in two. Passages about the same idea sit near each other. Unrelated ones drift apart. The meaning of your document is now geometry. An index alone doesn't answer anything. Revise, add retrieval. Embed the question the same way, score it against every chunk with a single matrix multiply, take the top four, and build a prompt that tells the model to answer
Fast Retrieval: Scoring questions with a single matrix multiply
[1:36]Only from those passages and to cite them. The revised code, because every vector is unit length, the whole search is one line. Q at M transpose is the cosine similarity of the question against all chunks at once and torch.top pulls the four closest. Those chunks become the context. The prompt does the rest of the work. Answer only from this context, and if it isn't here, say so. That instruction is what stops the hallucination. Now, ask a question. It
The "Grounding" Prompt: Forcing the model to stay within the provided context
[2:00]Becomes a vector, too, and drops into the same space. The matrix multiply ranks every chunk by nearness, and the top four light up the passages that actually talk about what you asked. Those and only those go to the model. The answer comes back built from your document with a page it came from attached. That citation is the difference between an answer you can check and when you have to trust. So, that's RAG end-to-end chunk, embed, retrieve, ground. PyTorch does the heavy
The Citation Receipt: Why page-level citations change everything
[2:25]Part, turning text into vectors and finding the nearest ones with a single multiply. The model never had to memorize your PDF. It just had to read the four passages you handed it. Same model, but now it answers from evidence you can point to. Your turn. Point this at PDF you actually care about. At least a textbook chapter, a research paper. Ask it a real question and check the cited page yourself. Then, push on it. Raise K and watch the answer get more complete, but noisier.
Your Turn: Auditing the pipeline with your own research papers
[2:50]Or ask something the document doesn't cover and confirm it refuses instead of inventing. That refusal is the whole point. RAG and PyTorch answers from your PDF with a receipt. This is Liam In Fra Mia.
More from Humanitarians AI Fellows
3:50Mycroft Update by Anjana: ECIS
2:01Mycroft Update on AI Vendor Tracker
2:48The Edge of Presence: Why AI Dominates the 24/7 Crypto Market
3:31The Benchmark Rot: Why AI Metrics Quietly Stop Working
3:05Loop Engineering: Infrastructure for Autonomous AI Systems
2:44