LeetLLM
My PlanLearnGlossaryTracksPracticeBlog
LeetLLM

Your go-to resource for mastering AI & LLM systems.

Product

  • Learn
  • Glossary
  • Tracks
  • Practice
  • Blog
  • RSS

Legal

  • Terms of Service
  • Privacy Policy

© 2026 LeetLLM. All rights reserved.

All Topics
Your Progress
0%

0 of 196 articles completed

🛠️Computing Foundations0/9
Git, Shell, Linux for AIDocker for Reproducible AIPython for AI EngineeringNumPy and Tensor ShapesCUDA for ML TrainingMPS & Metal for ML on MacData Structures for AISQL and Data ModelingAlgorithms for ML Engineers
📊Math & Statistics0/9
Gradients and BackpropVectors, Matrices & TensorsLinear Algebra for MLAdam, Momentum, SchedulersProbability for Machine LearningBayesian Inference from EvidenceStatistics and UncertaintyDistributions and SamplingHypothesis Tests, Intervals, and pass@k
📚Preparation & Prerequisites0/13
Neural Networks from ScratchCNNs from ScratchTraining & BackpropagationSoftmax, Cross-Entropy & OptimizationRNNs, LSTMs, GRUs, and Sequence ModelingAutoencoders and VAEsThe Transformer Architecture End-to-EndLanguage Modeling & Next TokensFrom GPT to Modern LLMsPrompt Engineering FundamentalsCalling LLM APIs in ProductionFirst AI App End-to-EndThe LLM Lifecycle
🧮ML Algorithms & Evaluation0/15
Linear Regression from ScratchLogistic Regression and MetricsDecision Trees, Forests, and BoostingReinforcement Learning BasicsValidation and LeakageStatistical Learning and GeneralizationConformal Prediction and UncertaintyClustering and PCAProbabilistic Generative ModelsCore Retrieval AlgorithmsDecoding AlgorithmsExperiment Design and A/B TestingCausal Inference and CounterfactualsPyTorch Training LoopsDataset Pipelines and Data Quality
📦Production ML Systems0/6
Feature Engineering for Production MLBatch and Streaming Feature PipelinesGradient Boosted Trees in ProductionRanking and Recommendation SystemsForecasting and Anomaly DetectionMonitoring Predictive Models
🧪Core LLM Foundations0/8
The Bitter Lesson & ComputeBPE, WordPiece, and SentencePieceStatic to Contextual EmbeddingsPerplexity & Model EvaluationFile Ingestion for AIChunking StrategiesLLM Benchmarks & LimitationsInstruction Tuning & Chat Templates
🧰Applied LLM Engineering0/25
Dimensionality Reduction for EmbeddingsCoT, ToT & Self-Consistency PromptingFunction Calling & Tool UseMCP & Tool Protocol StandardsContext EngineeringPrompt Injection DefenseResponsible AI GovernancePrivacy-Preserving Machine LearningData Labeling and Human FeedbackEvaluating AI AgentsProduction RAG PipelinesHybrid Search: Dense + SparseReranking and Cross-Encoders for RAGRAG Evaluation for Reliable AnswersLLM-as-a-Judge EvaluationBias & Fairness in LLMsHallucination Detection & MitigationLLM Observability & MonitoringExperiment Tracking with MLflow and W&BPrompt Optimization with DSPyModel Versioning & DeploymentSemantic Caching & Cost OptimizationLLM Cost Engineering & Token EconomicsModel Gateways, Routing, and FallbacksDesign an Automated Support Agent
🎓Portfolio Capstones0/9
Capstone: Delivery ETA PredictionCapstone: Product RankingCapstone: Demand ForecastingCapstone: Image Damage ClassifierCapstone: Production ML PipelineCapstone: Document QACapstone: Eval DashboardCapstone: Fine-Tuned ClassifierCapstone: Reproducible ML Study
🧠Transformer Deep Dives0/8
Sentence Embeddings & Contrastive LossEmbedding Similarity & QuantizationScaled Dot-Product AttentionVision Transformers and Image EncodersPositional Encoding: RoPE & ALiBiLayer Normalization: Pre-LN vs Post-LNMechanistic InterpretabilityDecoding Strategies: Greedy to Nucleus
🧬Advanced Training & Adaptation0/17
Scaling Laws & Compute-Optimal TrainingPre-training Data at ScaleBuild GPT from Scratch LabJAX for PyTorch ResearchersContinued Pretraining for Domain ShiftSynthetic Data PipelinesSupervised Fine-Tuning PipelineMixed Precision TrainingDistributed Training: FSDP & ZeROLoRA & Parameter-Efficient TuningTraining Run OperationsReward Modeling from Preference DataRLHF & DPO AlignmentConstitutional AI & Red TeamingRLVR & Verifiable RewardsKnowledge Distillation for LLMsModel Merging and Weight Interpolation
🤖Advanced Agents & Retrieval0/16
Vector DB Internals: HNSW & IVFAdvanced RAG: HyDE & Self-RAGGraphRAG & Knowledge GraphsRAG Security & Access ControlStructured Output GenerationReAct & Plan-and-ExecuteGuardrails & Safety FiltersCode Generation & SandboxingComputer-Use / GUI / Browser AgentsHuman-in-the-Loop Agent ArchitectureAI Coding Workflow with AgentsAgent Memory & PersistenceAgent Failure & RecoveryRecursive Language Models (RLM)Multi-Agent OrchestrationCapstone: Production Agent
⚡Inference & Production Scale0/31
Inference: TTFT, TPS & KV CacheMulti-Query & Grouped-Query AttentionKV Cache & PagedAttentionPrefix Caching and Prompt CachingFlashAttention & Memory EfficiencyContinuous Batching & SchedulingScaling LLM InferenceModel Parallelism for LLM InferenceAccelerator Architecture Field GuideCorrect GPU Profiling and BenchmarkingGPU Kernel Performance Engineering LabGPU Parallel Primitives LabGPU Compilers and Kernel LanguagesGEMM From Naive CUDA to Tensor CoresLow-Precision GPU ProgrammingGPU Runtime Execution LabAI-Generated Kernel EngineeringModel Quantization: GPTQ, AWQ & GGUFLocal LLM DeploymentSLM Specialization & Edge DeploymentSpeculative DecodingLong Context Window ManagementMixture of Experts ArchitectureMamba & State Space ModelsReasoning & Test-Time ComputeAdvanced MLOps & DevOps for AIGPU Serving & AutoscalingGPU Failure OperationsDistributed Inference Data PlaneServing Benchmark EngineeringA/B Testing for LLMs
🏗️System Design Capstones0/9
Content Moderation SystemCode Completion SystemMulti-Tenant LLM PlatformLLM-Powered Search EngineVision-Language Models & CLIPMultimodal LLM ArchitectureDiffusion Models: Images & TextReal-Time Voice AI AgentReasoning Agent System Design
🎤AI Lab Interviewing0/4
AI Lab Coding Interview: Python SystemsAI Lab System Design InterviewAI Lab Behavioral InterviewAI Lab Technical Presentation
🔬Project Deep Dives0/17
Deep Dive - vLLMDeep Dive - SkyRLDeep Dive - FlashAttentionDeep Dive - FlashInferDeep Dive - DeepGEMMDeep Dive - NCCLDeep Dive - MegatronDeep Dive - DeepSpeedDeep Dive - RayDeep Dive - MLflowDeep Dive - PyTorchDeep Dive - TransformersDeep Dive - SGLangDeep Dive - slimeDeep Dive - DeepEPDeep Dive - TinkerDeep Dive - Light-PEFT
Back to Topics
LearnApplied LLM EngineeringLLM-as-a-Judge Evaluation
📊MediumEvaluation & Benchmarks

