Phase 05 - Lesson 27

Avaliação de LLM — RAGAS, DeepEval, G-Eval

Correspondência exata e F1 ignoram a equivalência semântica. A revisão humana não escala. LLM-como-juiz é a resposta de produção — com calibração suficiente para confiar no número.

Tipo: Build Linguagens: Python Pré-requisitos: Fase 5 · 13 (Perguntas e Respostas), Fase 5 · 14 (Recuperação de Informação) Tempo: ~75 minutos

O Problema

Seu sistema de RAG responde: "June 29th, 2007." A referência de ouro é: "June 29, 2007." A correspondência exata pontua 0. F1 pontua ~75%. Um humano pontuaria 100%.

Agora multiplique por 10.000 casos de teste. Multiplique novamente por cada mudança no recuperador, no chunking, no prompt ou no modelo. Você precisa de um avaliador que entenda significado, rode barato em escala, não minta sobre regressões e revele os modos de falha certos.

2026 tem três frameworks que dominam esse problema.

  • RAGAS. Retrieval-Augmented Generation ASsessment. Quatro métricas de RAG (fidelidade, relevância da resposta, precisão de contexto, recall de contexto) com backends de NLI + LLM-juiz. Embasado em pesquisa, leve.
  • DeepEval. Pytest para LLMs. G-Eval, métricas de conclusão de tarefa, alucinação e viés. Nativo para CI/CD.
  • G-Eval. Um método (e uma métrica do DeepEval): LLM-como-juiz com cadeia de pensamento, critérios personalizados, pontuação 0-1.

Os três se apoiam em LLM-como-juiz. Esta lição constrói a intuição para o método e a camada de confiança ao seu redor.

O Conceito

Quatro dimensões de avaliação, arquitetura de LLM-como-juiz

LLM-como-juiz. Substitua uma métrica estática por um LLM que pontua saídas dada uma rubrica. Dado (query, context, answer), instrua um LLM juiz: "Pontue de 0 a 1 em fidelidade." Retorne a pontuação.

Por que funciona: LLMs aproximam o julgamento humano por uma fração mínima do custo. GPT-4o-mini a ~US$ 0,003 por caso pontuado viabiliza execuções de avaliação de regressão com 1000 amostras por menos de US$ 5.

Por que falha silenciosamente:

  1. Viés do juiz. Juízes preferem respostas mais longas, respostas da própria família de modelos, respostas que combinam com o estilo do prompt.
  2. Falhas de parsing de JSON. JSON ruim → pontuação NaN → silenciosamente excluída do agregado. Usuários do RAGAS conhecem essa dor. Proteja com try/except + modo de falha explícito.
  3. Drift entre versões de modelo. Atualizar o juiz muda todas as métricas. Congele o modelo do juiz + versão.

Os quatro do RAG.

Métrica Pergunta Backend
Fidelidade Cada afirmação na resposta vem do contexto recuperado? Entailment baseado em NLI
Relevância da resposta A resposta endereça a pergunta? Gera perguntas hipotéticas a partir da resposta; compara com a pergunta real
Precisão de contexto Dos chunks recuperados, que fração era relevante? LLM-juiz
Recall de contexto A recuperação trouxe tudo o que era necessário? LLM-juiz contra a resposta de ouro

G-Eval. Defina um critério personalizado: "A resposta citou a fonte correta?" O framework expande automaticamente em passos de avaliação por cadeia de pensamento e então pontua de 0 a 1. Bom para dimensões de qualidade específicas de domínio que o RAGAS não cobre.

Calibração. Nunca confie na pontuação bruta do juiz até ter uma correlação contra rótulos humanos. Rode 100 exemplos rotulados à mão. Plote juiz vs humano. Compute o rho de Spearman. Se rho < 0,7, sua rubrica de juiz precisa de trabalho.

Construa

Passo 1: fidelidade com NLI (estilo RAGAS)

from typing import Callable
from transformers import pipeline

nli = pipeline("text-classification",
               model="MoritzLaurer/DeBERTa-v3-large-mnli-fever-anli-ling-wanli",
               top_k=None)

