Skip to main content
LLM judge evaluators use a secondary model to assess output quality. multivon-eval uses QAG scoring (Question-Answer Generation) — generating binary yes/no questions about the output instead of asking for a numeric 1-10 rating. Why QAG? Binary questions make the grading criteria inspectable and avoid numeric scale ambiguity. They can require several model calls per output. Accuracy and cost depend on the task, generated questions, and judge; QAG is not a general accuracy guarantee.

Configuration

JudgeConfig

The judge model is fully decoupled from your pipeline model. Configure it once globally, override per-evaluator, or fall back to environment variables.
Resolution order (highest to lowest):
  1. Per-evaluator judge= kwarg
  2. configure() global
  3. JUDGE_PROVIDER / JUDGE_MODEL environment variables
  4. Built-in default: anthropic / claude-haiku-4-5
Changed in 0.16.0: temperature, max_tokens, timeout, and reliability_sample now default to None, meaning “inherit from the global config” — they resolve to the same effective defaults as before. The old merge compared overrides against the default values, so an explicit JudgeConfig(temperature=0.0) was silently ignored whenever a nonzero global was configured. Explicit values — including 0.0 — now always win.
Fixed in 0.16.1 — reasoning-tier judges. The QAG evaluators used small per-call caps (100 tokens for a yes/no verdict, 512 for claim extraction). That is plenty for a plain-text judge, but a reasoning model spends part of its output budget thinking before it answers, so those caps cut it off mid-thought and it returned an empty verdict. We measured a 47% error rate running gpt-5.5 as the judge. The per-call ceiling is now floored at 2048 tokens when the judge model is reasoning-tier (gpt-5/o1/o3/o4 prefixes). Every other judge is unaffected — its cap passes through untouched. Evaluator-specific per-call caps take precedence over the global JudgeConfig.max_tokens; the reasoning-model floor applies to that per-call cap.
The model under test and the judge model can be different providers.
In 0.17.0 the native Anthropic and OpenAI text-judge request paths do not forward JudgeConfig.temperature; Ollama uses the OpenAI path and shares this limitation. Google and LiteLLM do forward it. The resolved configuration is therefore not a complete record of effective sampling behavior. Temperature zero also does not guarantee identical outputs. timeout is forwarded to supported clients.

Local and self-hosted models

Any OpenAI-compatible server works as a judge — Ollama, LM Studio, vLLM, llama.cpp, or a self-hosted endpoint:
base_url is also read from the OPENAI_BASE_URL environment variable, so no code changes are needed to switch between cloud and local judges in CI.

Calibrated thresholds

Faithfulness, Hallucination, and Relevance look up historical threshold packs for the configured judge. These are starting points, not proof of calibration on your task. HaluEval task subsets include generated hallucinations; see the benchmark methodology. Validate thresholds against separate, human-reviewed development and test sets for your domain, especially after changing the judge or parser. This table is an excerpt; threshold_table() lists all shipped entries. Pass threshold= explicitly to override:
To inspect the full calibration table:

UNKNOWN verdicts

New in 0.16.0. QAG scoring asks the judge binary yes/no questions — but judges hedge, and a hedge is not a verdict. The parser now has three outcomes per question:
  • In 0.17.0, a leading “yes”/“no” verdict or a complete explicit phrase such as “The answer is yes.” parses as a verdict. Mentions inside explanations (“I cannot say yes”) and “yes or no” are UNKNOWN. Historical threshold measurements predate this stricter parser and need revalidation.
  • A reply with no unambiguous verdict is UNKNOWN: excluded from the score denominator entirely and disclosed in the result reason, e.g. 1 of 3 question(s) UNKNOWN — excluded from score denominator. An UNKNOWN never counts for or against the model.
  • If every verdict for a case is unparseable, the evaluator raises JudgeUnavailable and the case gets JUDGE_ERROR status — excluded from pass_rate, counted in report.errors.
One honest sentence about the past: before 0.16.0 the parser fell back to “does ‘yes’ appear in the first 50 characters”, so a judge replying “I cannot say yes or no with certainty” was scored as YES. That yes-bias is gone; the previously mis-scored tail is now UNKNOWN.

Error budget: max_error_rate

pass_rate excludes errored cases by design — a judge outage is not a quality regression. Since 0.17.0, an active fail_threshold gate rejects any error by default. An explicit max_error_rate permits a chosen error budget:
Available on suite.run, run_async, and run_on_cases. With max_error_rate unset, an active fail_threshold gate uses a zero-error budget. Empty and skipped coverage also make the gate indeterminate (exit code 2). A completed quality failure exits 1. Runs with neither gate configured still return a report for inspection. report.error_rate exposes the number directly (denominator is total, not evaluated — this is exactly the metric pass_rate cannot see, so read the two together).

Faithfulness

Extracts factual claims and checks their support in the provided context. The extractor can omit claims, so even a perfect score does not prove full grounding. When to use: RAG pipelines, document Q&A, or any task where the model must answer strictly from a provided source.
Requires context on the EvalCase.
Changed in 0.19.0: every unique extracted claim must receive a valid verdict. Empty extraction or exceeding max_claims returns a skipped measurement, not a pass. Invalid claim types raise an evaluator error; any unknown verdict raises JudgeUnavailable. Older versions could pass an empty list, score a ten-claim prefix, or omit unknown verdicts.
For development checkouts, Faithfulness(threshold=0.9, max_claims=30) allows up to 30 unique extracted claims. This can require one extraction call plus 30 verification calls before provider retries. Exact duplicates are collapsed after trimming whitespace. Results retain extracted/unique/verified counts, raw extraction and verdict replies, and the effective threshold. These fields expose the observed coverage, not extraction completeness. Use an AcceptancePolicy requiring faithfulness when missing measurements must block acceptance. A skipped faithfulness result can coexist with another passing check, so aggregate case pass rates alone do not enforce required-check coverage. Regrade saved outputs or rerun cases before using new results in comparisons; the old calibration packs have not been revalidated for this protocol.

Hallucination

Checks that the output doesn’t introduce claims not supported by context. When to use: Complement to Faithfulness — Faithfulness checks what’s present in the answer; Hallucination checks what shouldn’t be there.
Requires context.

Relevance

Checks that the output actually addresses the input question. When to use: Catch evasive, off-topic, or boilerplate responses that technically answer but don’t address what was asked.
No context required.

Coherence

Checks that the output is clear, well-structured, and logically sound. When to use: Long-form generation (articles, reports, explanations) where logical flow and clarity matter.

Toxicity

Checks that the output is safe, non-harmful, and appropriate. When to use: User-facing products, content moderation pipelines, or any deployment where harmful output is unacceptable. Score 1.0 = not toxic; 0.0 = toxic.

Bias

Checks that the output is free of demographic, political, or cultural bias. When to use: HR tools, news summarizers, recommendation systems, or any application where systematic favoritism is a risk. Score 1.0 = no bias detected; 0.0 = significant bias.

Summarization

Checks that a summary captures the key points of the source faithfully, without adding or omitting critical information. When to use: Summarization pipelines — news, legal documents, meeting transcripts.
Requires context (the source document).

AnswerAccuracy

Checks factual correctness of the output against expected_output. Uses judge comparison rather than string matching, so paraphrasing is handled correctly. When to use: Knowledge QA, fact retrieval, or any task with a known correct answer where the phrasing may vary.

ContextPrecision

For RAG systems: checks that retrieved context chunks are actually relevant to the question. High precision = low noise in retrieval. When to use: Evaluating the retrieval stage of a RAG pipeline independently from generation.
Accepts context as either a string or a list of strings (chunks). Evaluates up to 8 chunks.

ContextRecall

For RAG systems: checks that the retrieved context contains everything needed to derive the expected answer. When to use: Diagnosing retrieval gaps — cases where the model gave a wrong answer because the right chunk wasn’t retrieved.
Requires both context and expected_output.

CustomRubric

Define your own yes/no criteria. Each criterion is a (question, expected_answer) tuple. Score = fraction of criteria where the judge’s answer matches expected_answer. When to use: Domain-specific quality checks that don’t map to the built-in evaluators — support tone, legal disclaimers, brand voice.

GEval

Holistic numeric scoring for qualities that don’t decompose well into yes/no questions (creativity, tone, polish). The judge returns a 0.0–1.0 score directly with reasoning. When to use: Subjective qualities like writing style, creativity, or polish where binary questions don’t capture the nuance. Use sparingly — less auditable than QAG evaluators.
GEval is the only evaluator that uses a numeric score directly from the judge rather than QAG aggregation.

CheckEvaluator

The fastest way to add a quality check. You write a plain-English criterion; CheckEvaluator auto-generates specific yes/no questions from it and scores with QAG. No need to pick an evaluator class or write questions manually.
Questions are generated once at the start of suite.run() (eager warmup), so no case pays the generation cost and failures surface before the eval loop starts.

Escape hatch: pin questions for CI

Generated questions vary per run and per model. For reproducible CI runs, pin them explicitly:
When questions= is set, no LLM call is made during prepare().

Inspect generated questions

Discrete scores for N questions

With the default num_questions=3, the only possible scores are 0.0, 0.33, 0.67, and 1.0. The default threshold of 0.7 therefore requires 3/3 questions to pass. Lower the threshold or use num_questions=5 if you want more granularity.

Fallback behavior

If question generation fails after two attempts, CheckEvaluator issues a warnings.warn and falls back to using the criterion itself as a single yes/no question. The EvalResult reason will include a [⚠ question generation failed — using fallback] tag. Check ev._used_fallback programmatically.