Anti-hallucination: 5-layer grounding layer (quote verify, trigger va…#5
Merged
Conversation
…lidate, majority-vote referee, score clamp, schema guard) (2026-06-27)
There was a problem hiding this comment.
Pull request overview
This PR introduces a new “grounding” layer in the backend engines to reduce LLM hallucinations and enforce safer, more consistent structured outputs for adversary and scoring responses.
Changes:
- Added
backend/app/engines/grounding.pyimplementing quote verification, trigger validation, self-consistency voting, score clamping, and schema guards. - Integrated grounding into scoring (
validate_score_output,verify_scoring_quotes) and adversary response generation (validate_adversary_output, trigger validation, majority-vote referee).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| backend/app/engines/scoring.py | Applies score schema validation + quote grounding to judge output before persisting results. |
| backend/app/engines/grounding.py | New grounding utilities: schema/type guards, quote verification, trigger validation, majority vote, score clamping. |
| backend/app/engines/adversary.py | Adds adversary output schema guard; gates concessions via trigger validation + majority-vote referee. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+176
to
+179
| def validate_adversary_output(out: dict) -> dict: | ||
| """Enforce schema on adversary JSON: required fields, correct types.""" | ||
| _ensure_str(out, "reply", "[No response generated]") | ||
| _ensure_bool(out, "conceded", False) |
Comment on lines
+188
to
+192
| def validate_referee_output(out: dict) -> dict: | ||
| """Enforce schema on referee JSON.""" | ||
| _ensure_bool(out, "earned", False) | ||
| _ensure_str(out, "reason", "No reason provided.") | ||
| return out |
Comment on lines
+195
to
+200
| def validate_score_output(out: dict) -> dict: | ||
| """Enforce schema on scoring JSON and clamp numeric fields.""" | ||
| if not isinstance(out.get("rubric_results"), list): | ||
| out["rubric_results"] = [] | ||
| if not isinstance(out.get("dimension_scores"), dict): | ||
| out["dimension_scores"] = {d: {"score": 0, "max": 0} for d in _DIMENSION_NAMES} |
Comment on lines
+127
to
+130
| _DIMENSION_NAMES = { | ||
| "Position Defense", "Concession Strategy", | ||
| "Anchoring & Offers", "Pressure Resistance", "Legal Reasoning", | ||
| } |
Comment on lines
+64
to
+66
| if any_fixed: | ||
| result["_grounding_corrections"] = True | ||
| return result |
Comment on lines
+204
to
+212
| gate = grounding.majority_vote( | ||
| _referee, | ||
| args=(sc, user_msg, claimed, difficulty), | ||
| kwargs={}, | ||
| n=3, | ||
| key="earned", | ||
| ) | ||
| gate = grounding.validate_referee_output(gate) | ||
| if not gate.get("earned"): |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
…lidate, majority-vote referee, score clamp, schema guard) (2026-06-27)