# `llm` is any callable: prompt str -> generated str.
# Example: llm = lambda p: client.messages.create(model="claude-haiku-4-5", ...).content[0].text
LLM = Callable[[str], str]


def atomic_claims(answer: str, llm: LLM) -> list[str]:
    prompt = f"""Break this answer into simple factual claims (one per line):
{answer}
"""
    return llm(prompt).splitlines()


def faithfulness(answer: str, context: str, llm: LLM) -> float:
    claims = atomic_claims(answer, llm)
    if not claims:
        return 0.0
    supported = 0
    for claim in claims:
        result = nli({"text": context, "text_pair": claim})[0]
        entail = next((s for s in result if s["label"] == "entailment"), None)
        if entail and entail["score"] > 0.5:
            supported += 1
    return supported / len(claims)

Decomponha a resposta em afirmações atômicas. Verifique cada afirmação via NLI contra o contexto recuperado. Fidelidade = fração suportada.

Passo 2: relevância da resposta

import numpy as np
from sentence_transformers import SentenceTransformer

# encoder: any model implementing .encode(texts, normalize_embeddings=True) -> ndarray
# e.g., encoder = SentenceTransformer("BAAI/bge-small-en-v1.5")

def answer_relevance(question: str, answer: str, encoder, llm: LLM, n: int = 3) -> float:
    prompt = f"Write {n} questions this answer could be the answer to:\n{answer}"
    generated = [line for line in llm(prompt).splitlines() if line.strip()][:n]
    if not generated:
        return 0.0
    q_emb = np.asarray(encoder.encode([question], normalize_embeddings=True)[0])
    g_embs = np.asarray(encoder.encode(generated, normalize_embeddings=True))
    sims = [float(q_emb @ g_emb) for g_emb in g_embs]
    return sum(sims) / len(sims)

Se a resposta sugere perguntas diferentes daquela que foi feita, a relevância cai.

Passo 3: métrica personalizada G-Eval

from deepeval.metrics import GEval
from deepeval.test_case import LLMTestCaseParams, LLMTestCase

metric = GEval(
    name="Correctness",
    criteria="The answer should be factually accurate and match the expected output.",
    evaluation_steps=[
        "Read the expected output.",
        "Read the actual output.",
        "List factual claims in the actual output.",
        "For each claim, mark supported or unsupported by the expected output.",
        "Return score = fraction supported.",
    ],
    evaluation_params=[LLMTestCaseParams.INPUT, LLMTestCaseParams.ACTUAL_OUTPUT, LLMTestCaseParams.EXPECTED_OUTPUT],
)

test = LLMTestCase(input="When was the first iPhone released?",
                   actual_output="June 29th, 2007.",
                   expected_output="June 29, 2007.")
metric.measure(test)
print(metric.score, metric.reason)

Os passos de avaliação são a rubrica. Passos explícitos são mais estáveis do que prompts implícitos de "pontue de 0 a 1".

Passo 4: portão de CI

import deepeval
from deepeval.metrics import FaithfulnessMetric, ContextualRelevancyMetric


def test_rag_system():
    cases = load_regression_cases()
    faith = FaithfulnessMetric(threshold=0.85)
    rel = ContextualRelevancyMetric(threshold=0.7)
    for case in cases:
        faith.measure(case)
        assert faith.score >= 0.85, f"faithfulness regression on {case.id}"
        rel.measure(case)
        assert rel.score >= 0.7, f"relevancy regression on {case.id}"

Envie como um arquivo pytest. Rode em cada PR. Bloqueie merges em regressões.

Passo 5: avaliação de brinquedo do zero

Veja code/main.py. Aproximações usando apenas a stdlib de fidelidade (sobreposição das afirmações da resposta com o contexto) e relevância (sobreposição dos tokens da resposta com os tokens da pergunta). Não é produção. Mostra o formato.

