I added a practice feature to a German learning app for people preparing for their naturalisation appointment: the conversation where an official may ask about Germany's constitution, elections and history. Learners type or speak an answer, and a model gives feedback. That's exactly the setting where a model's occasional confident mistake does real harm. A learner who's told the wrong voting age by their practice app will say it to the official.
The fix is grounding: the model's knowledge comes from facts you hand it, each with its source, not from its training. And the model doesn't get the final say. Code checks what it produced before anything reaches the learner. Here's how that works, and the tests that showed it works.
At a glance
- Grounding means the model checks and answers only against material you supply, never against its own memory.
- Each practice question carries its official facts, quoted or condensed from the law or a government source, each ending with that source.
- The prompt forbids judging opinions, beliefs or personal reasons, and on sensitive topics allows only the facts' own wording.
- Code decides what appears: no model answer without facts, and every quote must appear in the learner's answer.
- Tested with wrong facts on purpose ("every five years", "from 16"): both caught. One slip was seen, and it's the reason the code checks exist.
What does grounding mean in practice?
The general idea is simple: give the model the truth to compare against, and tell it what it must not judge. In this feature:
- Each question carries a short list of official facts. For example, that the right to vote in federal elections starts at 18, ending with "(Art. 38 Abs. 2 GG)".1
- The model checks the learner's answer only against those facts, never against its own memory.
- The model never judges opinions, beliefs or personal reasons. "I think Germany has learned from its history" is an opinion; the feedback can point to the law's own terms, but it doesn't grade the view.
- On sensitive topics (the Nazi past, antisemitism, Israel), it uses only the facts' wording.
- The model answer it writes may use only the facts given. Where there are none, such as a question about the learner's own life, it writes no model answer at all.
Grounding is the same principle as RAG, without the search: here the relevant facts are attached to each question in advance instead of being retrieved. The RAG walkthrough shows the retrieval version.
Where do the facts come from?
Every fact was checked on the day it was written, against the source itself:
- Articles 1, 3, 4, 5, 19, 38 and 39 of the Basic Law (Grundgesetz) and § 10 of the Nationality Act (StAG) were read on gesetze-im-internet.de, the federal government's law portal.1 2 3
- The definition of the free democratic basic order came from the Federal Constitutional Court's 2017 press release on the NPD ruling.
- The federal office's (BAMF) published question catalogue doesn't mark which answers are correct, so no fact rests on a catalogue answer alone. Only what a question itself states (such as "1933 bis 1945") was used.
The rule for adding a fact is strict: quote or condense one sentence from the official source, end it with the source in brackets, and never write a number or date from memory. A test fails if any fact lacks its source.
Practical takeaway
Write your facts the way a careful editor would: one sentence each, each with its source, each checked against the primary text the day you wrote it. If you can't source it, don't give it to the model.
Why code gets the last word
The model returns JSON with a fixed structure: a checklist (did the answer address the question, were the facts right, were the key points there, was it short and calm), suggestions, a model answer and an opening quote. Then code checks it:
- No model answer without facts. If a question has no official facts, any model answer is dropped, even if the model wrote one.
- The opening quote must be in the learner's answer. If the model quotes something the learner didn't say, it doesn't appear.
How was it tested?
With the model running locally, four kinds of input:
| Test | Result |
|---|---|
| Wrong facts on purpose: "elections every five years" and "voting from 16" | Marked "facts right ✗", both corrections named, and the model answer was correct. The Bundestag is elected for four years, and the federal voting age is 18.1 4 |
| An opinion: "Ich finde, dass Deutschland aus seiner Geschichte gelernt hat …" | Not judged; the suggestions pointed to the law's own terms |
| No facts: a question about the learner's own life | No model answer appeared |
| One slip: on the personal question, the model once wrote that the answer's facts "match the official facts provided", although none were provided | The reason code, not the model, decides whether a model answer appears |
That last row is the important one. The model mostly followed the rules, and once it didn't, in a way that sounded perfectly reasonable. Without the code check, the learner would have seen it. With it, the slip couldn't reach them. The test set for the hosted model will include these exact cases.
Lessons for any feature that judges content
- Give the model the truth, with sources. Don't rely on what it remembers, especially for numbers, dates and legal facts.
- Say what it must not judge. Opinions, beliefs, personal reasons, sensitive topics: list them explicitly.
- Let code decide what appears. Drop model output that has no grounding, and check quotes against the input.
- Test with known wrong answers. Plant errors and confirm they're caught. Test the no-facts case and the opinion case too.
- Expect the occasional slip. Design so a slip is caught or harmless, rather than hoping it never happens.
FAQ
Does grounding eliminate hallucinations?
No, it reduces and contains them. The model can still misread the facts or claim something it wasn't given, which is why the code checks matter. Grounding plus checks makes a wrong statement much less likely to reach the user.
What's the difference between grounding and RAG?
RAG is grounding with a search step: the relevant material is retrieved at question time. Here the facts are attached to each question in advance. Both give the model the truth to work from instead of its memory.
How do you handle sensitive topics?
Restrict the model to the source's own wording on those topics, forbid it from judging views, and test it with opinions as well as facts. The goal is accurate information, not a verdict on the learner.
Can a smaller or local model do this?
The feature was first tested with a model running locally, and it handled the planted errors. Results vary by model, so the same test set should run before switching models.
Sources
- Grundgesetz, Art. 38, gesetze-im-internet.de.
- Grundgesetz für die Bundesrepublik Deutschland, gesetze-im-internet.de.
- Staatsangehörigkeitsgesetz, § 10, gesetze-im-internet.de.
- Grundgesetz, Art. 39, gesetze-im-internet.de.
This is general guidance, not legal advice. Please assess your specific case, ideally with your own counsel.
LLM Evaluation & Fact-Checking
Report AI results you never have to retract.
Get the free starter kit
Four complete skills for Claude, Claude Code and Codex: handover, session start, social captions and an honest exam-prep tutor. Free, so you can judge the standard.



