
Quick answer: Grounding means the model answers from documents you retrieved, not from its training memory. The reliable pattern is search-then-read: run a web search, fetch the full text of the top results, put that text in the context, and instruct the model to cite the sources or explicitly say it doesn't know. Done properly, this converts most hallucinations into either correct cited answers or honest abstentions.
It does not eliminate hallucinations. Anyone who tells you otherwise is selling something. But it changes the failure mode from "confidently wrong" to "checkable," and that's the difference between a demo and a product.
Why Grounding Beats Bigger Models
A model's parametric knowledge has two unfixable problems: it's frozen at the training cutoff, and it has no provenance. When the model says a library's latest version is 4.2, you can't tell whether that's knowledge or interpolation. Neither can the model.
Grounding sidesteps both. The claim comes from a document you can point at, dated today. When the model is wrong, you can usually trace whether the retrieval failed or the model misread the source. That traceability is what makes the system debuggable.
The naive version of this (search, paste in the snippets, hope) fails in predictable ways. I've seen every one of these in production:
- Search snippets are 20-word fragments; the model fills gaps with training memory.
- The model answers from memory anyway and decorates it with citations that don't support the claim.
- Retrieval returns a stale page and the model has no idea it's stale.
Each failure has a specific fix. That's the rest of this post.
Pattern 1: Search-Then-Read (Not Search-Then-Snippet)
The biggest single upgrade is fetching full page content instead of relying on search snippets. Snippets are built for humans scanning a results page, not for models answering questions; the actual answer is usually in a paragraph the snippet cut off.
With link.sc this is two small calls: search for the top results, then fetch each result's full page text:
curl "https://api.link.sc/v1/search" \
-H "x-api-key: lsc_your_key" \
-H "Content-Type: application/json" \
-d '{"q": "postgres 17 logical replication changes", "engine": "google"}'
# then, for each targetUrl in serpData.results:
curl "https://api.link.sc/v1/fetch" \
-H "x-api-key: lsc_your_key" \
-H "Content-Type: application/json" \
-d '{"url": "https://www.postgresql.org/docs/17/logical-replication.html", "format": "markdown"}'
If your search API only returns links, add a fetch step for the top 3-5 results before you build the prompt. Yes, it costs more tokens. It's worth it; answering from full text instead of snippets is the difference between grounding and citation theater.
Pattern 2: Cite-or-Abstain Prompting
The model needs permission to say "I don't know." Without it, an LLM under instruction to answer will answer, sources or no sources.
The prompt structure I use:
Answer the question using ONLY the numbered sources below.
Rules:
- Every factual claim must end with a citation like [2].
- If the sources do not contain the answer, say exactly:
"The retrieved sources do not answer this." Do not guess.
- If sources conflict, present both claims with their citations.
[1] (fetched 2026-07-18, example.com/changelog) ...full text...
[2] (fetched 2026-07-18, blog.example.org/post) ...full text...
Question: ...
Three details that matter more than they look:
- Number the sources and demand inline citations. Per-claim citations are checkable; a bibliography at the end is not.
- Give exact abstention wording. Models follow "say exactly X" far more reliably than "say you're unsure."
- Include the fetch date per source. This feeds the freshness pattern below.
Pattern 3: Freshness-Aware Retrieval
Grounding on a stale page is still hallucination, just outsourced. For time-sensitive questions (prices, versions, schedules, anything with "latest" in it), the retrieval layer has to care about dates.
Concretely:
- Pass recency filters to search when the question implies them ("released this week" → restrict to the past month).
- Fetch live rather than trusting a cached index. Search indexes lag; a direct fetch of the source page doesn't.
- Put the fetch timestamp in the prompt and instruct the model to prefer newer sources when claims conflict.
This is the same freshness problem RAG pipelines have, and the solutions overlap heavily; I covered the pipeline side in real-time web search for LLMs.
Pattern 4: The Verification Pass
For anything user-facing, add a second model call that audits the first. It gets the draft answer plus the sources and checks one thing: does each cited source actually support the sentence citing it?
Here's the full grounded flow with verification, condensed:
import requests
LSC = {"x-api-key": "lsc_your_key"}
def grounded_answer(question, llm):
# 1. Search, then fetch full-page content for the top results
r = requests.post("https://api.link.sc/v1/search", headers=LSC,
json={"q": question, "engine": "google"})
results = r.json()["serpData"]["results"][:5]
sources = []
for s in results:
page = requests.post("https://api.link.sc/v1/fetch", headers=LSC,
json={"url": s["targetUrl"], "format": "markdown"})
sources.append((s["targetUrl"], page.json()["content"]))
src_block = "\n\n".join(
f"[{i+1}] ({url})\n{text[:6000]}"
for i, (url, text) in enumerate(sources))
# 2. Draft with cite-or-abstain rules
draft = llm(f"Answer using ONLY these sources. Cite like [1]. "
f"If they don't answer it, say so.\n\n{src_block}\n\nQ: {question}")
# 3. Verify: every citation must be supported
verdict = llm(f"For each cited claim in the answer, check the cited "
f"source supports it. Reply SUPPORTED or list the "
f"unsupported claims.\n\nSOURCES:\n{src_block}\n\n"
f"ANSWER:\n{draft}")
if "SUPPORTED" not in verdict:
return "I couldn't verify an answer from current sources."
return draft
The verification pass roughly doubles your LLM cost. Whether that's worth it depends on what a wrong answer costs you. For internal tooling I skip it; for anything a customer reads, I don't.
How to Evaluate a Grounded System
Skip generic benchmarks and measure the two failure modes that actually hurt:
Citation accuracy. Sample answers, take each cited claim, read the cited source, and label it supported or unsupported. This is tedious human work for the first hundred examples and it's the highest-value evaluation you'll do. Once you trust an LLM judge against your human labels, automate it.
Abstention behavior. Build a small set of questions your sources cannot answer (fictional products, events after the fetch date) and measure how often the system abstains versus fabricates. A grounded system that never abstains isn't grounded; it's confident.
Track both over time. Retrieval quality drifts as the web changes, and a system that scored well in March can quietly degrade by July.
Honest Limits
Grounding narrows the hallucination problem; it doesn't close it.
- Models can misread sources. A correct citation to a real page can still support a subtly wrong summary of it. Verification catches most of this, not all.
- The web itself is wrong a lot. Grounding on a confidently wrong blog post gives you a confidently wrong cited answer. Source diversity helps; it doesn't cure it.
- Retrieval misses are invisible to the model. If search never surfaces the page with the real answer, the best case is abstention, not correctness.
AI search products with billion-dollar budgets still get this wrong regularly, which I dug into in AI search engines are confidently wrong. Their failures are mostly retrieval and misreading failures, exactly the ones above. The patterns in this post are the same ones they use; the difference is whether you measure.
Start with search-then-read and cite-or-abstain. Those two alone fix the majority of "the model just made that up" complaints, and you can add freshness handling and verification once you have traffic worth protecting. If you want to try the retrieval side, the quickstart gets you a grounded search call in about two minutes.
Ready to ground your LLM in live sources? Get a free link.sc key and make your first search and fetch calls today.