Armadilhas

  • Sem calibração. Um juiz com correlação de 0,3 com rótulos humanos é ruído. Exija uma rodada de calibração antes de enviar.
  • Autoavaliação. Usar o mesmo LLM para gerar e julgar infla as pontuações em 10-20%. Use uma família de modelos diferente para o juiz.
  • Viés posicional no julgamento pareado. Juízes preferem a primeira opção apresentada. Sempre randomize a ordem e rode ambas.
  • Agregado bruto esconde falhas. Pontuação média de 0,85 frequentemente esconde 5% de falhas catastróficas. Sempre inspecione o quantil inferior.
  • Apodrecimento do conjunto de ouro. Conjuntos de avaliação sem versionamento que sofrem drift ao longo do tempo quebram a comparação longitudinal. Marque o conjunto de dados a cada mudança.
  • Custo de LLM. Em escala, as chamadas ao juiz dominam o custo. Use o modelo mais barato que atinja o limiar de calibração. GPT-4o-mini, Claude Haiku, Mistral-small.

Use

A stack de 2026:

Caso de uso Framework
Monitoramento de qualidade de RAG RAGAS (4 métricas)
Portões de regressão de CI/CD DeepEval + pytest
Critérios de domínio personalizados G-Eval dentro do DeepEval
Monitoramento online de tráfego ao vivo RAGAS no modo sem referência
Verificações pontuais com humano no loop LangSmith ou Phoenix com UI de anotação
Red-teaming / avaliação de segurança Promptfoo + DeepEval

Stack típica: RAGAS para monitoramento, DeepEval para CI, G-Eval para dimensões inéditas. Rode os três; eles discordam de forma útil.

Envie

Salve como outputs/skill-eval-architect.md:

---
name: eval-architect
description: Design an LLM evaluation plan with calibrated judge and CI gates.
version: 1.0.0
phase: 5
lesson: 27
tags: [nlp, evaluation, rag]
---

Given a use case (RAG / agent / generative task), output:

1. Metrics. Faithfulness / relevance / context-precision / context-recall + any custom G-Eval metrics with criteria.
2. Judge model. Named model + version, rationale for cost vs accuracy.
3. Calibration. Hand-labeled set size, target Spearman rho vs human > 0.7.
4. Dataset versioning. Tag strategy, change log, stratification.
5. CI gate. Thresholds per metric, regression-window logic, bottom-quantile alert.

Refuse to rely on a judge untested against ≥50 human-labeled examples. Refuse self-evaluation (same model generates + judges). Refuse aggregate-only reporting without bottom-10% surfacing. Flag any pipeline where judge upgrade lands without parallel baseline eval.

Exercícios

  1. Fácil. Use o RAGAS em 10 exemplos de RAG com alucinações conhecidas. Verifique se a métrica de fidelidade captura cada uma delas.
  2. Médio. Rotule à mão 50 respostas de QA de 0 a 1 para correção. Pontue com G-Eval. Meça o rho de Spearman entre juiz e humano.
  3. Difícil. Construa um portão de CI com pytest usando DeepEval. Regrida intencionalmente o recuperador. Verifique se o portão falha. Adicione alerta de quantil inferior via verificação de limiar nos 10% mais baixos.

Termos-chave

Termo O que as pessoas dizem O que realmente significa
LLM-como-juiz Pontuar com um LLM Instruir um modelo juiz a pontuar saídas de 0 a 1 dada uma rubrica.
RAGAS A biblioteca de métricas de RAG Framework de avaliação open-source com 4 métricas de RAG sem referência.
Fidelidade A resposta está fundamentada? Fração das afirmações da resposta sustentadas pelo contexto recuperado.
Precisão de contexto Os chunks recuperados eram relevantes? Fração dos top-K chunks que de fato importaram.
Recall de contexto A recuperação encontrou tudo? Fração das afirmações da resposta de ouro sustentadas pelos chunks recuperados.
G-Eval Juiz LLM personalizado Rubrica + passos de avaliação por cadeia de pensamento + pontuação 0-1.
Calibração Confie, mas verifique Correlação de Spearman entre a pontuação do juiz e a pontuação humana.

Leitura Adicional

0 lifetime access. Curriculum based on AI Engineering from Scratch by Rohit Ghumare (MIT, used under attribution).