跳到正文
DEV Community· Vitoria AYRES·· 8 小時前AI 評分59

作者以 ENEM 2024 基準測試 LLM,三個模型統計上不分勝負

Testei LLMs no ENEM 2024, e o ranking não diz o que parece

AI 導讀

作者以 ENEM 2024 的 73 道文字題建立巴西葡萄牙語 LLM 基準,測試 Qwen3.8 27B、GPT-OSS 120B 和 GPT-OSS 20B。Qwen3.8 27B 以 97,0% 排第一,但三組逐題配對差異的 95% 信賴區間均包含 0,73 題不足以判定勝負。作者亦把 GPT-OSS 20B 的兩道空白回答改列模型失敗並計 0 分;本輪測試不涵蓋作文或語用能力。

正文

Um modelo de 27 bilhões de parâmetros ficou à frente de um de 120 bilhões no meu benchmark de ENEM. A manchete seria fácil, mas ela estaria errada: os três modelos que testei empataram estatisticamente.

Construí um benchmark aberto para medir LLMs em português do Brasil. O resultado mais útil da primeira rodada não foi quem ganhou, mas o que a ordem do placar não permite concluir.

Por que medir em português do Brasil

Os placares populares são em inglês, e traduzir questões não mede o que importa para quem usa esses modelos aqui. Entender a norma culta, a cultura, as instituições e os implícitos da língua exige perguntas feitas no nosso contexto.

Comecei pelo ENEM porque é uma prova pública, conhecida e com gabarito oficial.

Como medi

A primeira rodada usou 73 questões de texto do ENEM 2024: 40 de conhecimento e 33 de interpretação. Questões que dependem de imagem ficaram de fora, porque um modelo só de texto não teria como resolvê-las.

  • Condições iguais: mesmo prompt, temperatura 0 e o mesmo limite de 2048 tokens de saída para todos.
  • Intervalo de confiança em toda nota: com dezenas de questões, alguns pontos de diferença podem ser só ruído.
  • Sem chute na correção: se a resposta não indica uma alternativa válida, ela vale 0.
  • Custo zero: tudo rodou em planos gratuitos, inclusive o limite de cerca de 1 requisição por minuto do Qwen.

Do PDF ao dataset

As questões saem direto dos PDFs oficiais do INEP, e essa foi a parte menos glamorosa do projeto. O texto extraído com pypdf vem cheio de ruído: marca d'água, código de barras da página, cabeçalhos e até o rodapé da gráfica colado no fim da última linha.

O extrator limpa esse ruído com expressões regulares e separa a prova pelos marcadores de questão. Um detalhe: alguns títulos usam espaços especiais do Unicode, como U+2003, e um espaço comum na regex não os encontra.

Depois vêm os filtros, que deixam cada questão fora em vez de arriscar um item quebrado:

  1. Questões 1 a 5 saem, porque são de inglês ou espanhol.
  2. Questões sem gabarito saem, porque foram anuladas.
  3. Questões sem as 5 alternativas lidas por inteiro saem.
  4. Questões que provavelmente dependem de imagem saem.

Das 85 questões em português do primeiro dia, 73 passaram. O filtro de imagem é uma heurística: procura palavras como "charge", "gráfico" e "mapa", e também desconfia de enunciados com menos de 80 caracteres. Ele pode errar nos dois sentidos, e isso é uma limitação conhecida.

As questões não ficam no repositório, porque os textos de apoio têm direitos de terceiros. O projeto distribui o extrator, e cada pessoa gera os itens a partir dos PDFs públicos.

Rodar de graça sem perder resultado

O avaliador é uma CLI em Python, com cerca de 2.700 linhas de código e 194 testes automatizados. As chamadas passam por um cliente único via LiteLLM, então adicionar um modelo é acrescentar uma entrada em um arquivo YAML.

No plano gratuito, o maior desafio é a cota. Três mecanismos tornam a execução segura de interromper e retomar:

  • Cache em SQLite: a chave é um SHA-256 de modelo, item, tentativa, mensagens e parâmetros. Se qualquer um deles muda, a chave muda, e uma resposta antiga nunca é reaproveitada por engano.
  • Limitador de taxa: respeita limites por provedor e por modelo. Na Groq, configurei 30 requisições por minuto e 1.000 por dia, e o Qwen ficou em 1 por minuto.
  • Novas tentativas só para erros transitórios: são até 3, com espera exponencial a partir de 2 segundos, respeitando o retry-after do provedor, com teto de 60 segundos.

O cache guarda apenas respostas bem-sucedidas, então uma nova execução refaz só o que falhou. Isso tem um custo: como max_tokens faz parte da chave, mudar esse parâmetro refaz todas as respostas do modelo. Com o Qwen, 76 chamadas levam cerca de 76 minutos.

Como a resposta vira nota

O prompt deixa o modelo raciocinar, mas exige que ele termine com Resposta: X. O extrator pega a última ocorrência desse marcador, ignorando negrito, maiúsculas e acentos. Sem o marcador, só aceita a última linha se ela for exatamente uma alternativa.

Essa regra é propositalmente rígida. Ela favorece modelos que seguem formato, e essa escolha é consciente: seguir instrução faz parte de ser útil. O ponto mais delicado é separar a falha do modelo da falha da infraestrutura:

Situação Nota Entra na média
Correta 1 Sim
Incorreta 0 Sim
Sem resposta: recusa, resposta vazia, alternativa inexistente ou ambígua 0 Sim
Erro de API que persistiu após as novas tentativas 0 Não

Um timeout do provedor não diz nada sobre o modelo, então fica fora da média. Na rodada publicada, nenhum modelo teve erro de API.

Como calculei a incerteza

A nota geral é uma média macro: primeiro a média de cada categoria, depois a média das categorias. Assim, a categoria com mais itens não domina o placar. Por isso o Qwen aparece com 97,0%, embora tenha acertado 71 de 73 questões, ou 97,3%.

O intervalo de confiança vem de um bootstrap por percentil. São 2.000 reamostragens com reposição, feitas dentro de cada categoria e com semente fixa, então qualquer pessoa obtém o mesmo intervalo.

Comparar intervalos sobrepostos não basta para decidir um empate, porque todos os modelos responderam às mesmas questões. Por isso, calculo a diferença questão a questão e faço o bootstrap sobre essa diferença. Se o intervalo inclui 0, os modelos estão empatados.

O resultado

O Qwen3.8 27B ficou em primeiro com 97,0%, mas os intervalos dos três modelos se sobrepõem. Com 73 questões, a ordem não aponta um vencedor.

Posição Modelo Geral IC de 95% Conhecimento Interpretação
1 Qwen3.8 27B 97,0% 92,4 a 100 100% 93,9%
2 GPT-OSS 120B 93,9% 87,9 a 98,5 100% 87,9%
3 GPT-OSS 20B 89,7% 82,1 a 95,7 97,5% 81,8%

A nota geral é a média das duas categorias. Em conhecimento, dois modelos gabaritaram, então é a interpretação de texto que separa os resultados.

O que aparece quando se olha questão a questão

Nenhuma das três comparações pareadas exclui o zero. As diferenças abaixo usam as 73 questões, com o mesmo peso para cada uma:

Comparação Diferença (pontos percentuais) IC de 95%
Qwen3.8 27B e GPT-OSS 20B +6,8 -1,4 a +15,1
GPT-OSS 120B e GPT-OSS 20B +4,1 -1,4 a +11,0
Qwen3.8 27B e GPT-OSS 120B +2,7 -4,1 a +8,2

Os erros contam uma história mais interessante que a média:

  • A prova está perto do teto: os três acertaram 63 das 73 questões, ou 86%. Só 10 questões separam os modelos, e nenhuma derrubou os três.
  • Os erros se concentram: 8 das 10 questões estão entre a 22 e a 31, e 9 das 10 são de interpretação.
  • As famílias erram em lugares diferentes: o Qwen errou as questões 25 e 26, e nenhum GPT-OSS errou essas duas. Os dois GPT-OSS compartilham 3 erros: 22, 28 e 29.
  • Não vi preferência por letra: a distribuição das alternativas escolhidas ficou a no máximo 3 questões do gabarito em cada letra.

Quantas questões seriam necessárias para separar o Qwen do GPT-OSS 120B? Eles discordaram em 6 das 73 questões, com saldo de 2 para o Qwen. Se essa proporção se mantivesse, seriam cerca de 420 questões para o intervalo de 95% excluir o zero. É uma conta aproximada, mas mostra a escala: o próximo ganho vem de mais itens e itens mais difíceis, não de mais modelos.

Tokens e latência

O modelo maior foi o mais econômico: o GPT-OSS 120B gastou metade dos tokens de saída do 20B, com nota numericamente maior.

Modelo Tokens de saída (total) Mediana por resposta Máximo Latência mediana Latência p95
GPT-OSS 120B 17.187 218 706 0,83 s 1,55 s
Qwen3.8 27B 34.255 448 934 1,25 s 2,10 s
GPT-OSS 20B 34.813 367 2.048 1,07 s 2,84 s

Dois cuidados na leitura. Tokens não são diretamente comparáveis entre famílias: o mesmo conjunto de prompts deu 29.385 tokens de entrada nos GPT-OSS e 26.301 no Qwen, porque os tokenizadores são diferentes. E a latência depende da fila do provedor no plano gratuito, por isso ela é registrada, mas não entra na nota.

O modelo que raciocinou até acabar os tokens

O achado mais curioso veio de um erro. Em 2 questões, o GPT-OSS 20B devolveu uma resposta vazia.

A primeira suspeita foi o limite de 2048 tokens, e o uso registrado confirmava: ele gastou tudo raciocinando. Testei de novo com 4096 e 6500 tokens, e ele continuou sem responder. Nas mesmas questões, o GPT-OSS 120B e o Qwen resolveram com menos de 800 tokens.

Essa investigação expôs uma falha no meu próprio benchmark. A regra tratava a resposta vazia como erro de infraestrutura, que fica fora da média. Na prática, o modelo deixava de responder e não perdia ponto. Mudei a regra: resposta vazia agora é falha do modelo e vale 0.

Também decidi não aumentar o limite só para esse modelo. A metodologia exige o mesmo max_tokens para todos, e o aumento não resolveu. Com a regra nova, as 2 questões contam como sem_resposta, e a nota do 20B reflete o custo real desse comportamento. Ainda não sei por que ele raciocina tanto nelas: isso segue como pergunta aberta.

O que este resultado não prova

  • Que o Qwen é melhor: a diferença cabe dentro do intervalo de confiança.
  • Que os modelos dominam o português: a rodada cobre só questões de texto do ENEM, sem redação ou pragmática.
  • Que não houve contaminação: as questões são posteriores à data de corte dos GPT-OSS, mas falta um grupo anterior para comparar, e o Qwen não tem data de corte configurada.
  • Que os modelos sabem o conteúdo, e não a posição: o benchmark gira as alternativas para testar isso, mas essa verificação não rodou nesta primeira rodada.
  • Que o resultado se repete: cada questão foi respondida uma vez, e temperatura 0 não garante respostas idênticas entre execuções.

Os próximos passos são criar questões mais difíceis, incluir ironia e vida prática no Brasil e avaliar redações. Em um benchmark, saber o que o número não diz vale tanto quanto o número.

O código, a metodologia e o placar estão no repositório do projeto no GitHub.

來源:DEV Community · dev.to