LLM-as-a-Judge Evaluation

Add calibrated soft judgments to a RAG evaluation trace without letting an LLM override deterministic evidence gates.

23 min read
Learning path
Step 75 of 196 in the full curriculum
RAG Evaluation for Reliable AnswersBias & Fairness in LLMs

Personalize this lesson

Adapt explanations and teaching visuals to your background and preferred voice.

Maya's payment service crossed its rollback threshold. The selected DEP-27 policy requires a rollback runbook, not continued deployment, and the evidence checks have already confirmed that boundary. Now a large language model (LLM) judge compares two generated replies that preserve the same remedy. Which one would you want an on-call engineer to read first?

Read the two candidates before naming the evaluator:

CandidateReplyHard evidence status
brief"Payment-service crossed the rollback threshold; run the rollback runbook under DEP-27."Supported
actionable"Payment-service crossed the rollback threshold. DEP-27 requires rollback; run its rollback runbook."Supported

Both respect the selected evidence. The remaining question is softer: does the second wording make the required action clearer without becoming wordy or confusing?

Make one prediction before we add a model to this path: if a third reply said “keep deploying,” should a high helpfulness score rescue it? No. Eligibility and policy truth need exact assertions; clarity, actionability, and concision are the remaining questions for a soft evaluator.

An LLM-as-a-judge uses another LLM as an evaluator for quality that can't be fully decided by an exact assertion. It can compare clarity, helpfulness, or tone under a rubric. It mustn't decide whether restricted context was allowed or whether a policy claim is supported. Those remain deterministic gates.

