Skip to content
This page has been auto-translated and may contain errors.View in English

Evals ​

docs.scrimba.com

Você muda um prompt, testa uma vez, a resposta parece melhor, você publica, e uma semana depois os usuários encontram os casos que a mudança silenciosamente piorou. Um eval (abreviação de "evaluation", avaliação) é a solução: um teste repetível para saber se sua funcionalidade de IA funciona, um conjunto de entradas pareadas com o que seria uma boa saída, avaliado sempre da mesma forma para que você saiba se uma mudança realmente ajudou. Um modelo é uma caixa-preta probabilística que responde à mesma pergunta de forma diferente a cada execução, então medir é a única forma de saber ao certo, e essa disciplina é boa parte do que separa uma demonstração de um produto.

Por que confiar no olho falha ​

Checar as respostas da sua IA manualmente parece funcionar bem no começo. Você executa um prompt, lê a resposta, ela parece boa, e você segue adiante. O problema é que três coisas trabalham silenciosamente contra você, e você já encontrou todas elas.

Aqui estão as três:

  • A saída varia. O mesmo prompt pode gerar respostas diferentes a cada execução, então um resultado bom não garante que o próximo também será bom.
  • Mudanças causam regressões. Um ajuste no prompt que corrige um caso costuma quebrar outro que você não estava observando.
  • Não escala. Você consegue ler cinco respostas. Você não consegue ler quinhentas toda vez que mudar uma linha.

Nada disso significa que você fez algo errado. Significa que confiar no olho é a ferramenta errada para um trabalho desse tamanho, e existe um jeito mais tranquilo de fazer isso.

JunoPor que confiar no olho falha Ler respostas manualmente falha por três motivos, todos enraizados em como o modelo funciona: a saída varia de execução para execução, edições quebram silenciosamente casos que você não estava observando, e você não consegue acompanhar manualmente quando há centenas de respostas. Não é um problema de disciplina, é a ferramenta errada para o tamanho do trabalho. A boa notícia é que a solução é simples, e ela vem a seguir.

Olhar para uma única resposta não te diz quase nada, e o motivo está em como o modelo funciona. Como a saída é não-determinística (o mesmo prompt pode gerar respostas diferentes a cada execução), uma única resposta é uma amostra de tamanho um. Ela não consegue te mostrar a taxa de acerto, a proporção de casos que saem corretos, porque você precisa de muitas execuções sobre os mesmos casos para estimar com que frequência a IA realmente funciona.

Regressões se escondem por um motivo parecido. Corrija um caso manualmente e você não tem registro dos outros, então a próxima edição pode quebrar algo que você parou de observar. A única forma de perceber isso é ter um conjunto fixo de casos avaliado sempre da mesma maneira, de modo que uma queda apareça como um número em vez de uma surpresa em produção.

Há também um problema humano além da matemática. A revisão manual varia entre pessoas e entre estados de humor: a mesma resposta parece boa na segunda-feira e fraca na sexta-feira. Por isso o caminho é transformar "parece bom" em uma taxa de acerto medida sobre um conjunto fixo de casos. Transforme uma impressão em um número, sobre os mesmos casos.

JunoPor que confiar no olho falha Uma resposta é uma amostra de tamanho um, então ela só te diz que o modelo funcionou uma vez, não com que frequência ele funciona. Para ver uma taxa de acerto real você executa muitos casos; para pegar regressões você fixa esse conjunto de casos e avalia sempre da mesma forma. A revisão manual também varia com quem está revisando, então o objetivo é substituir "parece bom" por um número medido.

Checar por amostragem não falha porque você é descuidado. Falha porque já traz um viés de seleção embutido: você olha para os casos que espera que funcionem, então o comportamento que você nunca checa é justamente o que regride na frente dos usuários. A métrica que você não acompanha é exatamente a que se move.

Sem uma linha de base, toda mudança de qualidade é uma história que você conta para si mesmo. Você não consegue atribuir uma variação a uma edição específica, e não consegue fazer uma busca binária num conjunto de mudanças para descobrir qual delas derrubou a taxa de acerto (a proporção dos seus casos que sai correta), porque você nunca mediu o "antes". "Parece melhor" sobrevive porque nada o contradiz.

