Nearly every judge that behaves oddly is a rubric problem, not a model problem. The rubric is the part you own, and it is the part worth the
time.
from pydantic_evals import Case, Dataset
from pydantic_evals.evaluators import LLMJudge
dataset = Dataset(
cases=[Case(inputs='Can I return this after 40 days?')],
evaluators=[
LLMJudge(
rubric=(
'The answer states the 30-day return window and does not '
'invent an exception to it. Refusing to answer is not a pass.'
),
include_input=True,
model='openai:gpt-5-mini',
assertion={
'evaluation_name': 'refund_policy',
'include_reason': True,
},
),
],
)
report = dataset.evaluate_sync(answer_question)
import {
Case, Dataset, LLMJudge, setDefaultJudge,
} from 'logfire/evals'
setDefaultJudge(async ({ output, rubric }) =>
askYourModel(output, rubric)
)
const dataset = new Dataset({
cases: [new Case({ inputs: 'Can I return this after 40 days?' })],
evaluators: [
new LLMJudge({
rubric:
'The answer states the 30-day return window and does not ' +
'invent an exception to it. Refusing to answer is not a pass.',
includeInput: true,
assertion: { evaluationName: 'refund_policy' },
}),
],
})
const report = await dataset.evaluate(answerQuestion)
Name the failure, not the virtue
A rubric describing what good looks like leaves the judge to guess where the line is, and it will put the line somewhere different next week. Describe the specific thing that would make this output wrong. 'Invents a policy exception' is checkable. 'Is helpful' is not.
Say what does not count as a pass
Judges are agreeable. A rubric that only describes success finds success, including in an answer that dodged the question politely. Adding the failure case, such as a refusal not counting as a pass, changes the verdict on exactly the outputs you built the eval to catch.
One rubric, one question
A rubric asking about grounding and tone and length returns one verdict for three different things, and you cannot tell which one failed. Separate judges cost more and tell you where the problem is, which is the reason you are running this at all.
Show it what it needs
include_input and include_expected_output are both off by default. A rubric about whether the answer addressed the question cannot work without the question, and this is the usual cause of a judge that scores confidently and wrongly.