Stop Using BLEU Scores. Your LLM Evaluation Is Lying to You. LLM Evaluation

Stop Using BLEU Scores. Your LLM Evaluation Is Lying to You.

AR
Alex Rivera · April 4,2026 · 10 min read

TL;DR

BLEU and ROUGE scores don't measure what you think they measure. A high BLEU score doesn't mean your LLM is good at language, it means your output matches a reference string. We'll explain why legacy metrics fail for modern LLMs, show you the alternatives (BERTScore, LLM-as-judge, G-Eval, human evaluation), when to use each, and how to build custom evaluation pipelines that actually measure what matters.

You've probably evaluated an LLM like this: generate outputs, compute BLEU score, celebrate if it's above 30.

If you have, your evaluation is lying to you.

BLEU scores measure n-gram overlap with a reference. That's not language quality, that's copy-paste fidelity. An LLM can have a stellar BLEU score while producing incoherent garbage, and vice versa.

This matters because a single point improvement in BLEU often comes from gaming the metric, not improving the model. You end up optimizing for BLEU instead of optimizing for actual quality.

Why Legacy Metrics Fail for LLMs

BLEU and ROUGE were designed for machine translation. The assumption: there's one correct way to translate a sentence. Output something close to that reference, and you're good.

LLMs generate diverse, creative outputs. A question can have many valid answers. A summary can be expressed in many ways. If your output doesn't match the reference word-for-word, BLEU penalizes you even if you're correct.

Real Example: BLEU Fails at Synonymy

Reference: "The cat sat on the mat"
Model A: "The cat sat on the mat" → BLEU = 100%
Model B: "The feline sat on the rug" → BLEU = 0%

But Model B is arguably better (more interesting vocabulary).

Another Example: BLEU Doesn't Understand Semantics

Question: "What's 2+2?"
Reference: "2 + 2 = 4"
Model A: "2 + 2 = 4" → BLEU = 100%
Model B: "The answer is four" → BLEU = ~20%
Model C: "2+2=4" → BLEU = ~40%

All three are correct. Only Model A gets credit.
BLEU scores are good at measuring translation quality (where outputs are constrained). They're terrible at measuring generation quality (where outputs are open-ended).

Understanding the Metric Landscape

Modern LLM evaluation has moved beyond BLEU. There are now multiple approaches, each with tradeoffs. Understanding when to use each is the key to building a reliable evaluation pipeline.

Metric 1: BERTScore (Semantic Similarity)

What It Is

BERTScore compares the contextual embeddings of your output and reference. Instead of counting matching n-grams, it measures semantic similarity. Two sentences saying the same thing in different words get high scores.

Pros

  • Handles synonyms and paraphrasing
  • Evaluates semantic correctness, not surface-level matching
  • Works across languages with multilingual models
  • Correlates reasonably well with human judgment