Iterar por impressão também causa overfitting. Você fica retestando os mesmos poucos exemplos, ajusta até que eles pareçam certos, e silenciosamente treina seu prompt para esse conjunto pequeno e particular enquanto o tráfego real vai para outro lugar. A revisão manual não consegue ver essa mudança de distribuição, porque as novas entradas são justamente as que você não está testando. Um conjunto de avaliação versionado com uma pontuação acompanhada é a única forma de dizer que uma mudança ajudou, em vez de apenas parecer melhor, e é isso que diferencia iterar de chutar.

JunoPor que confiar no olho falha Já publiquei coisas confiando na impressão e depois vi justamente o caminho que nunca checei por amostragem lotar os logs de erro, isso é o viés de seleção fazendo seu trabalho. Sem linha de base não há atribuição nem busca binária: você não consegue provar qual edição moveu o número se nunca teve um número. Mantenha um conjunto versionado e uma pontuação acompanhada, ou você está fazendo overfitting nos cinco exemplos que fica retestando enquanto o tráfego real vai para onde você não consegue ver.

Monte um conjunto de avaliação ​

Um conjunto de avaliação é uma lista de casos de teste. Cada caso tem uma entrada e o que seria uma boa saída para ela. Comece pequeno. De dez a vinte casos que cobrem suas situações comuns, mais alguns casos-limite complicados, são muito mais úteis do que nenhum, e você pode crescer o conjunto conforme encontra novas falhas no mundo real.

python
eval_set = [
    {"input": "A comida estava fria e atrasou.", "expected": "NEGATIVE"},
    {"input": "Melhor refeição da minha vida!", "expected": "POSITIVE"},
    {"input": "Foi ok, nada especial.", "expected": "NEUTRAL"},
    # ...adicione casos reais e casos-limite conforme forem descobertos
]

Quando um usuário relatar uma resposta ruim, adicione-a ao conjunto com a saída que ela deveria ter dado. Seu conjunto de avaliação se torna então uma memória crescente de todo erro que você nunca quer repetir, do mesmo jeito que um bug corrigido se transforma num teste que você mantém.

JunoMonte um conjunto de avaliação Um conjunto de avaliação é uma lista de casos de teste: uma entrada, e o que seria uma boa resposta. Comece com dez a vinte que cubram suas situações do dia a dia e alguns casos complicados. Toda vez que um usuário encontrar uma resposta ruim, adicione-a com a resposta que deveria ter sido dada, e seu conjunto silenciosamente lembra de todo erro que você não quer repetir.

Um conjunto de avaliação é sua coleção de casos de teste, cada um uma entrada pareada com a saída que você aceitaria como boa. O número que importa não é o tamanho, é a cobertura. Um conjunto de vinte casos bem escolhidos supera cinquenta casos descartáveis sempre.

Procure cobrir três coisas: o caminho comum que seus usuários de fato percorrem, os limites de decisão onde dois rótulos ficam próximos um do outro (os casos ambíguos bem na linha divisória), e os modos de falha conhecidos que você já viu acontecer. Escolher a dedo entradas favoráveis faz suas pontuações parecerem boas e não te diz nada, então mantenha o conjunto representativo do tráfego real.

Todo bug relatado por um usuário se torna um caso permanente no conjunto. Isso o transforma em uma suíte de regressão: um bug corrigido permanece corrigido porque o caso que o expôs agora é executado sempre. Quando suas saídas esperadas são estruturadas em vez de texto livre, como um rótulo ou um campo JSON, você pode avaliar por comparação exata, que é limpa e inequívoca, veja saída estruturada.

Mantenha uma fatia separada, reservada, contra a qual você nunca ajusta o modelo. Se você ajustar o prompt até passar exatamente nos casos que está observando, está avaliando a si mesmo nas respostas que já estudou, e a pontuação deixa de significar qualquer coisa.

JunoMonte um conjunto de avaliação Cobertura vence tamanho bruto: acerte o caminho comum, os limites ambíguos entre rótulos, e as falhas que você já viu acontecer. Transforme todo bug relatado em um caso permanente para que o conjunto funcione como uma suíte de regressão. Mantenha uma fatia reservada contra a qual você nunca ajusta, ou você estará se avaliando nas respostas que já estudou.

Trate o conjunto de avaliação como um ativo que você versiona junto com o prompt, porque os dois se movem juntos e uma mudança no prompt pode alterar silenciosamente o que conta como uma boa resposta. A qualidade dos rótulos do conjunto é o teto da sua métrica: um valor "esperado" errado limita sua pontuação e silenciosamente te ensina a lição errada, então cuidar bem dos rótulos importa tanto quanto coletar os casos.

Proteja-se contra vazamento de teste. Se você ajusta até passar exatamente no conjunto que está reportando, o número é teatro. Reserve uma fatia que você não olha enquanto itera, e revezetora com o tempo para que ela não acabe vazando lentamente para o seu ciclo de ajustes de qualquer forma.

Observe o equilíbrio entre classes. Um conjunto com noventa por cento de casos positivos evidentes vai reportar um número bonito enquanto esconde toda falha nos dez por cento que realmente importam, então amostre de forma que os casos difíceis e raros tenham peso real. Extraia casos de logs de produção em vez de imaginá-los, já que o tráfego real revela formulações que você nunca inventaria sentado na sua mesa.

Aceite que o conjunto se deteriora. À medida que o produto muda, casos antigos deixam de refletir o que os usuários enviam, e novos modos de falha surgem que o conjunto nunca viu. Cuidar dele é um trabalho contínuo, não uma construção feita uma única vez.

JunoMonte um conjunto de avaliação O conjunto é um ativo que você versiona junto com o prompt, e a qualidade dos rótulos é o teto rígido da sua métrica, um valor esperado errado limita a pontuação inteira. Reserve uma fatia e revezetora, ou o número que você reporta é teatro. Observe o equilíbrio entre classes, extraia casos reais dos logs, e assuma que o conjunto se deteriora conforme o produto muda, então cuidar dele nunca realmente termina.

Como avaliar ​

Tarefas diferentes precisam de avaliações diferentes, então o primeiro passo é combinar a checagem com o tipo de resposta que você espera.

  • Correspondência exata funciona quando existe apenas uma resposta correta: um rótulo de classificação, um campo extraído, um sim ou não. Você compara a saída diretamente com o valor esperado.
  • Avaliação por critérios funciona quando não há uma única resposta correta, como um resumo ou uma réplica. Você checa se a saída atende a condições: O resumo menciona o fato principal? Tem menos de 50 palavras? O tom é educado?
  • LLM como juiz usa uma segunda chamada ao modelo para avaliar a saída de acordo com seus critérios. Escala bem para questões de qualidade difíceis de definir que uma checagem simples não consegue capturar, mas o juiz também é um modelo, então pode errar, e você deve confrontar seu julgamento com o julgamento humano de vez em quando.
python
# avaliação por correspondência exata sobre o conjunto de avaliação
def run_evals(eval_set, classify):
    passed = 0
    for test in eval_set:
        output = classify(test["input"])
        if output == test["expected"]:
            passed += 1
        else:
            print(f'FAIL: "{test["input"]}" -> got {output}, wanted {test["expected"]}')
    print(f"{passed}/{len(eval_set)} passed")

Correspondência exata é o ponto de partida mais amigável, e se encaixa perfeitamente no trabalho de classificação e extração dos capítulos anteriores. A ideia do LLM como juiz funciona porque perceber se uma resposta atende a um padrão é geralmente uma previsão mais fácil do que produzir a resposta, do mesmo jeito que revisar uma redação é mais fácil do que escrevê-la. Mas o juiz é outro previsor com as mesmas falhas, então trate suas pontuações como uma estimativa útil, dê a ele um roteiro de avaliação claro, e confira suas notas contra as suas próprias em uma amostra de vez em quando.

JunoComo avaliar Escolha a checagem que se encaixa na resposta: correspondência exata quando há apenas uma resposta correta, critérios quando existem várias respostas boas, e um segundo modelo como juiz para qualidade difícil de definir. Correspondência exata é o começo mais tranquilo, e se alinha perfeitamente com a classificação e extração que você já praticou. Mas o juiz também é um modelo, então dê uma olhada nas notas dele de tempos em tempos.

Combine o avaliador com a tarefa, e depois use o mais barato que ainda capture o que importa para você. Um avaliador (grader) é o código ou a chamada ao modelo que decide se uma saída passou, e a escolha errada tanto deixa passar falhas reais quanto marca como erradas respostas que estavam corretas.

Correspondência exata serve para rótulos e campos extraídos: você compara a saída com o valor esperado e o resultado é determinístico, então você pode confiar nele. Combina naturalmente com saída estruturada, já que um modelo retornando um esquema fixo te dá algo limpo para comparar em vez de um texto livre.

Critérios programáticos cobrem o meio-termo de forma barata: cheque o tamanho, confirme que uma string obrigatória está presente, valide que o JSON é interpretável, execute uma expressão regular. Isso roda em milissegundos sem nenhuma chamada ao modelo, então use para qualquer coisa semiestruturada antes de gastar dinheiro com um juiz.

LLM como juiz serve para qualidade aberta, onde um resumo ou uma resposta têm várias formas boas e nenhum alvo exato. Precisa de um roteiro de avaliação escrito para que o juiz aplique um padrão consistente, além de uma checagem de calibração em que você compara suas notas com seus próprios rótulos em uma amostra. Lembre-se de que um avaliador também é código no qual você precisa confiar: um avaliador instável entrega uma pontuação confiantemente errada.

JunoComo avaliar Use o avaliador mais barato que ainda pegue o que importa: correspondência exata para rótulos e campos, checagens programáticas para tamanho, JSON válido ou string obrigatória, e um modelo como juiz só para qualidade aberta. Correspondência exata combina bem com saída estruturada porque um esquema fixo te dá algo limpo para comparar. Seja qual for a escolha, o avaliador também é código em que você confia, então um avaliador instável entrega uma pontuação confiantemente errada.

LLM como juiz é o avaliador que falha das formas mais interessantes, então planeje-se para seus vieses antes de depender dele. Um juiz favorece respostas mais longas, escolhe a primeira opção ao comparar um par, e recompensa textos que se parecem com seu próprio estilo, e suas pontuações absolutas são pouco calibradas, então um 8 numa execução não é o mesmo 8 na próxima.

Trate o juiz como um modelo que você está avaliando por conta própria. Fixe e versione o modelo usado como juiz, porque ele varia quando é atualizado e suas pontuações se movem junto. Dê a ele um roteiro de avaliação bem definido com alguns exemplos de referência, e depois meça a concordância entre o juiz e o humano em uma amostra rotulada, para saber até que ponto confiar nele.

Quando possível, peça uma comparação em pares ("A ou B é melhor?") em vez de uma pontuação absoluta de 1 a 10; julgamentos relativos costumam ser mais confiáveis do que pedir a um modelo que acerte um número calibrado. Fixe o juiz, dê um roteiro bem definido, confira contra humanos.

Cuide da circularidade e da conta. A mesma família de modelo avaliando sua própria saída compartilha os mesmos pontos cegos, então uma falha que o gerador cometeu é uma falha que o juiz provavelmente vai deixar passar, e avaliar todo caso em escala é uma segunda conta de modelo além da primeira.

JunoComo avaliar O juiz tem opiniões que você não pediu: ele gosta de respostas longas, da primeira opção, e de textos que soam como ele mesmo, e suas pontuações absolutas oscilam entre execuções. Fixe e versione o modelo usado como juiz, entregue um roteiro bem definido com exemplos de referência, e acompanhe com que frequência ele concorda com um humano, porque agora você está avaliando o avaliador. Prefira comparações em pares em vez de um solitário 1 a 10, e lembre-se de que um modelo julgando sua própria família compartilha os pontos cegos e dobra a conta.

Execute a cada mudança ​

