ClaimCheck / README.md
NagaYu's picture
Point self-hosting instructions at python/ in the rule pack
1ce6570 verified
|
Raw History Blame Contribute Delete
6.55 kB
---
title: ClaimCheck
emoji: πŸ”Ž
colorFrom: yellow
colorTo: red
sdk: static
app_file: index.html
pinned: false
license: apache-2.0
short_description: Verify LLM answers against the context they came from
tags:
- hallucination-detection
- groundedness
- rag
- guardrails
---
# πŸ”Ž ClaimCheck
**Verify LLM answers against their source context before they reach users.**
Paste an answer and the context it was supposed to be grounded in. ClaimCheck extracts the claims it can check as
strings β€” numbers, dates, quotes, entities, URLs β€” matches each against the context, and returns a verdict
(`pass` / `annotate` / `retry` / `block`), a grounding score, and **how much of the answer it did not check**.
**Everything runs in your browser.** No server, no network call, no telemetry β€” the verifier is ~1,700 lines of
dependency-free JavaScript executing in this tab. Paste real model output if you want to; it stays on your machine.
| | |
|---|---|
| πŸ“¦ Rule pack | [`NagaYu/claimcheck-rules`](https://huggingface.co/NagaYu/claimcheck-rules) |
| πŸ“Š Evaluation set | [`NagaYu/claimcheck-eval`](https://huggingface.co/datasets/NagaYu/claimcheck-eval) |
| ⚑ Latency | ~0.2 ms typical · 15 ms on a 20,000-character worst case |
| 🌏 Languages | English and Japanese |
---
## Design philosophy
We cannot detect every hallucination. Nobody can, and a tool that claims to is lying to you.
But we do not have to. The observation this is built on:
> **Dangerous hallucinations are specific.**
A model that invents *"the contract terminates on 2023-11-04 under Article 12, with a penalty of 3,400,000 JPY"* is far
more harmful than one that says *"the contract may terminate at some point"*. And the specific one is **checkable as a
string**: numbers, dates, quotes, entities and URLs are literal tokens that either do, or do not, appear in (or follow
arithmetically from) the source.
So ClaimCheck verifies only what it can verify deterministically, and declares the rest out of scope β€” loudly.
## ⚠️ Always read `coverage`
Two independent numbers, and reporting one without the other is the most dangerous way to misuse this tool.
| field | question it answers |
|---|---|
| `grounding_score` | Of the claims I checked, what share held up? |
| `coverage` | What share of the answer did I check at all? |
```
grounding_score 1.00 + coverage 0.10
= one sentence checked out and nine were never looked at.
= NOT "this answer is verified".
```
An answer of pure hedging produces **zero** claims and scores **1.00** on any naive groundedness metric.
## Claim statuses
| status | colour | meaning |
|---|---|---|
| `supported` | 🟩 | Appears literally in the context after normalisation |
| `derived` | 🟦 | Computable from context numbers by 2–3 term arithmetic; the formula is shown |
| `approximate` | 🟨 | A near match exists β€” paraphrase, finer-grained date, related URL |
| `unsupported` | 🟧 | Nothing in the context backs it |
| `contradicted` | πŸŸ₯ | The context holds a **near but different** value |
`approximate` is deliberately **not** counted as grounded: a paraphrased quote is still an inaccurate quote.
## Measured behaviour
On the [158-case bilingual evaluation set](https://huggingface.co/datasets/NagaYu/claimcheck-eval):
```
answer-level recall 56/56 (100%) cases that should be flagged, and were
clean answers passing 44/46 (96%) the rest were annotated, never blocked
known false positives 22 (13.9%)
known false negatives 3 (1.9%)
JS/Python parity 158/158 (100%)
```
The false-positive rate is published deliberately. It is the number that decides whether anyone keeps a verifier
switched on, and hiding it helps nobody.
### Known limitation: semantic reversal
All three false negatives share a shape. A one-character change that reverses meaning keeps character similarity above
0.9, so a reversed quote reads as a faithful paraphrase:
| context | answer | similarity | status |
|---|---|---|---|
| 売上高は7%**ε’—εŠ **γ—γŸ | 売上高は7%**ζΈ›ε°‘**γ—γŸ | 0.97 | `approximate` ❌ |
| ζζ‘ˆγ―ε…¨δΌšδΈ€θ‡΄γ§**ζ‰Ώθͺ**γ•γ‚ŒγŸ | ζζ‘ˆγ―ε…¨δΌšδΈ€θ‡΄γ§**否決**γ•γ‚ŒγŸ | 0.92 | `approximate` ❌ |
| revenue **grew** 8% | revenue **declined** 8% | 0.97 | `approximate` ❌ |
Character matching cannot detect negation or antonym substitution. If your domain turns on approve/reject or
increase/decrease, **do not rely on quote status alone.** In all three cases the answer-level verdict was still
`retry`, because the NUMERIC and ENTITY claims inside the quote are the layer that catches it.
### False positives
Faithful paraphrase Β· generic noun phrases ("Machine Learning") Β· acronym expansion (WHO ↔ World Health Organization) Β·
rounding just outside tolerance Β· fiscal vs calendar years Β· identifier variants (ISO 9001:2015 vs ISO 9001) Β·
URL query parameters.
**ENTITY is the noisiest check.** Set `{"enable_entity": false}` in the policy box first, and start from `annotate`,
never `block`.
## Policy presets
Paste any of these into the **Policy JSON** box. Full set in the
[rule pack](https://huggingface.co/NagaYu/claimcheck-rules):
```jsonc
// observe: nothing blocked but critical safety β€” start here
{"retry_on_contradicted": 9999, "retry_grounding": 0.0, "annotate_grounding": 1.0}
// numeric + date only: the lowest false-positive configuration
{"enable_entity": false, "enable_quote": false, "enable_url": false}
// tolerant of rounding
{"numeric_tolerance": 0.02, "contradiction_rel": 0.10}
```
## Running it yourself
The core is an ES module with no dependencies:
```js
import { gate, verify, buildHighlight } from "./claimcheck.js";
const r = gate(answer, context, systemPrompt, userInput, schemaJson, policyJson, tagsJson);
console.log(r.verdict, r.grounding_score, r.coverage);
```
A Python implementation with a Gradio UI and a REST API also exists and is behaviourally identical (verified at 100%
parity on all 158 evaluation cases); it ships under `python/` in the
[rule pack repository](https://huggingface.co/NagaYu/claimcheck-rules) for self-hosting.
## Disclaimer
ClaimCheck is **one layer of defence, not a correctness guarantee.** It verifies numbers, dates, quotes, entities and
URLs against a context you supply. It says nothing about claims it could not extract, nothing about reasoning, and
nothing about whether the context itself was right. A `pass` verdict means *"the specific things I know how to check,
checked out"* β€” nothing more.
Apache-2.0.