Cons

  • Requires a reference (doesn't work for open-ended generation)
  • Expensive (embedding computation for long documents)
  • Still metric-gameable (can generate "correct semantically" but nonsensical text)

When to Use

Use BERTScore when you have reference answers and want to reward diverse but correct outputs.

import bert_score

predictions = ["The cat is sleeping", "The feline is resting"]
references = ["The cat is asleep"]

P, R, F1 = bert_score.score(predictions, references, lang="en")
# F1 scores: [0.91,0.87], Both correct, even though different

Metric 2: LLM-as-Judge (Learned Evaluation)

What It Is

Use another LLM (usually GPT-4 or Claude) to evaluate outputs. Ask it: "Is this answer correct? Why or why not?" Score based on its assessment.

Pros

  • Handles open-ended evaluation (no reference needed)
  • Understands nuance, context, and intent
  • Can penalize hallucinations and factual errors
  • Surprisingly correlates well with human judgment

Cons

  • Expensive (API calls add up)
  • Judge LLM has its own biases and limitations
  • Can be gamed if model learns to match judge's style
  • No transparency into scoring logic

When to Use

Use LLM-as-judge when you need nuanced evaluation and don't have references. It's industry standard for evaluating chat, summarization, and reasoning tasks.

from langchain.evaluation import EvaluatorChain
from langchain.chat_models import ChatOpenAI

evaluator = EvaluatorChain.from_llm_and_criteria(
 llm=ChatOpenAI(model="gpt-4"),
 criteria="helpfulness"
)

score = evaluator.evaluate_strings(
 prediction="The capital of France is Paris",
 input="What's the capital of France?"
)
# Returns: score, reasoning from GPT-4

Metric 3: G-Eval (Generative Evaluation)

What It Is

A framework where you define evaluation criteria and let an LLM score outputs step-by-step. More structured than LLM-as-judge, more flexible than static metrics.

Pros

  • Customizable to your specific criteria
  • Transparent reasoning (LLM explains its score)
  • Handles complex, multi-dimensional evaluation
  • Works for any task you can describe

Cons

  • Still expensive (LLM API calls)
  • Quality depends on how well you define criteria
  • Can be inconsistent across evaluations

When to Use

Use G-Eval when you need custom evaluation logic that LLM-as-judge doesn't provide. Perfect for domain-specific tasks.

import anthropic

def evaluate_response(question: str, response: str, criteria: list[str]) -> dict:
 client = anthropic.Anthropic()

 prompt = f"""Evaluate this LLM response against the criteria.

Question: {question}
Response: {response}

Criteria:
{chr(10).join(f"- {c}" for c in criteria)}

For each criterion:
1. Assess how well the response meets it
2. Provide a score from 1-5
3. Explain your reasoning

Format your response as JSON with keys: criterion, score, reasoning"""

 result = client.messages.create(
 model="claude-3-sonnet",
 max_tokens=1024,
 messages=[{"role": "user", "content": prompt}]
 )

 return json.loads(result.content[0].text)

Metric 4: Human Evaluation (Ground Truth)

What It Is

Have humans rate your outputs. It's slow and expensive, but it's ground truth.

Pros

  • Most reliable evaluation method (if done right)
  • Catches things automated metrics miss
  • Can evaluate subjective qualities (tone, creativity)
  • Provides actionable feedback for improvement

Cons

  • Expensive ($1-5 per evaluation)
  • Slow (days or weeks for large datasets)
  • Inconsistent between raters (requires inter-rater agreement)
  • Doesn't scale for continuous evaluation

When to Use

Use human evaluation as a validation gate. Evaluate a subset of outputs from all your metrics to see which correlates best with human judgment.

// Set up human evaluation through Toloka/Labeling/MTurk
const evaluationConfig = {
 instructions: "Is this response helpful, accurate, and clear?",
 examples: [
 { output: "Paris is the capital of France", rating: 5 },
 { output: "The capital is in the middle of the country", rating: 2 }
 ],
 scale: [1,2,3,4,5],
 minRaters: 3, // Get consensus
 payPerEvaluation: 0.50
};

// Compare human ratings to automated metrics
const correlations = {
 bleu: 0.42, // Weak correlation
 bertscore: 0.68, // Moderate correlation
 llmAsJudge: 0.79, // Strong correlation
 humanEval: 1.00 // Ground truth
};

Building a Custom Evaluation Pipeline

to set up a production evaluation system that doesn't rely on BLEU:

Step 1: Define What Success Looks Like

// Not: "maximize BLEU"
// But: "generate responses that are correct, helpful, and clear"

const successCriteria = {
 correctness: {
 description: "Answer is factually accurate",
 metric: "llmAsJudge",
 threshold: 0.85
 },
 helpfulness: {
 description: "Answer directly addresses the question",
 metric: "llmAsJudge",
 threshold: 0.80
 },
 clarity: {
 description: "Answer is easy to understand",
 metric: "llmAsJudge",
 threshold: 0.75
 },
 hallucination: {
 description: "No made-up information",
 metric: "customGEval",
 threshold: 0.95
 }
};

Step 2: Implement Multi-Metric Evaluation

async function evaluateResponse(question: string, response: string) {
 const results = {
 timestamp: new Date(),
 question,
 response,
 metrics: {}
 };

 // Run multiple metrics in parallel
 const [bertscore, llmJudge, geval] = await Promise.all([
 computeBERTScore(response, expectedReference),
 runLLMAsJudge(question, response),
 runGEval(question, response, customCriteria)
 ]);

 results.metrics.bertscore = bertscore;
 results.metrics.llmJudge = llmJudge;
 results.metrics.geval = geval;

 // Weighted aggregate score (you define the weights)
 results.aggregateScore = (
 bertscore * 0.2 + // 20% semantic similarity
 llmJudge.score * 0.5 + // 50% LLM evaluation
 geval.overallScore * 0.3 // 30% custom criteria
 );

 return results;
}

Step 3: Validate Against Human Judgment

// Periodically, sample outputs and get human evaluation
async function validateMetrics() {
 const sample = await getSampleOutputs(100);
 const humanRatings = await getHumanEvaluation(sample);

 const correlations = {
 bertscore: pearsonCorrelation(sample.map(s => s.metrics.bertscore), humanRatings),
 llmJudge: pearsonCorrelation(sample.map(s => s.metrics.llmJudge.score), humanRatings),
 geval: pearsonCorrelation(sample.map(s => s.metrics.geval.overallScore), humanRatings)
 };

 // Log which metric is most predictive of human judgment
 console.log('Metric correlations with human judgment:', correlations);

 // Alert if a metric diverges (something's wrong)
 if (correlations.llmJudge < 0.70) {
 alert('LLM-as-judge correlation has degraded. Investigate.');
 }
}

Common Pitfalls When Switching Metrics

Pitfall 1: Replacing One Bad Metric with Another

Don't switch from BLEU to just LLM-as-judge. Use multiple metrics. A single metric can be gamed or fail on certain categories.

Pitfall 2: Forgetting to Validate

New metrics can feel "better" but still be wrong. Always validate against human judgment on a held-out test set before committing to a metric.

Pitfall 3: Ignoring Bias in the Judge LLM

If you use GPT-4 as a judge, your model is optimizing to be like GPT-4. It might produce correct outputs that GPT-4 doesn't recognize. Vary your judge or use multiple judges.

Pitfall 4: Not Tracking What Changed

When scores improve, understand why. Did the model actually improve, or did you just optimize for the metric? Log examples that improved and examples that got worse.

The Practical Recommendation

If you're evaluating an LLM production system, use this stack:

  1. For correctness: LLM-as-judge (GPT-4 or Claude) scoring "Is the answer factually correct?"
  2. For semantic quality: BERTScore (if you have references) or G-Eval with custom criteria
  3. For production safety: Custom rules (hallucination detection, prompt injection, jailbreak attempts)
  4. For validation: Human evaluation on a small sample every month

Ditch BLEU. It's been useful, but it's not measuring what you think it is.

The best evaluation metric is the one that correlates with what your users care about. Usually that's human judgment. Invest in understanding what your users actually value, then build metrics around that.

Building reliable LLM evaluation?

alt.qa provides evaluation infrastructure for LLM applications. Multi-metric pipelines, human validation, and continuous monitoring. No more BLEU scores.

Get evaluation infrastructure
Alex Rivera is a Senior AI Engineer at alt.qa. He's spent years wrestling with LLM evaluation and learned the hard way that not all metrics are created equal.