feat(evaluation): independent OpenAI judge with abstention scoring (ADR-0018 increment 5) - #25
Merged
Merged
Conversation
…DR-0018 increment 5)
…DR-0018 increment 5)
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.
Summary
AnswerQualityJudge) behind whichRagasJudgegains a real OpenAI adapter (gpt-5.4-mini-2026-03-17), alongside the existing Gemini adapter, which now becomes an explicit development fallback.Qwen/Qwen3-Embedding-0.6Bin the default local configuration) for RAGAS embedding calls through Gemini, which would fail silently.judge.embedding_modelis now a separate configuration key.Details
evaluation/judge_ports.py:ModelIdentity,JudgeSample,JudgeResult, andAnswerQualityJudge(aProtocolexposing.identityand.evaluate(sample)).ragas_judge.py:RagasJudge.evaluate(sample) -> JudgeResult; newbuild_openai_ragas_judgeusinginstructor.from_provider("openai/...")andOpenAIEmbeddings.reasoning_effortis passed directly toInstructorLLM, verified against the library’s actual implementation, which already handlesgpt-5.*models as reasoning models.build_gemini_ragas_judgewas adapted accordingly. Abstention is evaluated through a dedicated structured call because RAGAS has no native metric for it. It uses a second, isolatedInstructorLLMinstance with its own PT-BR prompt, so it does not affect RAGAS’s internal prompts.JudgeResultcontains only what RAGAS actually produces—a scalar score—rather than the structuredunsupported_claimsandrationalefields shown in the ADR’s illustrative JSON, which would require abandoning RAGAS’s built-in classes.answer_harness.py: every question, including unanswerable ones, now goes throughretrieve → generate → judge;citation_accuracyremains absent from the metrics dictionary only for unanswerable questions; addsabstention_appropriateandcitation_n, which now differs fromanswer_nbecause the two groups have different sizes.run.py: adds_build_judge_factory, fail-closed and following the same pattern as_build_embedder; addsjudge_provider,judge_reasoning_effort,judge_prompt_version, andjudge_label("exploratory_same_provider_judge"whenjudge_provider == "gemini") to the manifest and--resumevalidation; adds an abstention column to the answer-quality table.benchmark-v01.yaml: the default is nowjudge.provider: openai.openaifrom a transitive dependency to a direct dependency inpyproject.toml. No package is actually added because it was already resolved throughragas/instructor.evaluation/judge_calibration.pyandscripts/judge_calibration_report.py: Cohen’s weighted kappa, Spearman correlation usingstatistics.correlationfrom the standard library with no new dependency, false-supported/unsupported rates, and abstention agreement. The mechanism is ready to consume real human-labeled data once it becomes available.Out of scope (deferred and documented in the code)
factual_correctness—requires reference answers, which the golden set does not include, an inherited gap from ADR-0007.gpt-oss-20b)—the ADR itself marks it as experimental.Test plan
uv run pytest— 351 passed, 20 integration tests deselecteduv run mypy src tests— 0 issues across 157 filesuv run python scripts/quality_gate.py— all checks pass (lint, formatting, architecture, MCP, typing, tests, and security/Bandit) except dependency auditing (pip-audit):gitpython 3.1.53has three known advisories fixed in3.1.54. Confirmed viagit stashthat this issue already exists onmainand predates this increment; traced withuv tree --inverttostreamlit, an unrelated direct dependency.grep AnswerJudge/grep judge.score\(acrosssrc/andtests/— no orphaned references found