NLP Textbook RAG
Ask the canonical NLP textbook a question and get an answer grounded only in its pages, with citations and the exact passages, nothing made up.
The problem
I took a natural language processing class for my master's, and I wanted to actually understand how RAG works under the hood. So I built one end to end.
The goal was a system built on our course textbook, Jurafsky & Martin's Speech and Language Processing (35 chapters, ~1,000 pages), where the LLM answers from the book itself rather than from whatever it absorbed during training. Every answer traces back to the actual pages, and when the book doesn't cover something, it says so instead of guessing.
How it works
Ask a question and it runs through a fixed retrieval-augmented pipeline. Nothing in the answer comes from the model's own training: it only sees passages pulled from the book, and if nothing relevant comes back, it says so.
The corpus is the whole textbook split into 10,170 passages (about 280 characters each, 20% overlap so a concept that straddles a boundary still lands intact in some chunk). Questions and passages are embedded with the same MiniLM model, which is the only reason the cosine similarity means anything. The final step hands the LLM a strict anti-hallucination prompt: answer only from the supplied passages, cite the chapters you drew from.
Architecture
The whole app is serverless TypeScript on Vercel: no standing server, and no Python even for the embeddings. It breaks into three layers.
Frontend
A Next.js app with two views over the pipeline:
- A live run you drive yourself: ask a question and see the answer with the exact passages it retrieved shown inline.
- A database viewer that browses all 10,170 indexed chunks directly, so the index isn't a black box.
Backend
Retrieval runs in Vercel serverless functions, with no model server of its own (a past life of this ran generation via Ollama on an always-on, paid GCP VM; going serverless is what makes this version cheap enough to keep live). The question is embedded in-request through a hosted MiniLM endpoint, the same model used on the corpus, so the cosine distances are actually comparable. The vectors live in Supabase pgvector, which runs the nearest-neighbor search, and a daily GitHub Action pings the database so the free tier never pauses.
LLM
The final step sends the retrieved passages to a generative model. It runs on a free Groq model today, with bring-your-own-model support as a planned next step. The model gets a strict anti-hallucination prompt: answer only from the supplied passages, and cite the chapters it drew from.
