M2X-046: RAGAS harness, citation accuracy and abstention scoring - #38
Open
yashpancholi09 wants to merge 2 commits into
Open
M2X-046: RAGAS harness, citation accuracy and abstention scoring#38yashpancholi09 wants to merge 2 commits into
yashpancholi09 wants to merge 2 commits into
Conversation
`uv run m2x eval rag` produces the three PRD gate numbers plus abstention. The design's organising idea is that the four figures are NOT the same kind of claim, and the report prints that rather than leaving it to a reader's memory: context precision and faithfulness are a language model's opinion, citation accuracy and abstention are mechanical. On the zero-spend stack the judge shares the answerer's weights -- both default to Llama-3.1-8B, because there is no stronger free judge. A judge with the answerer's blind spots inflates faithfulness in exactly the cases where the answerer is confidently wrong. So --judge-model is a flag and the judge id is on every results row. Citation accuracy is ours, per the ticket: it must fail a citation whose text merely sounds right but points at the wrong segment, and no similarity metric can do that. A citation is correct iff the chunk it names covers turns overlapping a ground-truth span in the same meeting. Text never enters. The sanity case proving it lifts the quote verbatim from the CORRECT passage and attaches it to the WRONG chunk. Micro rather than macro, so one sloppy answer with six citations cannot hide behind a careful one with one; uncited answers counted separately, because a system that stopped citing would otherwise score 0.0 for having no denominator. Abstention is scored as correctness, not as a rate. An undifferentiated rate would let a system that declines everything score 5/30 and read as cautious. RAGAS needed langchain-community pinned below 0.4: ragas 0.4.3 imports langchain_community.chat_models.vertexai, which 0.4.x removed. Worth recording that the import chain reaches a Vertex AI (Gemini) integration, and Gemini is banned by CLAUDE.md -- nothing calls it, but the dependency is there. DEFECT FOUND LIVE, which no unit test could have caught. The bridge implemented the three methods BaseRagasLLM declares abstract; RAGAS's metrics call `generate`, the base class's async wrapper. 8 of 22 judged questions failed. The harness takes its judge as an injected callable -- deliberately, so the mechanical half is testable without the optional dependency -- so no RAGAS code ran until the live command did. A wrapper around a third-party interface is only tested by the third party. The fix is one method. The lesson is a surface test comparing the bridge's public callables against BaseRagasLLM's, which immediately found a second gap (get_temperature) that had never reached a live run at all. LIVE BASELINE, after the fix: context precision 0.4649, faithfulness 0.6667, citation accuracy 0.7857, abstention accuracy 0.4333. All four legs fail, which is the honest Phase 2 starting point and better had a day early than at the gate. Citation accuracy and abstention are byte-identical across the broken-judge and fixed-judge runs, confirming the mechanical half is independent of RAGAS in practice and not only in the design. The shape matters more than the numbers: 5/5 unanswerable correct but only 7/20 single-meeting. The system abstains on answerable questions because the quote check cannot match transcript text -- reference turns carry <FILL/>, <UNKNOWN/> and <PName> annotation tags a model quoting what it reads will not reproduce. day4-ask.md hit this with markdown and fixed it for emphasis; transcripts break it harder. That is a defect in `m2x ask`, not in the harness, and three candidate directions are recorded without one being taken. Two supporting changes, both additive. AskOutcome grew `hits`: it recorded `retrieved` as a count, so the only way to learn which turns a citation pointed at was to query the index again by id -- a second lookup that could disagree with the first and would silently move citation accuracy. chunk_segments was split out of chunk_transcript because a Transcript is an AdapterResult carrying provider, latency and cost, and the tiron reference was written by human annotators, so there is no such call to describe.
…lection The module's own docstring says it is skipped when the optional `ragas` group is absent, and `pytest.importorskip` was there to do it — one line below the `m2x.ragas_bridge` import it was meant to guard. `ragas_bridge` imports `langchain_core` at module scope, so on a default `uv sync` the import raised first and pytest aborted the whole run at collection, not just this file. `uv run pytest` on a fresh clone is the command `docs/gates.md` asks a supervisor to trust, so it has to work without an optional dependency group. default sync: 606 passed, 1 skipped --group ragas: 612 passed `m2x.cli` already defers the same import into the command body.
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.
uv run m2x eval ragproduces the three PRD gate numbers plus abstention.Stacked on
feature/m2x-045-rag-question-set.The four figures are not the same kind of claim
The report prints this rather than leaving it to a reader's memory. On the zero-spend stack the judge shares the answerer's weights — a judge with the answerer's blind spots inflates faithfulness exactly where the answerer is confidently wrong.
--judge-modelis a flag and the judge id is on every results row.Citation accuracy is ours, and text never enters it
The ticket names the property to review: it must fail a citation whose text merely sounds right but points at the wrong segment. No similarity metric can do that — sounding right is what a similarity metric rewards.
The sanity case proving it lifts the quote verbatim from the correct passage and attaches it to the wrong chunk. Any check consulting the text passes it.
Micro not macro, so one sloppy answer with six citations cannot hide behind a careful one with one. Uncited answers counted separately, because a system that stopped citing would otherwise score 0.0 for having no denominator. The 1-based/0-based boundary is crossed in exactly one tested function.
Defect found live, which no unit test could have caught
The first run failed on 8 of 22 judged questions:
'AdapterRagasLLM' object has no attribute 'generate'. The bridge implemented the three methodsBaseRagasLLMdeclares abstract; RAGAS's metrics callgenerate, the base's async wrapper.The unit suite could not have found it — the harness takes its judge as an injected callable, so no RAGAS code ran until the live command did. A wrapper around a third-party interface is only tested by the third party.
The fix is one method. The lesson is a surface test comparing the bridge's public callables against
BaseRagasLLM's — which immediately found a second gap (get_temperature) that had never reached a live run at all.Live baseline — all four legs fail
Citation accuracy and abstention are identical across both runs — as they must be, since neither touches the judge. A useful accident: it confirms the mechanical half is independent of RAGAS in practice, not only in the design.
single_meeting 7/20 · cross_meeting 1/5 · unanswerable 5/5The shape matters more than the numbers. The system abstains on most answerable questions while abstaining correctly on every unanswerable one — the safe direction to fail in, but a failure. Cause: the quote check. Reference turns carry
<FILL/>,<UNKNOWN/>and<PName>annotation tags, so a model quoting what it reads cannot reproduce the stored string byte for byte.day4-ask.mdhit this with markdown and fixed it for emphasis; transcripts break it harder.That is a defect in
m2x ask, not in the harness, and it belongs to the Friday gate ticket. Three candidate directions recorded, none taken.What Friday inherits, ranked — none is a harness change
top_k = 5, never varied — five passages for a question one turn answers is four irrelevant contexts by construction. Likely most of the context-precision gap, and the cheapest experiment available.max_distance = 0.48, resting on eight questions. Every results row now carriesnearest_distanceper question, so thirty measurements can replace the eight without another live run.Dependency notes for review
ragas 0.4.3importslangchain_community.chat_models.vertexai, removed in 0.4.x — pinnedlangchain-community<0.4. Worth flagging that the import chain reaches a Vertex AI (Gemini) integration and Gemini is banned byCLAUDE.md; nothing calls it, but the dependency is there, and a sunset package under the gate's tree is a liability.ragasis an optional group. The harness injects its judge, so the mechanical half and all three ticket-mandated sanity cases run on a fresh clone without it.AskOutcomegrewhits(additive): it recordedretrievedas a count, so learning which turns a citation pointed at needed a second index lookup that could disagree with the first.chunk_segmentssplit out ofchunk_transcript: aTranscriptis anAdapterResultcarrying provider/latency/cost, and the tiron reference was written by human annotators — there is no such call to describe.612 tests green (27 new).