Um conjunto de avaliação só é útil se você realmente o executar. Trate seus prompts como código: antes de publicar uma mudança em um prompt, em um modelo, ou na sua recuperação de dados, execute as avaliações e compare a pontuação com a de antes. Se o número caiu, você causou uma regressão, mesmo que seu único teste manual tenha parecido bom.

Isso é o que transforma a engenharia de prompt de um chute em algo que você pode iterar com confiança. Mude algo, meça, mantenha o que pontua melhor, e descarte o que pontua pior. É o mesmo ciclo que torna o software comum confiável, agora aplicado às partes difusas de uma funcionalidade de IA.

Se a pontuação caiu, você causou uma regressão. Um teste manual afortunado não anula o conjunto, então deixe o número decidir sempre.

JunoExecute a cada mudança Um conjunto de avaliação só ajuda se você o executa, então transforme isso em hábito: antes de qualquer mudança ir para produção, execute as avaliações e confira a pontuação em relação à última vez. Se ela caiu, isso é uma regressão a corrigir, não um acaso a ignorar. Mude, meça, mantenha o que pontua melhor, e você estará iterando em vez de chutando.

Conecte a execução das avaliações ao seu fluxo de desenvolvimento para que ela funcione como um portão de mudanças, do mesmo jeito que uma suíte de testes funciona como portão para um merge. Uma mudança em um prompt, em um modelo, ou na sua recuperação de dados (a etapa que traz documentos de apoio) não vai para produção até que você tenha executado o conjunto e comparado a pontuação com a execução anterior. O número, e não sua sensação depois de um único teste manual, decide se a mudança é uma melhoria.

Mude uma variável por vez. Se você editar o prompt e trocar o modelo na mesma passagem, uma variação na pontuação tem duas causas possíveis e você não consegue atribuí-la a nenhuma delas com certeza. Isole a mudança, execute o conjunto, leia o resultado, e só então avance para a próxima.

Leia o comparativo caso a caso, não apenas a pontuação agregada (o número único calculado pela média de todos os casos). Um total estável pode escondereste um caso que foi corrigido e outro que quebrou ao mesmo tempo, o que resulta em zero enquanto seu comportamento silenciosamente mudava. Olhar quais casos mudaram de resultado te diz o que sua mudança realmente fez.

Acompanhe a pontuação ao longo do tempo para que a melhoria fique visível e as regressões se destaquem. Um histórico registrado transforma "isso parece melhor" em uma linha que você pode apontar, e torna uma queda repentina fácil de rastrear até a mudança que a causou.

JunoExecute a cada mudança Trate a pontuação como um portão de mudanças, do mesmo jeito que testes são um portão para um merge: sem execução, sem publicação. Mude uma variável por passagem para que uma variação na pontuação tenha uma única causa, e leia o comparativo caso a caso, já que um total estável pode escondereste um caso corrigido e outro quebrado. Registre a pontuação ao longo do tempo para que os avanços fiquem visíveis e as regressões se destaquem.

Faça disso um portão real, não um ritual. Coloque um limite de pontuação na integração contínua para que uma mudança que fique abaixo da barra reprove a build, em vez de depender de alguém lembrar de olhar. E execute o conjunto novamente a cada atualização de versão do modelo, porque o mesmo prompt se comporta diferente em novos pesos; fixe a versão do modelo contra a qual você testou e reavalie antes de adotar uma nova.

Tenha duas armadilhas em mente. Primeiro, o conjunto de avaliação (sua coleção fixa de casos de teste com resultados esperados) é um substituto, não a verdade absoluta, então ajustar demais contra ele causa overfitting: você sobe a pontuação enquanto o comportamento real fica estagnado. Continue expandindo e revezetorando o conjunto para estar medindo a tarefa, não memorizando o teste.

Segundo, avaliações offline não são o quadro completo. Combine-as com sinais online: amostras de tráfego de produção, feedback de usuários, taxas de reclamação, e alimente falhas reais de volta ao conjunto como novos casos.

Como a saída é não-determinística, a mesma entrada pode pontuar diferente entre execuções. Execute amostras suficientes por caso e avalie contra uma tolerância em vez de perseguir o ruído de uma única execução; uma oscilação de um ponto entre execuções é a medição respirando, não uma regressão. Defina a barra em um nível que sobreviva a essa variação, ou você vai passar a semana investigando fantasmas. Já fiz exatamente isso, mais de uma vez.

JunoExecute a cada mudança Coloque um limite na integração contínua para que uma mudança ruim reprove a build, e reavalie a cada atualização de versão do modelo porque novos pesos leem o mesmo prompt de forma diferente. O conjunto é um substituto, então continue revezetorando ele e combine com sinais online, ou você vai fazer overfitting no seu próprio teste. E como a saída é não-determinística, avalie contra uma tolerância em vez de investigar fantasmas, o que sim, eu já fiz.

Na prática ​

A função run_evals da seção anterior é um arcabouço de avaliação completo, ainda que pequeno. Você aponta ela para seu classificador e seu conjunto de avaliação, e ela te diz quantos casos passam e mostra exatamente quais falham:

python
run_evals(eval_set, classify_review)
# FAIL: "Foi ok, nada especial." -> got POSITIVE, wanted NEUTRAL
# 2/3 passed

Aquela única linha de falha vale mais do que uma dezena de testes manuais bem-sucedidos, porque aponta para uma fraqueza real que agora você pode corrigir e medir de novo. O capítulo final, Segurança e limites, cobre os riscos contra os quais você precisa se planejar antes de colocar qualquer coisa disso na frente de usuários reais.

JunoNa prática Um arcabouço pequeno como run_evals já se paga: te dá uma pontuação e os casos exatos que quebraram. Corrija um, execute de novo, veja o número se mover. A seguir, Segurança e limites cobre o que observar antes que usuários reais cheguem.

Um pequeno arcabouço de avaliação (eval harness), o pedaço de código que executa cada caso do seu conjunto de avaliação e avalia a saída contra o que você esperava, é o ciclo que transforma "parece bom" em um número que você pode mover. Você executa o conjunto, recebe uma pontuação mais uma lista de falhas, corrige a falha real mais barata, executa de novo.

Cada caso que falha é uma unidade de trabalho com uma definição clara de "pronto": o caso passa. Isso é um alvo mais nítido do que "melhorar o prompt", porque você pode ver exatamente quando acerta e exatamente quando regride.

Antes que qualquer coisa disso chegue a usuários reais, o próximo capítulo, Segurança e limites, cobre os riscos contra os quais você se planeja com antecedência.

JunoNa prática O arcabouço transforma impressões em um número que você pode mover: execute o conjunto, leia a pontuação e as falhas, corrija a falha real mais barata, execute de novo. Cada falha é uma tarefa com uma definição clara de "pronto", o que é um alvo mais nítido do que "melhorar isso". Depois, Segurança e limites antes que usuários reais vejam isso.

Em produção, aquele pequeno arcabouço deixa de ser um script que você executa manualmente e passa a fazer parte do sistema. Ele cresce até se tornar um portão de integração contínua, uma checagem que bloqueia um lançamento quando a pontuação cai abaixo de um limite que você define, além de um painel que você acompanha entre lançamentos para pegar a deterioração lenta que uma única execução nunca mostra.

Avaliações offline, o conjunto fixo que você pontua antes de publicar, e monitoramento online, os sinais que você coleta do tráfego real depois, se alimentam mutuamente: falhas de produção se tornam novos casos offline, e o conjunto offline te diz se sua correção realmente se sustentou. As equipes que ganham aqui não são as que têm o prompt mais inteligente. São as que mediram enquanto todo mundo confiava no olho.

Essa é a disciplina. O próximo capítulo, Segurança e limites, cobre os riscos contra os quais você precisa se planejar antes que qualquer coisa disso chegue a usuários reais.

JunoNa prática Amadureça isso e o script se torna um portão de integração contínua mais um painel, com avaliações offline e monitoramento online se alimentando mutuamente. Já publiquei coisas confiando em "parece bom para mim" e paguei o preço depois, então pode confiar: as equipes que ganham mediram enquanto o resto confiava no olho. Leia Segurança e limites antes que usuários reais cheguem.