Sections in this lesson
RAG Fundamentals
Build a source-aware retrieval pipeline with explicit abstention and access filtering.
Reviewed: · Content owner: Interview Preparator
What you will learn
- Separate ingestion from query-time retrieval.
- Preserve source IDs and tenant filters.
- Diagnose retrieval misses before changing the prompt.
Before you start
The flow
- 1.Ingest & chunk
- 2.Embed & index
- 3.Authorized retrieval
- 4.Grounded answer
- 5.Evaluate
Two pipelines, one evidence chain
Ingestion parses documents, chunks text and stores vectors with source/version metadata. At query time, authorize access, retrieve passages and ask the model to answer using the available evidence. RAG does not retrain model weights.
Keep document updates and deletions reflected in the index. A successful retrieval from a stale policy can still produce an incorrect business answer.
Abstention is useful behavior
If there is no relevant authorized evidence, return a known unsupported state instead of fabricating a source. Similarity thresholds are dataset-dependent; the fixture uses a threshold only to demonstrate the branch.
A citation ID is not enough: verify that the cited passage supports the claim. Retrieved instructions remain untrusted data. The application must enforce access controls and safe tool execution.
Inspect the right failure layer
Measure whether the right source appears in top-k, then whether the answer faithfully uses it. Poor retrieval requires chunking, indexing or query work; a larger generation model may not fix it. Compare a simple baseline before adopting advanced RAG.
Try it
import assert from 'node:assert/strict';const documents = [ { id: 'policy-A', tenant: 'A', text: 'Refunds are available within 14 days.', score: 0.9 }, { id: 'policy-B', tenant: 'B', text: 'Confidential enterprise policy.', score: 1 },];function retrieve(tenant, minimumScore) { return documents.filter(d => d.tenant === tenant && d.score >= minimumScore);}function composeContext(tenant, minimumScore) { const sources = retrieve(tenant, minimumScore); return sources.length ? { status: 'READY', context: sources.map(s => `[${s.id}] ${s.text}`), citations: sources.map(s => s.id) } : { status: 'ABSTAIN', context: [], citations: [] };}assert.deepEqual(composeContext('A', 0.8).citations, ['policy-A']);assert.equal(composeContext('A', 0.95).status, 'ABSTAIN');assert.equal(composeContext('unknown', 0).status, 'ABSTAIN');console.log(composeContext('A', 0.8));// Fixed retrieval scores and context only: this example does not call an LLM.Run with Node.js 22: node examples/generative-ai/rag-fundamentals.mjs. This is a deterministic teaching example, not a live model call.
Interview questions
Does RAG eliminate hallucination?
No. Retrieval can fail, sources can be stale and generation can misread evidence. Evaluate each layer.
Why preserve source identifiers?
For citations, auditability, document lifecycle operations and evaluation against expected evidence.
When is fine-tuning a different choice?
When learning a behavior or format is the goal; frequently changing facts and per-user access still need retrieval or tools.
Practice
Add a deleted document flag and ensure no deleted or foreign-tenant source enters context.
Check your solution
- Known query returns source IDs.
- Missing or inaccessible evidence abstains.
- Deletion is tested independently from relevance.
Official references
Continue learning
Category sequence
Generative AI
Lesson 6 / 8
Was this lesson useful?
Change notes: Initial bilingual lesson and executable example.