Quick Summary
RAG helps an AI model search your own documents first and then answer using that context, which makes it ideal for chat-with-PDF apps, knowledge bases, and beginner AI products.
- RAG is search + generation, not model retraining.
- Chunking and retrieval quality matter as much as the model.
- RAG is best for documents, FAQs, manuals, and changing knowledge.
- A small working RAG app is the best way to learn the pattern.
You've probably seen demos of AI answering questions from a PDF or a company knowledge base. That's RAG — Retrieval-Augmented Generation. It's one of the most useful patterns in modern AI, and it's simpler than it sounds.
In this article, I'll break it down exactly — what the problem is, how RAG solves it, and the code pattern behind every "chat with your PDF" app you've seen.
The Problem RAG Solves
LLMs like Gemini or GPT know a lot — but they were trained on data up to a certain date, and they don't know your data. If you ask ChatGPT about your company's internal docs, it has no idea. It'll either hallucinate an answer or say it doesn't know.
💡 Key Concept
How RAG Actually Works
There are two phases: indexing (one-time setup) and querying (every time a user asks something).
Phase 1 — Indexing Your Documents
Before a user can ask anything, you need to process your documents into a searchable format:
- Extract text from the PDF or document
- Split it into small chunks (e.g. every 500 words)
- Convert each chunk to an embedding — a list of numbers that captures the meaning
- Store those embeddings in a vector database
// Step 1: Extract text from PDFconst pdfText = await extractText(pdfBuffer);// Step 2: Split into chunksconst chunks = splitIntoChunks(pdfText, {size: 500,overlap: 50});// Step 3: Generate embeddingsconst embeddings = await Promise.all(chunks.map(chunk => gemini.embedContent(chunk)));// Step 4: Store in vector databaseawait vectorDB.upsert(chunks.map((chunk, i) => ({id: generateId(),vector: embeddings[i],text: chunk,})));
Phase 2 — Answering a Question
When a user asks a question, you don't send the entire document to the AI. Instead:
async function answerQuestion(userQuestion) {// 1. Embed the questionconst qEmbed = await gemini.embedContent(userQuestion);// 2. Find the most relevant chunksconst results = await vectorDB.search({vector: qEmbed,limit: 3,});// 3. Build the prompt with contextconst prompt = `Use the following context to answer.Context: ${results.map(r => r.text).join('\n\n')}Question: ${userQuestion}`;// 4. Get the answerreturn await gemini.generateContent(prompt);}
✅ Why This Works
RAG vs Fine-Tuning
| Approach | When to use | Cost | Updates easily? |
|---|---|---|---|
| RAG | Your docs, FAQs, knowledge bases | Low | Yes — just re-index |
| Fine-tuning | Specific tone or domain expertise | High | Needs full retraining |
| Prompt engineering | Formatting, tone, persona | None | Instant |
⚠️ Common Mistake
500–800 words per chunk with 10–15% overlap.Frequently asked questions
What does RAG mean in AI?
RAG stands for Retrieval-Augmented Generation. It means the model first retrieves relevant information from your data and then generates an answer using that context.
When should I use RAG instead of fine-tuning?
Use RAG when the answer should come from documents, FAQs, or a changing source of truth. Use fine-tuning when you want to shape style, tone, or a narrow behavior pattern.
Why do people build chat-with-PDF apps with RAG?
Because RAG is a practical way to make a model answer from a specific PDF or document set without retraining the model every time the source changes.
Free Course
Build a Real AI App — Node.js + RAG + Gemini
Go from this article to a working project. Free, step by step, follows my YouTube playlist.
Start Free Course →