In their MT-Bench and Chatbot Arena study, Zheng et al. report over 80% agreement between GPT-4 judgments and human preferences, at the level of human-human agreement in their setup. The same paper reports position bias (most judges favored the first slot), verbosity bias, self-enhancement (preferring a model's own answers), and limited reasoning. A judge is useful measurement equipment, not ground truth.[1]Reference 1Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena.https://arxiv.org/abs/2306.05685

Keep facts outside the judge

Start by naming the decision, not the model. In this deploy-policy pipeline, each question has a different owner:

QuestionCorrect evaluatorWhy
Did selected evidence pass access and freshness checks?Code gateA soft score must never admit forbidden evidence.
Does the answer advise continued deployment when DEP-27 requires rollback?Claim-to-source verifierPolicy truth is inspectable.
Which supported answer is clearer and more actionable?Calibrated judge or humanReasonable reviewers can compare phrasing.
Is the case sensitive, ambiguous, or outside rubric coverage?Human reviewerUncertainty is part of the decision.

Only the third row changes in this lesson. The previous lesson split retrieval failures from generation failures with candidate recall, selected-context recall, claim support, and citation support.

Soft scores for context relevance, groundedness, and answer relevance can help with paraphrase-heavy residual risk, but they mustn't reopen authorization or DEP-27 policy truth.

⚠️ Common mistake: Claim support for release-critical policy stays deterministic (the claim ledger and source gates from RAG Evaluation for Reliable Answers). Judge "faithfulness" or groundedness scores are only for paraphrase-heavy residual risk after those hard gates pass. A soft faithfulness judge mustn't replace claim-to-source verification for DEP-27-style policy truth.

Three checkpoints make the contract explicit: deterministic gates decide eligibility, swapped comparisons test preference stability, and calibration plus bias probes decide whether the metric may guide a release.

Three-stage LLM judge flow: deterministic policy gate blocks unsupported continue-deploy replies, anonymous pairwise judging picks the actionable supported reply, and calibration still blocks metric promotion until agreement and probe checks pass.
Policy truth decides eligibility first. Pairwise judging ranks only supported replies, and calibration still decides whether that metric can guide release decisions.

Why should an exact required phrase or permission rule be checked outside an LLM judge?

Answer

Deterministic facts don't need probabilistic interpretation. Keep schema, exact evidence, and policy checks in code so the judge handles only the subjective dimensions that remain.

With eligibility separated from preference, we can now run the smallest useful lab: two safe answers and one answer that must never reach the judge.

Start with two supported answers

Before opening the code, predict the route: brief and actionable should pass, while unsafe_continue should be blocked. The lab uses an abbreviated hard gate so that boundary fits on one screen. The previous lesson built the complete evidence-path validator; here we reuse its result and add one unsafe counterexample to prove that no soft score can override it.

supported-candidates.py
1from dataclasses import dataclass 2 3@dataclass(frozen=True) 4class AnswerTrace: 5 request_id: str 6 selected_source_id: str 7 selected_version: str 8 admissible: bool 9 allowed_action: str 10 11trace = AnswerTrace( 12 request_id="incident-48291", 13 selected_source_id="dep-27-rollback-threshold", 14 selected_version="deploy-policy/2026-04-01", 15 admissible=True, 16 allowed_action="rollback", 17) 18 19answers = { 20 "brief": "Payment-service crossed the rollback threshold; run the rollback runbook under DEP-27.", 21 "actionable": ( 22 "Payment-service crossed the rollback threshold. DEP-27 requires rollback; " 23 "run its rollback runbook." 24 ), 25 "unsafe_continue": "Keep deploying payment-service while you monitor the graph.", 26} 27 28def hard_failures(answer: str, answer_trace: AnswerTrace) -> list[str]: 29 # Demo only: use the claim-to-source verifier from the RAG evaluation lesson in production. 30 failures: list[str] = [] 31 lowered = answer.lower() 32 if not answer_trace.admissible: 33 failures.append("selected evidence isn't admissible") 34 if "keep deploying" in lowered or "continue deploying" in lowered: 35 failures.append("answer advises unsupported continued deployment") 36 if answer_trace.allowed_action not in lowered: 37 failures.append("answer omits supported rollback action") 38 return failures 39 40safe_candidates = [ 41 name for name, answer in answers.items() if not hard_failures(answer, trace) 42] 43 44assert safe_candidates == ["brief", "actionable"] 45assert hard_failures(answers["unsafe_continue"], trace) == [ 46 "answer advises unsupported continued deployment", 47 "answer omits supported rollback action", 48] 49 50print(f"Evidence version: {trace.selected_version}") 51print(f"Candidates eligible for soft judging: {safe_candidates}") 52print(f"Blocked answer: {hard_failures(answers['unsafe_continue'], trace)[0]}")
Output
1Evidence version: deploy-policy/2026-04-01 2Candidates eligible for soft judging: ['brief', 'actionable'] 3Blocked answer: answer advises unsupported continued deployment

The output gives us the first invariant: only supported answers enter soft judging. If a judge later says unsafe_continue sounds friendlier, the answer still stays blocked, so we can experiment with the judge without moving the safety boundary.

Diagram showing brief reply, Hard-gate fail?, actionable reply, and unsafe_continue.
brief reply, Hard-gate fail?, actionable reply, and unsafe_continue.

The gate has reduced the problem to a safe pair. Before asking which reply wins, choose whether the evaluator should score one answer or compare two.

Choose the evaluator before writing the rubric

Not every evaluation question belongs to an LLM. Choose the measurement tool from the decision you need to make.

Zheng et al.'s paper names three shapes: pairwise comparison, single-answer grading, and reference-guided grading. This lab uses the first two as pairwise and pointwise shapes, while policy truth stays outside both.[1]Reference 1Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena.https://arxiv.org/abs/2306.05685

Here are the two soft-evaluation shapes that matter for the DEP-27 question:

ShapeQuestionBest fitMain control
PointwiseDoes one safe answer satisfy anchored quality criteria?Monitoring a single output when no direct alternative existsCalibrate category or score anchors against human labels
PairwiseWhich of two safe answers better satisfies the rubric?Comparing prompt or model variants on the same caseSwap candidate order, allow ties, and normalize slots back to reply identity

Predict the choice before running the next cell. rollback authorization has an exact oracle, clearer supported reply compares two safe variants, and new exception policy has no tested rubric anchor. Their routes should be code, pairwise judge, and human review in that order.

choose-the-evaluator.py
1@dataclass(frozen=True) 2class EvaluationQuestion: 3 name: str 4 has_exact_oracle: bool 5 compares_two_safe_variants: bool 6 requires_policy_owner: bool = False 7 8def choose_evaluator(question: EvaluationQuestion) -> str: 9 if question.has_exact_oracle: 10 return "deterministic_gate" 11 if question.requires_policy_owner: 12 return "human_review" 13 if question.compares_two_safe_variants: 14 return "pairwise_judge_with_calibration" 15 return "pointwise_judge_with_calibration" 16 17questions = [ 18 EvaluationQuestion("rollback authorization", True, False), 19 EvaluationQuestion("clearer supported reply", False, True), 20 EvaluationQuestion("new exception policy", False, False, True), 21] 22choices = {item.name: choose_evaluator(item) for item in questions} 23 24assert choices["rollback authorization"] == "deterministic_gate" 25assert choices["clearer supported reply"] == "pairwise_judge_with_calibration" 26assert choices["new exception policy"] == "human_review" 27 28for name, choice in choices.items(): 29 print(f"{name}: {choice}")
Output
1rollback authorization: deterministic_gate 2clearer supported reply: pairwise_judge_with_calibration 3new exception policy: human_review

The three printed routes follow the unresolved question, not a preferred vendor. With the evaluator shape chosen, the next job is to define what a win means.

Write a rubric for the remaining question

A vague instruction such as "pick the better answer" lets the evaluator reward length, politeness, or formatting arbitrarily. A rubric should name what remains undecided after hard checks and include anchors for a tie.

CriterionBetter answerTie conditionOutside judge scope
ActionabilityGives a useful, low-friction next stepBoth give the same useful next stepWhether the rollback threshold was crossed
ClarityStates remedy plainly without internal clutterBoth are equally clearWhether policy source is current
ConcisionAdds useful information without repetitionDifference is stylistic onlyWhether continued deployment is allowed

Turn those labels into observations a reviewer can repeat. After hard gates establish the rollback remedy, actionability passes when the reply names the immediate next step, is partial when the step is vague, and fails when no usable step appears.

Clarity passes when an engineer can identify outcome and action on first read, is partial when their relationship takes a second read, and fails when wording supports multiple actions. Concision passes when every sentence adds decision-useful detail, is partial when an extra sentence changes no action, and fails when repeated or ornamental text wins. A tie stays available whenever the difference is stylistic.

G-Eval asks a judge to generate evaluation steps and then fill a structured form for task-specific criteria. A named criterion plus a structured verdict is easier to audit than a free-form impression.[2]Reference 2G-Eval: NLG Evaluation using GPT-4 with Better Human Alignment.https://arxiv.org/abs/2303.16634

Freeze those anchors in the packet before sending it to a model API. Candidate names become anonymous slots, not model or prompt-version names. Protected facts appear as already validated context, so the judge can stay focused on preference instead of re-litigating authorization.

Before reading the output, predict what the packet should contain: the evidence version and hard-check result should remain visible for provenance, while literal names such as brief and actionable should be absent from the candidate slots.

pairwise-judge-packet.py
1from dataclasses import asdict 2 3@dataclass(frozen=True) 4class Criterion: 5 name: str 6 question: str 7 tie_anchor: str 8 9rubric = ( 10 Criterion( 11 name="actionability", 12 question="Does the reply give a safe, useful next action?", 13 tie_anchor="Neither answer gives a meaningfully better next action.", 14 ), 15 Criterion( 16 name="clarity", 17 question="Is the rollback outcome easy for an engineer to understand?", 18 tie_anchor="Both answers communicate the outcome equally clearly.", 19 ), 20 Criterion( 21 name="concision", 22 question="Does added wording contribute useful information rather than repetition?", 23 tie_anchor="The extra wording doesn't change usefulness.", 24 ), 25) 26 27def pairwise_packet(first_name: str, second_name: str) -> dict[str, object]: 28 assert first_name in safe_candidates and second_name in safe_candidates 29 return { 30 "case_id": trace.request_id, 31 "validated_context": { 32 "source_id": trace.selected_source_id, 33 "version": trace.selected_version, 34 "protected_fact": "The required action is rollback, not continued deployment.", 35 "hard_checks": "passed before judging", 36 }, 37 "candidates": { 38 "A": answers[first_name], 39 "B": answers[second_name], 40 }, 41 "rubric": [asdict(item) for item in rubric], 42 "allowed_verdicts": ["A", "B", "tie", "needs_human_review"], 43 } 44 45packet_ab = pairwise_packet("brief", "actionable") 46assert "brief" not in packet_ab["candidates"] 47assert "actionable" not in packet_ab["candidates"] 48 49print(f"Context gate: {packet_ab['validated_context']['hard_checks']}") 50print(f"Candidate slots: {list(packet_ab['candidates'])}") 51print(f"Rubric criteria: {[item['name'] for item in packet_ab['rubric']]}") 52print(f"Verdicts: {packet_ab['allowed_verdicts']}")
Output
1Context gate: passed before judging 2Candidate slots: ['A', 'B'] 3Rubric criteria: ['actionability', 'clarity', 'concision'] 4Verdicts: ['A', 'B', 'tie', 'needs_human_review']

The output confirms that separation: the packet carries provenance and an explicit verdict set, but the candidates are only A and B. In a deployed evaluator, serialize this packet, request structured output from the chosen judge model, and store the raw packet plus parsed verdict. Don't rely on a hidden prompt that can't be reproduced during a regression.

Treat the judge output as untrusted data

The judge is another model. Its JSON can be malformed, its evidence can be irrelevant, and its preference can contradict its own rationale. Parse and validate it as you would validate a tool result from an agent.

Predict the failure path: a decisive B with an evidence string instead of a list should be rejected before any winner is counted. The parser below treats the complete result as a contract, not the verdict field alone.

validate-judge-result.py
1@dataclass(frozen=True) 2class JudgeResult: 3 order: tuple[str, str] 4 preferred_slot: str 5 evidence: tuple[str, ...] 6 needs_human_review: bool 7 8def parse_judge_result( 9 order: tuple[str, str], 10 raw: dict[str, object], 11) -> JudgeResult: 12 verdict = raw.get("verdict") 13 allowed = {"A", "B", "tie", "needs_human_review"} 14 if not isinstance(verdict, str) or verdict not in allowed: 15 raise ValueError(f"unsupported verdict: {verdict}") 16 17 raw_evidence = raw.get("evidence", []) 18 if not isinstance(raw_evidence, list) or not all( 19 isinstance(item, str) for item in raw_evidence 20 ): 21 raise ValueError("evidence must be a list of strings") 22 evidence = tuple(raw_evidence) 23 if verdict in {"A", "B"} and not evidence: 24 raise ValueError("decisive verdict requires criterion evidence") 25 26 return JudgeResult( 27 order=order, 28 preferred_slot=verdict, 29 evidence=evidence, 30 needs_human_review=verdict == "needs_human_review", 31 ) 32 33first_pass = parse_judge_result( 34 ("brief", "actionable"), 35 { 36 "verdict": "B", 37 "evidence": [ 38 "B separates the threshold, policy requirement, and next action clearly." 39 ], 40 }, 41) 42 43assert first_pass.preferred_slot == "B" 44 45try: 46 parse_judge_result( 47 ("brief", "actionable"), 48 {"verdict": "B", "evidence": "B has a next action."}, 49 ) 50except ValueError as exc: 51 print(f"Malformed fixture blocked: {exc}") 52else: 53 raise AssertionError("malformed evidence container must be rejected") 54 55print(f"First pass preference slot: {first_pass.preferred_slot}") 56print(f"Recorded rationale: {first_pass.evidence[0]}")
Output
1Malformed fixture blocked: evidence must be a list of strings 2First pass preference slot: B 3Recorded rationale: B separates the threshold, policy requirement, and next action clearly.

The output is a stored fixture, not proof that a particular hosted model will agree. It does prove that malformed evidence is stopped at the integration boundary. Make the evaluator run observable and testable before plugging in any provider.

Valid structure still says nothing about preference quality. The next check keeps the same two candidates but changes their display order.

A preference must survive swapping A and B

Pairwise comparison asks the evaluator to choose between two concrete alternatives. That makes position bias visible: a judge may prefer the first slot instead of the better reply. Zheng et al. identify this bias in LLM judging, so every pairwise comparison in this lab runs twice with candidates swapped.[1]Reference 1Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena.https://arxiv.org/abs/2306.05685

Predict the two verdicts before reading the figure. A stable judge might return B for (brief, actionable) and A for (actionable, brief). Those letters differ, but they identify the same reply. A slot-following judge would return A both times, which maps to two different replies and must be treated as unstable.

Order-swap comparison where pass one picks slot B and pass two picks slot A, both normalizing to the actionable reply for a stable winner, while a slot-following judge picks A in both orders and routes the mismatch to review.
Swap the slots, then normalize back to reply identity. If both passes still pick the same reply, the verdict is stable. If they only keep picking slot A, route it to review.

Translate each slot back to reply identity before aggregating. A verdict of B in the first pass and A in the swapped pass can represent the same underlying answer; comparing raw letters would falsely call that disagreement.

aggregate-order-swaps.py
1def preferred_candidate(result: JudgeResult) -> str | None: 2 if result.preferred_slot not in {"A", "B"}: 3 return None 4 index = 0 if result.preferred_slot == "A" else 1 5 return result.order[index] 6 7def aggregate_swaps(first: JudgeResult, swapped: JudgeResult) -> dict[str, object]: 8 if first.needs_human_review or swapped.needs_human_review: 9 return {"winner": "needs_human_review", "status": "needs_human_review"} 10 if first.preferred_slot == "tie" or swapped.preferred_slot == "tie": 11 return {"winner": "tie", "status": "tie"} 12 13 first_choice = preferred_candidate(first) 14 second_choice = preferred_candidate(swapped) 15 if first_choice is not None and first_choice == second_choice: 16 return {"winner": first_choice, "status": "stable"} 17 return {"winner": "tie", "status": "unstable_after_swap"} 18 19stable_second_pass = parse_judge_result( 20 ("actionable", "brief"), 21 { 22 "verdict": "A", 23 "evidence": ["A preserves the safe remedy and supplies a clear next step."], 24 }, 25) 26slot_sensitive_second_pass = parse_judge_result( 27 ("actionable", "brief"), 28 { 29 "verdict": "B", 30 "evidence": ["B appears in my preferred slot."], 31 }, 32) 33tie_second_pass = parse_judge_result( 34 ("actionable", "brief"), 35 {"verdict": "tie", "evidence": []}, 36) 37review_second_pass = parse_judge_result( 38 ("actionable", "brief"), 39 {"verdict": "needs_human_review", "evidence": []}, 40) 41 42stable = aggregate_swaps(first_pass, stable_second_pass) 43unstable = aggregate_swaps(first_pass, slot_sensitive_second_pass) 44explicit_tie = aggregate_swaps(first_pass, tie_second_pass) 45review = aggregate_swaps(first_pass, review_second_pass) 46 47assert stable == {"winner": "actionable", "status": "stable"} 48assert unstable == {"winner": "tie", "status": "unstable_after_swap"} 49assert explicit_tie == {"winner": "tie", "status": "tie"} 50assert review == {"winner": "needs_human_review", "status": "needs_human_review"} 51 52print(f"Stable comparison: {stable}") 53print(f"Slot-sensitive comparison: {unstable}") 54print(f"Explicit tie: {explicit_tie}") 55print(f"Review route: {review}")
Output
1Stable comparison: {'winner': 'actionable', 'status': 'stable'} 2Slot-sensitive comparison: {'winner': 'tie', 'status': 'unstable_after_swap'} 3Explicit tie: {'winner': 'tie', 'status': 'tie'} 4Review route: {'winner': 'needs_human_review', 'status': 'needs_human_review'}

Keep those states separate in your report. An explicit tie is a valid rubric outcome, needs_human_review is an escalation, and unstable_after_swap is evidence that slot order changed a decisive preference.

That distinction gives operators a diagnosis, not only a score. Stable preference can continue to calibration, an explicit tie can remain unresolved, and an unstable pair becomes a regression case for the judge prompt or model.

Judge output prefers answer A, but after swapping display order it prefers the same screen position rather than the same answer. What does that show?

Answer

Changing answer order changes the verdict, so the first result isn't stable preference evidence. Repeat with swapped order and treat inconsistent pairs as biased or inconclusive.

Probe the biases you expect

One clean comparison doesn't establish that a judge is trustworthy. Build probe cases where an undesirable shortcut is easy to observe.

Four LLM-judge bias probes: position swap keeps the actionable winner and passes, same-information padding wins and fails, leaked identity labels flip the winner and fail, and a family-G judge preferring generator G fails, so three failed probes block metric promotion.
Probe the shortcuts you expect. Slot swapping still picks `actionable`, but padding, leaked identity labels, and same-family preference all fail, so the metric stays blocked.
ProbeControlled changeSuspicious signalResponse
PositionSwap only slots A and BWinner follows slotRecord unstable result
LengthAdd apologies and repeated policy text, no new helpPadded copy winsTighten concision rubric and track length
IdentityReveal prompt or model labels in one run onlyPreference changesKeep candidates anonymous
Self-preferenceSame-quality pair from generator family G vs H; judge from family GSystematic win for G when labels presentAnonymize, cross-family judge, fail promotion on lift
AmbiguityCompare two equally useful rewritesForced winnerPermit ties or human review

Predict the release outcome from the controlled changes. Position should pass because reply identity stays stable. Padding, leaked identity, and same-family preference should fail because each change gives the judge a shortcut unrelated to answer quality. Ambiguity should route to a tie or a reviewer rather than force a winner.

Self-preference and same-family judge bias

A judge is a conditional predictor, not an objective standard. Panickssery et al. found self-preference in several evaluated judge settings: evaluators could recognize and favor their own generations, even without explicit model labels. On their summarization probes, GPT-4 distinguished its own summaries from two other models and humans at 73.5% accuracy, and self-preference strength rose with self-recognition. Effect size varied by model and task, so treat self-preference as a bias to measure rather than a universal ordering rule.[3]Reference 3LLM Evaluators Recognize and Favor Their Own Generations.https://arxiv.org/abs/2404.13076

This bias can mask regressions during a model swap or upgrade. Anonymize model-specific markers and templates, compare judges from a different model family as an additional probe, and calibrate the results against human labels. A cross-family judge isn't automatically neutral.

Length isn't only a hypothetical confounder. Length-Controlled AlpacaEval fits a regression so it can ask what the preference would have been if the two answers had equal length. That adjustment raised Spearman correlation with Chatbot Arena from 0.94 to 0.98 on their reported leaderboard snapshot.[4]Reference 4Length-Controlled AlpacaEval: A Simple Way to Debias Automatic Evaluators.https://arxiv.org/abs/2404.04475 In a local product eval, the smaller first step is to add same-information length probes and report when padding wins.

These fixtures stand in for stored judge returns from probes wired into promotion. Before running the report, predict three failures: padding, identity, and self-preference. The code doesn't detect bias from text alone; it compares each observed result with behavior you defined in advance. Identity and self-preference sit in both the matrix and runnable report instead of being left as narrative claims.

bias-probe-report.py
1@dataclass(frozen=True) 2class ProbeResult: 3 name: str 4 expected_winner: str 5 observed_winner: str 6 7padded = ( 8 answers["brief"] 9 + " We sincerely apologize for the inconvenience. " 10 + "We appreciate your patience while we coordinate the rollback." 11) 12 13# Identity: same pair, labels stripped vs model names revealed. 14identity_masked_winner = "actionable" 15identity_labeled_winner = "brief" # flips toward the branded slot when labels leak 16 17# Self-preference: matched-quality G vs H outputs judged by family-G evaluator. 18# After anonymization there should be no systematic G lift; revealed family tags create one. 19self_pref_anonymous_winner = "tie" 20self_pref_family_labeled_winner = "generator_g" 21 22probes = [ 23 ProbeResult( 24 name="position_swap", 25 expected_winner="actionable", 26 observed_winner=str(stable["winner"]), 27 ), 28 ProbeResult( 29 name="same_information_padding", 30 expected_winner="brief", 31 observed_winner="padded", 32 ), 33 ProbeResult( 34 name="identity_label_reveal", 35 expected_winner=identity_masked_winner, 36 observed_winner=identity_labeled_winner, 37 ), 38 ProbeResult( 39 name="self_preference_family_label", 40 expected_winner=self_pref_anonymous_winner, 41 observed_winner=self_pref_family_labeled_winner, 42 ), 43] 44 45failed_probes = [ 46 probe.name for probe in probes if probe.expected_winner != probe.observed_winner 47] 48 49assert "rollback" in padded.lower() 50assert "same_information_padding" in failed_probes 51assert "identity_label_reveal" in failed_probes 52assert "self_preference_family_label" in failed_probes 53assert "position_swap" not in failed_probes 54 55print(f"Probes run: {len(probes)}") 56print(f"Failed probes: {failed_probes}") 57print("Action: block metric promotion until padding, identity, and self-pref probes pass")
Output
1Probes run: 4 2Failed probes: ['same_information_padding', 'identity_label_reveal', 'self_preference_family_label'] 3Action: block metric promotion until padding, identity, and self-pref probes pass

Three failed probes are release evidence, not an inconvenience to hide. The padding failure points to a concision rubric or judge that rewards extra words; the identity failure points to leaked labels; the self-preference failure points to a judge-family risk. Position swap can pass while those other shortcuts still block promotion.

Calibrate the measurement against people

Hard gates have test oracles. Soft judgments need a labeled calibration set: people apply the same rubric to a representative sample, then the judge is scored against those labels.

Raw agreement is easy to understand, but it can overstate reliability when one label dominates. Cohen's kappa corrects for agreement expected from each rater's label frequencies:[5]Reference 5A Coefficient of Agreement for Nominal Scaleshttps://doi.org/10.1177/001316446002000104

κ=po−pe1−pe\kappa = \frac{p_o - p_e}{1 - p_e}κ=1−pe​po​−pe​​

Here, pop_opo​ is observed agreement and pep_epe​ is agreement expected from label prevalence. Kappa isn't a universal release threshold. Your baseline is human-human agreement on the same rubric and the same workflow slices.

In this fixture, the judge and human labels agree on six of eight rows, so po=0.75p_o = 0.75po​=0.75. Their label counts produce pe=0.359p_e = 0.359pe​=0.359, which gives κ≈0.610\kappa \approx 0.610κ≈0.610. The arithmetic explains why kappa is lower than raw agreement; the eight rows are still far too small to approve a real metric.

Predict the printed result before running the cell: six matches, raw agreement 0.75, kappa near 0.610, and a warning that the sample is insufficient.

calibrate-against-human-labels.py
1from collections import Counter 2 3@dataclass(frozen=True) 4class LabeledDecision: 5 case_id: str 6 slice_name: str 7 human: str 8 judge: str 9 10calibration_rows = [ 11 LabeledDecision("r1", "rollback", "actionable", "actionable"), 12 LabeledDecision("r2", "rollback", "brief", "brief"), 13 LabeledDecision("r3", "rollback", "tie", "tie"), 14 LabeledDecision("r4", "rollback", "actionable", "actionable"), 15 LabeledDecision("r5", "retry_deploy", "brief", "brief"), 16 LabeledDecision("r6", "retry_deploy", "tie", "actionable"), 17 LabeledDecision("r7", "retry_deploy", "actionable", "brief"), 18 LabeledDecision("r8", "retry_deploy", "brief", "brief"), 19] 20 21def raw_agreement(rows: list[LabeledDecision]) -> float: 22 return sum(row.human == row.judge for row in rows) / len(rows) 23 24def cohens_kappa(rows: list[LabeledDecision]) -> float: 25 labels = {row.human for row in rows} | {row.judge for row in rows} 26 total = len(rows) 27 human_counts = Counter(row.human for row in rows) 28 judge_counts = Counter(row.judge for row in rows) 29 observed = raw_agreement(rows) 30 expected = sum( 31 human_counts[label] / total * judge_counts[label] / total 32 for label in labels 33 ) 34 return (observed - expected) / (1.0 - expected) 35 36agreement = raw_agreement(calibration_rows) 37kappa = cohens_kappa(calibration_rows) 38assert agreement == 0.75 39 40print(f"Calibration rows: {len(calibration_rows)}") 41print(f"Raw agreement: {agreement:.2f}") 42print(f"Cohen's kappa: {kappa:.3f}") 43print("Release evidence: insufficient sample; collect labeled slices")
Output
1Calibration rows: 8 2Raw agreement: 0.75 3Cohen's kappa: 0.610 4Release evidence: insufficient sample; collect labeled slices

The aggregate hides where the misses happen. Rows r6 and r7 disagree inside retry_deploy, so inspect their evidence, criterion labels, slot order, and judge rationale before changing the prompt. Keep each disagreement as a diagnostic example instead of averaging it away.

Predict the slice report next: rollback should be perfect, while retry_deploy should land at 0.50 and become the only weak slice.

calibration-by-workflow-slice.py
1def agreement_by_slice(rows: list[LabeledDecision]) -> dict[str, float]: 2 grouped: dict[str, list[LabeledDecision]] = {} 3 for row in rows: 4 grouped.setdefault(row.slice_name, []).append(row) 5 return {name: raw_agreement(items) for name, items in grouped.items()} 6 7slice_agreement = agreement_by_slice(calibration_rows) 8weak_slices = [ 9 name for name, score in slice_agreement.items() if score < 0.75 10] 11 12assert slice_agreement["rollback"] == 1.0 13assert slice_agreement["retry_deploy"] == 0.5 14assert weak_slices == ["retry_deploy"] 15 16for name, score in slice_agreement.items(): 17 print(f"{name}: agreement={score:.2f}") 18print(f"Slices requiring review: {weak_slices}")
Output
1rollback: agreement=1.00 2retry_deploy: agreement=0.50 3Slices requiring review: ['retry_deploy']

For a real evaluation program, freeze the rubric and collect labels for easy wins, genuine ties, and known failures across workflows such as rollback, access review, and retry-after-rollback. Measure human-human agreement before comparing the judge to people. Re-run after any prompt, judge-model, rubric, or traffic-distribution change, and escalate a weak slice even when the aggregate looks healthy.

A judge agrees with human labels 90% overall but misses most unsafe-answer cases. Is it calibrated for a safety release gate?

Answer

No. Overall agreement hides the critical slice. Measure confusion, precision, and recall against reviewed human labels for each release-critical category before trusting the judge there.

Conversation quality still needs the trace

Once a developer conversation has multiple turns, a fluent final reply can conceal a bad evidence path. A judge packet should include relevant conversation turns, selected evidence identifiers, hard-gate outcomes, and the safe candidates being compared.

Conversation judging flow where the same Maya and assistant turns split into two evidence traces: current deploy policy passes admissibility and reaches anonymous soft judging, while stale policy is blocked before any soft score.
The same turns can route differently once evidence versions diverge. Current policy reaches soft judging; stale policy stops before any semantic score is produced.

The next cell blocks a conversation before semantic judging if its trace isn't admissible. This is the same contract as the single-turn example, applied to a fuller packet. When a bundle is blocked, keep the selected version and gate outcome in the record so a reviewer can reproduce the path. Don't hand those fields to the judge as a freshness question.

Predict the two routes before running it. The current policy should reach soft judging with its version preserved. The stale policy should stop before scoring, while its version and failed gate remain available for diagnosis.

trace-aware-conversation-packet.py
1@dataclass(frozen=True) 2class ConversationBundle: 3 turns: tuple[str, ...] 4 answer_trace: AnswerTrace 5 candidate_names: tuple[str, str] 6 7def route_bundle(bundle: ConversationBundle) -> dict[str, object]: 8 blocked = not bundle.answer_trace.admissible 9 if not blocked: 10 for name in bundle.candidate_names: 11 if hard_failures(answers[name], bundle.answer_trace): 12 blocked = True 13 break 14 return { 15 "route": "blocked_before_judge" if blocked else "ready_for_soft_judge", 16 "selected_version": bundle.answer_trace.selected_version, 17 "admissible": bundle.answer_trace.admissible, 18 "hard_gate": "failed" if blocked else "passed", 19 } 20 21safe_bundle = ConversationBundle( 22 turns=( 23 "Maya: Payment-service crossed the rollback threshold.", 24 "Assistant: I found the DEP-27 rollback policy.", 25 "Maya: What should I do before retrying the deploy?", 26 ), 27 answer_trace=trace, 28 candidate_names=("brief", "actionable"), 29) 30stale_bundle = ConversationBundle( 31 turns=safe_bundle.turns, 32 answer_trace=AnswerTrace( 33 request_id=trace.request_id, 34 selected_source_id=trace.selected_source_id, 35 selected_version="deploy-policy/2025-01-01", 36 admissible=False, 37 allowed_action="rollback", 38 ), 39 candidate_names=("brief", "actionable"), 40) 41 42assert route_bundle(safe_bundle)["route"] == "ready_for_soft_judge" 43assert route_bundle(stale_bundle)["route"] == "blocked_before_judge" 44assert route_bundle(stale_bundle)["selected_version"] == "deploy-policy/2025-01-01" 45assert route_bundle(stale_bundle)["hard_gate"] == "failed" 46 47safe_result = route_bundle(safe_bundle) 48stale_result = route_bundle(stale_bundle) 49print(f"Current policy: {safe_result['route']} ({safe_result['selected_version']})") 50print(f"Stale policy: {stale_result['route']} ({stale_result['selected_version']})") 51print(f"Stale gate: {stale_result['hard_gate']}")
Output
1Current policy: ready_for_soft_judge (deploy-policy/2026-04-01) 2Stale policy: blocked_before_judge (deploy-policy/2025-01-01) 3Stale gate: failed

The output keeps provenance attached to both outcomes. A reviewer can see why the current bundle was eligible and why the stale one never reached a semantic score.

Use judges offline before letting them guide changes

The trace is now safe to measure, but that doesn't make each judge result a live policy decision. Use judging first as an offline experiment metric: compare prompt versions or model releases over a frozen dataset, investigate disagreements, and let people approve consequential changes.

Define the promotion contract before collecting scores. The numbers below are illustrative requirements for this lab, not universal industry thresholds:

Release evidenceLab requirementCurrent lab state
Every candidate passed deterministic policy gatesRequiredPass
Labeled calibration rowsAt least 508
Known bias probesAll passPadding, identity, self-pref fail
Human review pathRequiredDefined

Predict the gate result from the table: hard checks and an escalation path pass, but eight calibration rows miss the 50-row minimum and three bias probes fail. Promotion should be blocked for exactly those two reasons.

judge-metric-promotion-gate.py
1@dataclass(frozen=True) 2class MetricPromotion: 3 hard_gate_passed: bool 4 calibration_count: int 5 minimum_calibration_count: int 6 failed_bias_probes: tuple[str, ...] 7 has_human_review_path: bool 8 9def promotion_failures(promotion: MetricPromotion) -> list[str]: 10 failures: list[str] = [] 11 if not promotion.hard_gate_passed: 12 failures.append("hard policy checks failed") 13 if promotion.calibration_count < promotion.minimum_calibration_count: 14 failures.append("calibration set is too small") 15 if promotion.failed_bias_probes: 16 failures.append("judge failed a bias probe") 17 if not promotion.has_human_review_path: 18 failures.append("human escalation path is missing") 19 return failures 20 21promotion = MetricPromotion( 22 hard_gate_passed=True, 23 calibration_count=len(calibration_rows), 24 minimum_calibration_count=50, 25 failed_bias_probes=tuple(failed_probes), 26 has_human_review_path=True, 27) 28failures = promotion_failures(promotion) 29 30assert failures == [ 31 "calibration set is too small", 32 "judge failed a bias probe", 33] 34 35print("Metric promotion: BLOCKED") 36for failure in failures: 37 print(f"- {failure}") 38print("Next work: label more cases; repair length, identity, and self-pref probes")
Output
1Metric promotion: BLOCKED 2- calibration set is too small 3- judge failed a bias probe 4Next work: label more cases; repair length, identity, and self-pref probes

A blocked promotion is the correct result. The lab has produced a useful candidate preference, but it hasn't established that its judge deserves to influence prompt selection across real developer workflows. The gate separates a promising observation from release evidence.

Even after those gaps close, agreement with reviewers isn't the last question. The next lesson asks whether the same judge routes equivalent requests evenly when wording or language variety changes.

A practical evaluation report

When you implement this pattern in a real project, store a report with these sections:

Report sectionEvidence to retainDecision it supports
Hard-gate resultsSource IDs, versions, claim failuresWhich answers are ineligible
Rubric contractCriteria, anchors, allowed verdictsWhat the judge was asked to measure
Raw judge runsBoth slot orders and rationale snippetsWhether preference is reproducible
Bias probesPosition, length, identity, self-preferenceWhether known shortcuts remain
CalibrationHuman labels, per-slice agreement, kappaWhether metric matches reviewers
Promotion decisionFailed requirements and ownerWhether new metric may guide release

Treat that report as an operational handoff, not a dashboard screenshot. Keep the case_id, source and version, rubric and prompt versions, judge model version, slot order, raw response, parsed verdict, human label, workflow slice, and final disposition together. The application owner can then diagnose eligibility, the evaluation owner can inspect disagreement, and the release owner can see exactly why promotion passed or stopped.

A judge score is one observation. Experiment decisions need a calibrated, stress-tested metric and a record of its failure modes. Keep judging asynchronous or offline until those records and gates are in place; don't let one soft score change a live policy path.

Run the completed chain on one trace: hard gates choose eligible candidates, the rubric defines the comparison, anonymous order swaps test stability, probes expose shortcuts, human labels calibrate slices, and the promotion gate decides whether the metric may guide an experiment. The judge can rank supported wording. It can't grant permission, repair stale evidence, or ship itself.

Complete the lesson

Mastery Check

Answer every question, then check your score. Score 75% or higher to mark this lesson complete.

1.DEP-27 requires rollback rather than continued deployment. Which evaluator should handle selected-evidence freshness, support for a continued-deploy claim, clarity between two supported replies, and a new exception outside the rubric?

Correct answer: Use a code gate, a claim-to-source verifier, a calibrated judge or human, and a human reviewer, in that order.

Access and freshness are exact checks, policy authorization is inspectable against the source, and clarity is the residual subjective comparison. A new exception has no validated rubric anchor, so it needs accountable human judgment.

2.Two replies already pass deterministic DEP-27 checks. Which packet design keeps a pairwise judge focused on actionability, clarity, and concision while making the run reproducible?

Correct answer: Use anonymous A/B slots, include validated context and criterion tie anchors, allow tie or review, and store structured output.

Anonymous slots reduce identity leakage. Validated context records what hard gates already established without asking the judge to re-litigate it. Tie anchors, escalation, and structured storage make the soft comparison auditable.

3.A pairwise judge returns verdict B for (brief, actionable), but its evidence field is the string B gives a next action rather than a list of strings. What should happen before aggregation?

Correct answer: Reject the result as malformed because the structured contract requires evidence to be a list of strings.

An allowed verdict doesn't make the complete object valid. Schema validation must happen before normalization and aggregation; silent coercion would hide an evaluator integration failure.

4.The first judge run returns B for (brief, actionable). After swapping order, it returns A for (actionable, brief). A separate pair gets a decisive label first and an explicit tie after swapping. How should these comparisons be reported?

Correct answer: The first is a stable actionable win after mapping slots to identities; the second remains an explicit tie.

B in the first order and A in the swapped order both identify actionable. An explicit tie is a valid rubric result, distinct from a decisive disagreement that normalizes to different candidates.

5.A controlled probe adds apologies and repeated rollback text to a supported reply without adding useful information. The judge selects the padded version. What release response fits this signal?

Correct answer: Tighten the concision rubric, track length, and block metric promotion until the padding probe passes.

The controlled change adds words without help, so the win exposes verbosity bias. It isn't evidence that the answer improved. Repair the rubric or judge and rerun the known probe before promotion.

6.A family-G judge gives matched-quality G and H answers a tie when labels are hidden, but systematically prefers G after family labels are revealed. What should the team do?

Correct answer: Block promotion, anonymize candidates, and repeat the self-preference probe with a cross-family judge.

A systematic same-family lift on matched answers is a measured bias. Promotion must wait until identity leakage is removed and the evaluator is tested again. Hard claim support remains outside the judge.

7.Four calibration rows have human labels A, A, B, B and judge labels A, A, A, B. Observed agreement is 0.75 and expected agreement from label frequencies is 0.50. What is Cohen's kappa?

Correct answer: 0.50, because (0.75 - 0.50) / (1 - 0.50) equals 0.25 / 0.50.

Kappa discounts agreement expected from label prevalence. Substituting the two supplied probabilities gives 0.50, which is lower than raw agreement but not a claim that the judge is release-ready.

8.A judge agrees with humans on 75% overall, with 100% agreement on rollback rows but 50% on retry-deploy rows. The retry-deploy slice contains the safety-relevant disagreements. What should the report do?

Correct answer: Withhold safety promotion and inspect retry-deploy disagreements before recalibration.

Aggregate agreement can hide failures in a critical workflow. Slice-level review identifies where the judge disagrees with people, and a safety gate must not be approved from easy rollback rows alone.

9.A multi-turn bundle contains current rollback evidence and two safe candidate replies in one run, but a stale selected policy version with admissible=false in another. Why should the stale bundle stop before soft judging while retaining its version?

Correct answer: Route it as blocked_before_judge and retain version plus hard-gate outcome for reproducible trace diagnosis.

A fluent conversation can't repair an inadmissible evidence path. Keeping the selected version and gate result preserves provenance for debugging, while freshness remains a deterministic eligibility decision.

10.A promotion contract requires hard gates, at least 50 labeled rows, no failed bias probes, and a human review path. The candidate has 8 labels, failed padding and identity probes, and a review path. What decision follows?

Correct answer: Block promotion because the calibration count and known-bias requirements fail, then repair and recollect slices.

The explicit contract fails twice: 8 is below 50 and two known probes still fail. A human path helps escalation but doesn't turn an under-calibrated, biased metric into release evidence.

10 questions remaining.

Next Step
Continue to Bias & Fairness in LLMs

You can now treat an automated judge as a measured instrument with swap checks, bias probes, and human calibration. Next you'll ask a different question of that same judge: when two requests share the same authorized remedy, does wording or language variety change who gets auto-served versus sent to review?

PreviousRAG Evaluation for Reliable Answers
Share this article
XFacebookLinkedInBlueskyRedditHacker NewsEmail
References

Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena.

Zheng, L., et al. · 2023 · NeurIPS 2023

https://arxiv.org/abs/2306.05685

G-Eval: NLG Evaluation using GPT-4 with Better Human Alignment.

Liu, Y., et al. · 2023

https://arxiv.org/abs/2303.16634

LLM Evaluators Recognize and Favor Their Own Generations.

Panickssery, A., Bowman, S. R., & Feng, S. · 2024 · NeurIPS 2024

https://arxiv.org/abs/2404.13076

Length-Controlled AlpacaEval: A Simple Way to Debias Automatic Evaluators.

Dubois, Y., et al. · 2024

https://arxiv.org/abs/2404.04475

A Coefficient of Agreement for Nominal Scales

Cohen, J. · 1960 · Educational and Psychological Measurement

https://doi.org/10.1177/001316446002000104

Discussion

Questions and insights from fellow learners.

Discussion loads when you reach this section.