WHAT YOU WILL BUILD
A three-case evidence checklist for supported, unsupported, and unanswered questions.
A citation has two jobs: point to an accessible source and support the claim being made. An ID allowlist checks the first job. A separate comparison between the claim and the cited passage checks the second.
Before you start
Use a text editor and Node.js 22 or newer ↗. Check your version with node --version. Save the downloaded file in an empty folder, then open a terminal in that folder.
All data is included. No packages, account, or API key are required. Answers are supplied examples. The script checks citation structure; it does not generate answers or judge their meaning.
Download the lab (.mjs)FOLLOW ALONG
Work through the example.
- 01
Read the source of truth
The sample policy says unused items have 30 days and opened items are not eligible. There is no gift-card policy. Keep this short source visible during review.
- 02
Run the three cases
The valid source ID receives REVIEW SUPPORT. The invented ID receives REJECT. A declared unknown answer with no citation receives ABSTAIN.
- 03
Try a false claim with a real ID
The final assertion attaches returns-v2 to a 90-day claim. It still reaches REVIEW SUPPORT. Compare it with the passage and manually mark the claim unsupported.
- 04
Write an acceptance record
For each case record: source exists, claim supported, exceptions preserved, and unknown handled. Accept the first answer only after its claim passes all relevant checks.
THE COMPLETE LAB
Run it locally.
Run this command from the folder containing your downloaded file:
node rag-evidence.mjsView or copy the complete JavaScript
// SaveMyToken local lab. Run with Node.js 22 or newer.
import assert from "node:assert/strict";
const sources = new Map([
["returns-v2", "Unused items: 30 days. Opened items: not eligible."],
]);
// ID validation is structural. A person must still check claim support.
function checkCitation(answer) {
if (answer.status === "unknown") return answer.sourceId === null ? "ABSTAIN" : "REJECT";
return sources.has(answer.sourceId) ? "REVIEW SUPPORT" : "REJECT";
}
const cases = [
{ status: "answered", text: "Unused items have 30 days.", sourceId: "returns-v2" },
{ status: "answered", text: "All items have 90 days.", sourceId: "invented" },
{ status: "unknown", text: "No evidence about gift cards.", sourceId: null },
];
const results = cases.map(checkCitation);
console.log(results.join(" | "));
assert.deepEqual(results, ["REVIEW SUPPORT", "REJECT", "ABSTAIN"]);
// This passes ID validation but is false: validate meaning separately.
assert.equal(checkCitation({ status: "answered", text: "90 days", sourceId: "returns-v2" }), "REVIEW SUPPORT");
Expected output for the unchanged example
REVIEW SUPPORT | REJECT | ABSTAINThe assertions also check the baseline behavior. After changing an input, predict the result and update the relevant assertion.
NOW CHANGE ONE THING
Make the example your own.
Add an answer that gets the 30-day limit right but says opened items are eligible. Give it a real citation and explain why it must fail the support review.
You are done when…
A real source ID cannot make a false statement pass your full review; uncovered questions remain explicitly unanswered.
If something goes wrong
Do not rename REVIEW SUPPORT to VERIFIED. For a real application, resolve IDs on the server from the retrieved, authorized source set and check the cited version.
EXPLAIN WHAT YOU LEARNED
Interview practice
Try answering aloud before opening the reference answer. These are original learning questions, not a record of any employer's interviews.
01Does a citation prevent hallucination?
No. It can point to a real passage that does not support the answer. Verify the source, the claim, and any important conditions separately.
Watch for: Citation presence is only a structural check.
02When should a RAG assistant abstain?
When accessible evidence is missing, contradictory, or insufficient for the requested claim. Explain what is missing and offer a relevant next step when one is available.
Watch for: Low similarity alone is not a universally calibrated abstention rule.
03How should citations be linked?
Keep source IDs and locations with the retrieved passages. Resolve approved IDs into actual links or document locations rather than accepting invented URLs from generated text.
Watch for: An old source version may no longer justify the current answer.
04What if two sources disagree?
Expose the disagreement, compare scope and effective dates, and apply a documented precedence rule where one exists. Avoid silently combining incompatible statements.
Watch for: A newer upload timestamp is not always a newer policy date.
05How can you evaluate groundedness?
Break the answer into checkable claims and compare each with the available evidence. Record unsupported claims and missing exceptions alongside overall correctness.
Watch for: An answer can repeat its sources faithfully while the sources themselves are wrong.
Sources and further reading
The explanation and local exercises were written for SaveMyToken. These references support the underlying concepts; the sample outputs describe only the supplied examples.
Hugging Face: evaluating RAG ↗LangChain: retrieval and RAG ↗