RUNLOCALAIv38
->Will it run?Best GPUCompareTroubleshootStartLearnPulseModelsHardwareToolsBench
Run check
RUNLOCALAI

Independently operated catalog for local-AI hardware and software. Hand-written verdicts. Source-cited claims. Reproducible commands when we have them.

OP·Eruo Fredoline
DIR
  • Models
  • Hardware
  • Tools
  • Benchmarks
TOOLS
  • Will it run?
  • Compare hardware
  • Cost vs cloud
  • Choose my GPU
  • Prompting kits
  • Quick answers
REF
  • All buyer guides
  • Learn local AI
  • Methodology
  • Glossary
  • Errors KB
  • Trust
EDITOR
  • About
  • Author
  • How we make money
  • Editorial policy
  • Contact
LEGAL
  • Privacy
  • Terms
  • Sitemap
MAIL · MONTHLY DIGEST
Get monthly local AI changes
Monthly recap. No spam.
DISCLOSURE

Some links on this site are affiliate links (Amazon Associates and other first-class retailers). When you buy through them, we earn a small commission at no extra cost to you. Affiliate links do not influence our verdicts — there are cards we rate highly that we don't have affiliate relationships with, and cards that sell well that we refuse to recommend. Read more →

© 2026 runlocalai.coIndependently operated
RUNLOCALAI · v38
  1. >
  2. Home
  3. /Learn
  4. /Courses
  5. /RLHF, DPO, and PPO
  6. /Ch. 12
RLHF, DPO, and PPO

12. Synthetic Preference Data

Chapter 12 of 24 · 20 min
KEY INSIGHT

Synthetic preference data is most useful for initial alignment and for domain-specific fine-tuning where human data is scarce. For final alignment, human preferences remain the gold standard. Use synthetic data to expand coverage and reduce annotation costs, but validate with human evaluation before production deployment.

Human annotation is expensive and slow. Synthetic preference data—generated by AI systems rather than humans—offers a path to faster, cheaper, and more scalable alignment signals. The key challenge is maintaining quality: synthetic preferences must correlate with real human preferences.

LLM-as-judge: Use a capable model (GPT-4, Claude, etc.) to judge preference pairs. The judge must be more capable than the model being aligned.

def generate_synthetic_preference(prompt, response_a, response_b, judge_model):
    """
    Generate synthetic preference using an LLM judge.
    Returns (chosen, rejected, confidence).
    """
    judge_prompt = f"""You are evaluating AI assistant responses for helpfulness and harmlessness.

USER QUERY: {prompt}

RESPONSE A: {response_a}

RESPONSE B: {response_b}

Which response is better? Consider:
- Accuracy of information
- Completeness of answer
- Clarity and readability
- Appropriateness for the query

Respond in this format:
PREFERENCE: [A/B]
CONFIDENCE: [high/medium/low]
REASONING: [brief explanation]
"""
    
    judgment = call_judge_model(judge_prompt, model=judge_model)
    
    # Parse the response
    pref_line = [l for l in judgment.split('\n') if l.startswith('PREFERENCE:')][0]
    preference = pref_line.split(':')[1].strip()
    
    chosen = response_a if preference == 'A' else response_b
    rejected = response_b if preference == 'A' else response_a
    
    return {
        "prompt": prompt,
        "chosen": chosen,
        "rejected": rejected,
        "judgment": judgment
    }

Constitutional AI critique-revise: Generate responses, have the model critique its own outputs, then revise based on critique. Preferences are inferred: revised > original.

def critique_and_revise(prompt, initial_response, critique_model):
    """
    Constitutional AI style preference generation.
    """
    # Critique
    critique_prompt = f"""Review this response for issues:

USER: {prompt}
RESPONSE: {initial_response}

Identify any problems with accuracy, completeness, or safety.
"""
    critique = critique_model(critique_prompt)
    
    # Revision
    revision_prompt = f"""Given this critique, revise the response:

USER: {prompt}
ORIGINAL: {initial_response}
CRITIQUE: {critique}

Provide an improved response:
"""
    revised = critique_model(revision_prompt)
    
    # Preference: revised is better than original
    return {
        "prompt": prompt,
        "chosen": revised,
        "rejected": initial_response,
        "critique": critique
    }

Failure mode: judge model bias. The judge has its own preferences and biases that leak into the training signal. If the judge prefers verbose responses, the policy will learn to be verbose—even when conciseness is better.

# Detect judge bias: check correlation between response length and preference
def detect_length_bias(synthetic_preferences):
    lengths_chosen = [len(p["chosen"].split()) for p in synthetic_preferences]
    lengths_rejected = [len(p["rejected"].split()) for p in synthetic_preferences]
    
    longer_preferred = sum(c > r for c, r in zip(lengths_chosen, lengths_rejected))
    pct_longer_preferred = longer_preferred / len(synthetic_preferences)
    
    print(f"Longer responses preferred: {pct_longer_preferred:.1%}")
    
    if abs(pct_longer_preferred - 0.5) > 0.15:
        print("WARNING: Significant length bias in judge")
        return True
    return False

Self-generated preferences: Fine-tune a model on its own outputs, where preferences come from self-critique or external evaluation. This can bootstrap alignment without external annotation.

EXERCISE

Implement a synthetic preference pipeline using an LLM judge. Generate 100 synthetic preference pairs from your model outputs. Then have a human evaluate a random subset of 20 pairs: for each, rate whether the synthetic preference matches human judgment. Calculate agreement rate and identify categories of prompts where synthetic preferences diverge most from human preferences.

← Chapter 11
PPO Implementation
Chapter 13 →
Data Quality Filtering