lexrag / app /validate.py
RV302001's picture
Initial commit: LexRAG hybrid legal RAG
cc0207f
Raw
History Blame Contribute Delete
1.92 kB
"""Citation validation: strip any [bracketed] citation not in the retrieved set.
Guards against hallucinated case names. A citation is kept only if its text
matches (substring, case-insensitive) one of the retrieved source case names.
"""
from __future__ import annotations
import re
_CITATION_RE = re.compile(r"\[([^\[\]]+)\]")
def _matches_any(cited: str, allowed: list[str]) -> bool:
c = cited.strip().lower()
if not c:
return False
for name in allowed:
n = name.lower()
# Accept exact, or either being a substring of the other (handles the
# model truncating/expanding the case name slightly).
if c == n or c in n or n in c:
return True
return False
def validate_answer(answer: str, sources: list[dict]) -> dict:
"""Drop hallucinated citations. Return {answer, removed:[...]}.
Kept citations stay bracketed. Unknown ones are unwrapped (text retained,
brackets removed) and reported in `removed`.
"""
allowed = [s["case_name"] for s in sources]
removed: list[str] = []
def _sub(m: re.Match) -> str:
cited = m.group(1)
if _matches_any(cited, allowed):
return m.group(0) # keep bracketed citation
removed.append(cited)
return cited # strip brackets, keep raw text
cleaned = _CITATION_RE.sub(_sub, answer)
return {"answer": cleaned, "removed": removed}
if __name__ == "__main__":
srcs = [{"case_name": "Jimmy Jahangir Madan vs Bolly Cariyappa Hindley By L.Rs on 10 August, 2001"}]
raw = (
"The application under Section 302 was held not maintainable "
"[Jimmy Jahangir Madan vs Bolly Cariyappa Hindley By L.Rs on 10 August, 2001]. "
"A different rule applied [Fake Hallucinated Case v Nobody 2099]."
)
out = validate_answer(raw, srcs)
print("CLEANED:\n", out["answer"])
print("\nREMOVED:", out["removed"])