Structured output makes values easier to validate, but a valid schema does not prove that those values are true. For a grounded answer, keep each factual claim connected to a source revision and a supporting passage. Reject unsupported fields before presenting them as facts.
Validate syntax, source presence and meaning separately
| Check | What it establishes |
|---|---|
| JSON/schema validation | The record has the expected structure |
| Source identity and revision | The evidence record can be located |
| Exact supporting quote | The cited text exists in that revision |
| Contextual support review | The text supports the claim, units and date |
| Conflict handling | Unresolved evidence is not silently omitted |
A small citation-presence gate
def supported_answer(claims, source_map):
return all(c.get('source_id') in source_map and bool(c.get('quote'))
and c['quote'] in source_map[c['source_id']] for c in claims) and bool(claims)
sources = {"d1": "The fixture supports version 2."}
valid = [{"source_id": "d1", "quote": "version 2"}]
invalid = [{"source_id": "d1", "quote": "version 3"}]
assert supported_answer(valid, sources)
assert not supported_answer(invalid, sources)
This mechanical test checks that a cited quote exists in its named source. It is necessary for traceability, but not sufficient for semantic support. A real review must also check whether the quote answers the question and whether important qualifications were omitted.
Preserve an unresolved outcome
If a required claim lacks support, remove it or return an explicitly unresolved field. Do not replace a missing number with a plausible value. If sources disagree, keep both revisions and the reason a reviewer accepted one interpretation.
Cleaner Markdown or more URLs can make evidence handling easier to inspect. They do not certify the output, eliminate hallucinations or establish a universal improvement in accuracy.
Reference documentation: www.searchcans.com — /reader-api.