Deterministic grounding check for evidence-grounded AI — required facts present, every number traceable, abstention when unanswerable. No LLM judge.
Project description
opengate-grounding
Deterministic grounding check for evidence-grounded AI — no LLM judge.
Is an AI answer actually supported by the context it was given? opengate-grounding
answers that with pure, reproducible logic — the Python port of OpenGATE's
check_grounding. It catches the three grounding failures that matter in production:
- Dropped facts — the specific facts a correct answer must contain actually appear.
- Fabricated numbers — every figure in the answer traces back to the context or the question.
- Failure to abstain — when the context can't answer, the model must decline rather than invent.
Because it's deterministic (no grader model, no API key), it's free, instant, and safe to run on every answer — inline in an agent or as a CI gate. It's the same check that powers the OpenGATE evaluation framework and the OpenGATE MCP server.
Install
pip install opengate-grounding
No dependencies. Python 3.8+.
Quick start
from opengate_grounding import check_grounding
result = check_grounding(
answer="You have 30 days to request a refund, with no restocking fee.",
context="Customers may request a full refund within 30 days. There is no restocking fee.",
anchors=["30 days", "no restocking fee"],
)
result.grounded # True
result.issues # []
A failing answer tells you exactly why:
r = check_grounding(
answer="30 days, no restocking fee, plus a 90-day extension.",
context="Customers may request a full refund within 30 days. There is no restocking fee.",
anchors=["30 days", "no restocking fee"],
)
r.grounded # False
r.ungrounded_numbers # ['90']
r.issues # ['ungrounded number "90" — not in the provided context']
Unanswerable questions must abstain:
r = check_grounding(
answer="That isn't in the provided context — contact sales.",
context="Pro plan has a 30-day trial.",
answerable=False,
)
r.grounded # True
r.abstained # True
Gate it in your tests
from opengate_grounding import assert_grounded
def test_refund_answer():
assert_grounded(
answer=my_rag("How long is the refund window?"),
context=retrieved_passages,
anchors=["30 days", "no restocking fee"],
)
On failure the assertion names the concrete issues, so a grounding regression shows up as a red build.
Use it as a DeepEval metric
pip install "opengate-grounding[deepeval]"
from deepeval import evaluate
from deepeval.test_case import LLMTestCase
from opengate_grounding.deepeval_metric import GroundingMetric
case = LLMTestCase(
input="How long is the refund window?",
actual_output="You have 30 days, with no restocking fee.",
retrieval_context=["Refund within 30 days. No restocking fee."],
additional_metadata={"anchors": ["30 days", "no restocking fee"]},
)
evaluate([case], [GroundingMetric()])
GroundingMetric maps actual_output → answer, retrieval_context → context, and input → question.
Per-case controls (anchors, answerable, allowed_new_numbers) go on additional_metadata or the
metric constructor. Score is 1.0 when grounded, 0.0 otherwise; with the default threshold=1.0 a
case passes only when fully grounded. Pair it with DeepEval's model-graded metrics for breadth, and use
this one to gate the grounding.
API
check_grounding(answer, context, *, question=None, anchors=None, allowed_new_numbers=None, answerable=True, abstain_markers=None) -> GroundingResult
| Argument | Meaning |
|---|---|
answer |
The system's answer (string). |
context |
The retrieved context — a string or a list of passages. |
question |
Optional. Whitelists numbers that appear in the question. |
anchors |
Facts a correct answer must contain. Each may be a string, an Anchor, or a {"value": ..., "aliases": [...]} dict. |
allowed_new_numbers |
Numbers the answer is permitted to introduce (e.g. a computed total). |
answerable |
When False, the answer must abstain rather than answer. |
abstain_markers |
Phrases that count as a valid refusal (defaults to DEFAULT_ABSTAIN). |
GroundingResult — grounded: bool, anchors_missed: list[str], ungrounded_numbers: list[str],
abstained: bool, issues: list[str]. Truthy when grounded (so if check_grounding(...): works).
Also exported: Anchor, contains, numbers_in, flatten_context, DEFAULT_ABSTAIN.
What it deliberately won't do
- No LLM-as-judge. Scores are deterministic checks — reproducible, free, and your judgment lives in the anchors you supply, not a grader model's.
- No general "quality" score. It measures grounding, not fluency or helpfulness.
- It never sees your model. It inspects the answer text you give it — no weights, no internals.
License
MIT © PharmaTools.AI. Part of the OpenGATE project.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file opengate_grounding-0.1.0.tar.gz.
File metadata
- Download URL: opengate_grounding-0.1.0.tar.gz
- Upload date:
- Size: 10.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
53f38b9d173a1309186b9a9aa9b23c5e50927cac0ce12ddbde066c8e66dc5f88
|
|
| MD5 |
a3cf021d27bea4743bf1344b6ec5fc12
|
|
| BLAKE2b-256 |
6e4d83cb7d5f900384ddc7387903efd4e63cf992eaea54f486520982f01af546
|
Provenance
The following attestation bundles were made for opengate_grounding-0.1.0.tar.gz:
Publisher:
python-publish.yaml on nickjlamb/opengate
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
opengate_grounding-0.1.0.tar.gz -
Subject digest:
53f38b9d173a1309186b9a9aa9b23c5e50927cac0ce12ddbde066c8e66dc5f88 - Sigstore transparency entry: 2084853116
- Sigstore integration time:
-
Permalink:
nickjlamb/opengate@9cef0e4333a2ede7148579bda8474fa2c37ebe8c -
Branch / Tag:
refs/tags/opengate-py-0.1.0 - Owner: https://github.com/nickjlamb
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yaml@9cef0e4333a2ede7148579bda8474fa2c37ebe8c -
Trigger Event:
push
-
Statement type:
File details
Details for the file opengate_grounding-0.1.0-py3-none-any.whl.
File metadata
- Download URL: opengate_grounding-0.1.0-py3-none-any.whl
- Upload date:
- Size: 9.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4aae6f1eea0912618fa93e3141612c9a7e30d79eef4d07a4d69dfcc65d8de10b
|
|
| MD5 |
76e6cdf0e095e44651ca3ba50ac620f4
|
|
| BLAKE2b-256 |
251b512e87548101f4eb502c5f638f74fd633e894999abcff429f33274679495
|
Provenance
The following attestation bundles were made for opengate_grounding-0.1.0-py3-none-any.whl:
Publisher:
python-publish.yaml on nickjlamb/opengate
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
opengate_grounding-0.1.0-py3-none-any.whl -
Subject digest:
4aae6f1eea0912618fa93e3141612c9a7e30d79eef4d07a4d69dfcc65d8de10b - Sigstore transparency entry: 2084853125
- Sigstore integration time:
-
Permalink:
nickjlamb/opengate@9cef0e4333a2ede7148579bda8474fa2c37ebe8c -
Branch / Tag:
refs/tags/opengate-py-0.1.0 - Owner: https://github.com/nickjlamb
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yaml@9cef0e4333a2ede7148579bda8474fa2c37ebe8c -
Trigger Event:
push
-
Statement type: