All skills
shipshitdev avatar

/advanced-evaluation

@400068d
by Ship Shitshipshitdev/library37 stars
3

Design and operate LLM-as-a-Judge evaluation systems using direct scoring, pairwise comparison, rubric calibration, evaluator bias mitigation, confidence scoring, and automated quality assessment. Use when building LLM-as-judge systems, comparing model responses, calibrating rubrics, debugging inconsistent evaluations, or designing A/B tests for prompt or model changes.

Use this Skill: https://skilld.dev/gh/shipshitdev/library/advanced-evaluation

This session only. Nothing lands on disk.

referencesbias-mitigation.md

≈2.3k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Bias Mitigation Techniques for LLM Evaluation

This reference details specific techniques for mitigating known biases in LLM-as-a-Judge systems.

Position Bias

The Problem

In pairwise comparison, LLMs systematically prefer responses in certain positions. Research shows:

  • Some models exhibit mild first-position bias (~55% preference for first position in ties)
  • Smaller models often show stronger bias

Mitigation: Position Swapping Protocol

async def position_swap_comparison(response_a, response_b, prompt, criteria):
    # Pass 1: Original order
    result_ab = await compare(response_a, response_b, prompt, criteria)
    
    # Pass 2: Swapped order
    result_ba = await compare(response_b, response_a, prompt, criteria)
    
    # Map second result (A in second position → B in first)
    result_ba_mapped = {
        'winner': {'A': 'B', 'B': 'A', 'TIE': 'TIE'}[result_ba['winner']],
        'confidence': result_ba['confidence']
    }
    
    # Consistency check
    if result_ab['winner'] == result_ba_mapped['winner']:
        return {
            'winner': result_ab['winner'],
            'confidence': (result_ab['confidence'] + result_ba_mapped['confidence']) / 2,
            'position_consistent': True
        }
    else:
        # Disagreement indicates position bias was a factor
        return {
            'winner': 'TIE',
            'confidence': 0.5,
            'position_consistent': False,
            'bias_detected': True
        }

Alternative: Multiple Shuffles

For higher reliability, use multiple position orderings:

async def multi_shuffle_comparison(response_a, response_b, prompt, criteria, n_shuffles=3):
    results = []
    for i in range(n_shuffles):
        if i % 2 == 0:
            r = await compare(response_a, response_b, prompt, criteria)
        else:
            r = await compare(response_b, response_a, prompt, criteria)
            r['winner'] = {'A': 'B', 'B': 'A', 'TIE': 'TIE'}[r['winner']]
        results.append(r)
    
    # Majority vote
    winners = [r['winner'] for r in results]
    final_winner = max(set(winners), key=winners.count)
    agreement = winners.count(final_winner) / len(winners)
    
    return {
        'winner': final_winner,
        'confidence': agreement,
        'n_shuffles': n_shuffles
    }

Length Bias

The Problem

LLMs tend to rate longer responses higher, regardless of quality. This manifests as:

  • Verbose responses receiving inflated scores
  • Concise but complete responses penalized
  • Padding and repetition being rewarded

Mitigation: Explicit Prompting

Include anti-length-bias instructions in the prompt:

CRITICAL EVALUATION GUIDELINES:
- Do NOT prefer responses because they are longer
- Concise, complete answers are as valuable as detailed ones
- Penalize unnecessary verbosity or repetition
- Focus on information density, not word count

Mitigation: Length-Normalized Scoring

def length_normalized_score(score, response_length, target_length=500):
    """Adjust score based on response length."""
    length_ratio = response_length / target_length
    
    if length_ratio > 2.0:
        # Penalize excessively long responses
        penalty = (length_ratio - 2.0) * 0.1
        return max(score - penalty, 1)
    elif length_ratio < 0.3:
        # Penalize excessively short responses
        penalty = (0.3 - length_ratio) * 0.5
        return max(score - penalty, 1)
    else:
        return score

Mitigation: Separate Length Criterion

Make length a separate, explicit criterion so it's not implicitly rewarded:

criteria = [
    {"name": "Accuracy", "description": "Factual correctness", "weight": 0.4},
    {"name": "Completeness", "description": "Covers key points", "weight": 0.3},
    {"name": "Conciseness", "description": "No unnecessary content", "weight": 0.3}  # Explicit
]

Self-Enhancement Bias

The Problem

Models rate outputs generated by themselves (or similar models) higher than outputs from different models.

Mitigation: Cross-Model Evaluation

Use a different model family for evaluation than generation:

def get_evaluator_model(generator_model):
    """Select evaluator to avoid self-enhancement bias."""
    # Use a model from a different provider or family than the generator
    evaluator_map = {
        'family-a': 'family-b-capable-model',
        'family-b': 'family-a-capable-model',
    }
    for key, evaluator in evaluator_map.items():
        if key in generator_model.lower():
            return evaluator
    return 'default-capable-evaluator-model'

Mitigation: Blind Evaluation

Remove model attribution from responses before evaluation:

def anonymize_response(response, model_name):
    """Remove model-identifying patterns."""
    patterns = [
        f"As {model_name}",
        "I am an AI",
        "I don't have personal opinions",
        # Model-specific patterns
    ]
    anonymized = response
    for pattern in patterns:
        anonymized = anonymized.replace(pattern, "[REDACTED]")
    return anonymized

Verbosity Bias

The Problem

Detailed explanations receive higher scores even when the extra detail is irrelevant or incorrect.

Mitigation: Relevance-Weighted Scoring

async def relevance_weighted_evaluation(response, prompt, criteria):
    # First, assess relevance of each segment
    relevance_scores = await assess_relevance(response, prompt)
    
    # Weight evaluation by relevance
    segments = split_into_segments(response)
    weighted_scores = []
    for segment, relevance in zip(segments, relevance_scores):
        if relevance > 0.5:  # Only count relevant segments
            score = await evaluate_segment(segment, prompt, criteria)
            weighted_scores.append(score * relevance)
    
    return sum(weighted_scores) / len(weighted_scores)

Mitigation: Rubric with Verbosity Penalty

Include explicit verbosity penalties in rubrics:

rubric_levels = [
    {
        "score": 5,
        "description": "Complete and concise. All necessary information, nothing extraneous.",
        "characteristics": ["Every sentence adds value", "No repetition", "Appropriately scoped"]
    },
    {
        "score": 3,
        "description": "Complete but verbose. Contains unnecessary detail or repetition.",
        "characteristics": ["Main points covered", "Some tangents", "Could be more concise"]
    },
    # ... etc
]

Authority Bias

The Problem

Confident, authoritative tone is rated higher regardless of accuracy.

Mitigation: Evidence Requirement

Require explicit evidence for claims:

For each claim in the response:
1. Identify whether it's a factual claim
2. Note if evidence or sources are provided
3. Score based on verifiability, not confidence

IMPORTANT: Confident claims without evidence should NOT receive higher scores than 
hedged claims with evidence.

Mitigation: Fact-Checking Layer

Add a fact-checking step before scoring:

async def fact_checked_evaluation(response, prompt, criteria):
    # Extract claims
    claims = await extract_claims(response)
    
    # Fact-check each claim
    fact_check_results = await asyncio.gather(*[
        verify_claim(claim) for claim in claims
    ])
    
    # Adjust score based on fact-check results
    accuracy_factor = sum(r['verified'] for r in fact_check_results) / len(fact_check_results)
    
    base_score = await evaluate(response, prompt, criteria)
    return base_score * (0.7 + 0.3 * accuracy_factor)  # At least 70% of score

Aggregate Bias Detection

Monitor for systematic biases in production:

class BiasMonitor:
    def __init__(self):
        self.evaluations = []
    
    def record(self, evaluation):
        self.evaluations.append(evaluation)
    
    def detect_position_bias(self):
        """Detect if first position wins more often than expected."""
        first_wins = sum(1 for e in self.evaluations if e['first_position_winner'])
        expected = len(self.evaluations) * 0.5
        z_score = (first_wins - expected) / (expected * 0.5) ** 0.5
        return {'bias_detected': abs(z_score) > 2, 'z_score': z_score}
    
    def detect_length_bias(self):
        """Detect if longer responses score higher."""
        from scipy.stats import spearmanr
        lengths = [e['response_length'] for e in self.evaluations]
        scores = [e['score'] for e in self.evaluations]
        corr, p_value = spearmanr(lengths, scores)
        return {'bias_detected': corr > 0.3 and p_value < 0.05, 'correlation': corr}

Summary Table

Bias Primary Mitigation Secondary Mitigation Detection Method
Position Position swapping Multiple shuffles Consistency check
Length Explicit prompting Length normalization Length-score correlation
Self-enhancement Cross-model evaluation Anonymization Model comparison study
Verbosity Relevance weighting Rubric penalties Relevance scoring
Authority Evidence requirement Fact-checking layer Confidence-accuracy correlation

Source: SKILL.md on GitHub

1 warning16d4 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    No security issues or malicious patterns were detected. The skill contains standard documentation, guidelines, and benign example code for implementing LLM-as-a-Judge evaluation pipelines.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer7mo

    7/7 files flagged

Signed by skilld at 400068d. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 days ago.

Activeupdated 3 months ago
Other metadata
metadata
{
  "version": "2.1.1",
  "source": "https://github.com/muratcankoylan/Agent-Skills-for-Context-Engineering/blob/main/skills/advanced-evaluation/SKILL.md",
  "upstream_repo": "muratcankoylan/Agent-Skills-for-Context-Engineering",
  "upstream_ref": "main",
  "upstream_commit": "25e1fa79a33f",
  "last_synced": "2026-06-13",
  "license": "MIT",
  "tags": "evaluation, llm-as-judge, quality, bias-mitigation"
}

README badge

README badge for shipshitdev/library/advanced-evaluation