Como comparar duas IAs de decisão pela divergência entre elas (e não só pela taxa de acerto)

Gráfico de matriz de confusão usado para comparar duas IAs de decisão
Resposta rápida

Para comparar duas IAs de decisão, não basta olhar a taxa de acerto: dois modelos com a mesma acurácia podem errar em casos opostos. O método é rodar os dois no mesmo conjunto rotulado, montar a matriz de confusão de cada um (separando falso positivo de falso negativo, com precisão e recall), medir a concordância entre eles com o kappa de Cohen (cohen_kappa_score no scikit-learn) e aplicar o teste de McNemar só nos pares discordantes. Aí você escolhe pelo custo do erro: menos FN quando perder um caso dói mais, menos FP quando o alarme falso é o problema

Duas IAs de decisão com a MESMA taxa de acerto podem errar em casos completamente diferentes

E isso muda qual delas você deve colocar em produção 😀

Fala aí, beleza? O Jev, da TypeSafe AI, foi anunciado em 15 de setembro de 2026 como o primeiro modelo público da categoria que a empresa chama de System One Models

E ele não é um chatbot: você manda um estado (a informação a avaliar) e perguntas (o que decidir), e ele devolve uma decisão estruturada, ou seja, uma opção, um score ou uma probabilidade

Nada de texto redigido

Aí que fica interessante: como a saída é estruturada, dá pra colocar o Jev lado a lado com um concorrente qualquer (por exemplo, um LLM generalista com saída estruturada) e comparar item a item, como se fossem dois avaliadores humanos classificando os mesmos casos

O método que te mostro aqui tem três peças: a matriz de confusão de cada modelo, a concordância entre os dois e a análise só dos casos em que eles discordam

Bora ver na prática?

O que você precisa antes de comparar o Jev com outro modelo

Antes de qualquer código, se liga no que precisa estar na mesa:

  • Um conjunto de itens com o rótulo real conhecido: é a verdade do seu problema, o gabarito. Sem isso não existe acerto nem erro, só opinião de IA
  • O mesmo conjunto passado pelos dois modelos: cada item recebe a decisão do Jev e a decisão do concorrente
  • Python com scikit-learn: vamos usar confusion_matrix e cohen_kappa_score, as duas em sklearn.metrics
  • Acesso ao Jev: ele está disponível no Vercel AI Gateway, na Cloudflare, no OpenRouter (ID typesafe/jev-1.13) e pela API direta
Formação Claude Code
Formação Recomendada

Formação Claude Code

Domine Claude Code do absoluto zero até o avançado

  • 120 aulas
  • 4 projetos
  • 9h 45min

Tome cuidado com a API direta: o acesso ainda parece desigual entre contas, então se a sua não liberou, as outras vias resolvem 🙂

E o custo?

O Jev 1.13 sai por US$ 0,042 por milhão de tokens de entrada e US$ 0,00 na saída, e o preço no OpenRouter é igual ao direto da TypeSafe

Porém a própria empresa avisa que esse preço inicial pode estar subsidiado, então confira a tarifa atual antes de ir pra produção

O foco aqui é o método de comparação, então instalação e código de chamada ficam de fora: no Passo 2 você vê só os tipos de pergunta da API e o que cada um devolve, que é o que interessa pra montar a tabela

Passo a passo: comparando duas IAs de decisão pelo tipo de erro

A ideia central é simples: acurácia te diz QUANTO cada modelo erra, mas não diz ONDE

E o onde é o que importa na hora de decidir

  1. Monte o dataset pareado

Cada linha precisa ter o mesmo item, o rótulo real, a decisão do modelo A e a decisão do modelo B

Os dados abaixo são ILUSTRATIVOS, só pra estrutura do código ficar clara, não são resultado de teste nenhum:

# Dados ilustrativos: 1 = positivo (sim), 0 = negativo (não)
y_real   = [1, 0, 1, 1, 0, 0, 1, 0, 1, 0]
y_jev    = [1, 0, 0, 1, 0, 1, 1, 0, 1, 0]
y_rival  = [1, 1, 1, 1, 0, 0, 0, 0, 1, 0]

Erro comum deste passo: avaliar cada modelo num conjunto diferente

Se o Jev viu os casos fáceis e o concorrente viu os difíceis, a comparação pareada vai pro lixo, beleza?

  1. Colete as decisões do Jev com o tipo de pergunta certo

A API do Jev tem três tipos de pergunta:

  • Choice: devolve a opção escolhida (.choice), uma probabilidade pra cada opção (.probabilities) e a confiança (.confidence)
  • Score: devolve um score que pode cair entre níveis (.score), mais probabilidades e confiança
  • Noul: devolve um único número de 0 a 1 (.noul), a probabilidade de a resposta ser sim

Pra escolher entre opções, Choice

Pra sim ou não, Noul

E guarde a confiança junto! Ela vai de 0 a 1 e é calculada pelo formato da distribuição de probabilidades (detalhes aqui): toda a massa numa opção dá 1.0, e quanto mais espalhada a distribuição, menor a confiança

A TypeSafe diz que essa confiança é calibrada, e isso é uma afirmação do próprio fabricante, então vale conferir com os seus dados

Se usar Noul, você precisa transformar o número em sim ou não, e o corte é escolha SUA, depende do problema:

def noul_para_rotulo(valores_noul, corte):
    # corte: você define, de acordo com o custo de cada tipo de erro
    return [1 if v >= corte else 0 for v in valores_noul]

Erro comum deste passo: descartar a confiança

Aí você perde justamente a chance de ver onde o modelo erra com convicção, que é o erro mais perigoso

  1. Monte a matriz de confusão de cada modelo

Que matriz?

É uma tabela 2×2 que cruza a classe prevista com a classe real, e dela saem dois tipos de erro bem diferentes:

  • Falso positivo (FP): caso negativo previsto como positivo, o erro tipo I, o alarme falso
  • Falso negativo (FN): caso positivo previsto como negativo, o erro tipo II, o caso perdido

Com isso você calcula precisão (a fração das afirmações "é positivo" que estão certas, penaliza FP) e recall (a fração dos positivos reais que foram encontrados, penaliza FN):

from sklearn.metrics import confusion_matrix

def perfil_de_erro(nome, y_real, y_pred):
    print(nome)
    print(confusion_matrix(y_real, y_pred))

    vp = sum(1 for r, p in zip(y_real, y_pred) if r == 1 and p == 1)
    fp = sum(1 for r, p in zip(y_real, y_pred) if r == 0 and p == 1)
    fn = sum(1 for r, p in zip(y_real, y_pred) if r == 1 and p == 0)

    precisao = vp / (vp + fp) if (vp + fp) else 0
    recall = vp / (vp + fn) if (vp + fn) else 0
    print(f"FP={fp}  FN={fn}  precisão={precisao:.2f}  recall={recall:.2f}")

perfil_de_erro("Jev", y_real, y_jev)
perfil_de_erro("Rival", y_real, y_rival)

Repara que eu conto FP e FN na mão, assim não tem dúvida de qual número é qual 🙂

Erro comum deste passo: parar na acurácia

Acurácia junta FP e FN no mesmo balde, e é exatamente isso que a gente quer separar

  1. Meça a concordância entre os dois com o kappa de Cohen

O kappa mede o quanto dois avaliadores concordam ao classificar os mesmos itens, descontando a concordância que aconteceria por acaso

A fórmula é κ = (Po – Pe) / (1 – Pe), em que Po é a concordância observada e Pe a esperada por acaso, calculada a partir das proporções de cada avaliador

No scikit-learn é uma linha só (documentação do cohen_kappa_score):

from sklearn.metrics import cohen_kappa_score

kappa = cohen_kappa_score(y_jev, y_rival)
print(f"kappa entre Jev e rival: {kappa:.2f}")

O resultado vai de -1 a 1: 1 é concordância total e 0 é nenhuma concordância além do acaso

Pra ler o número, a escala de Landis e Koch (1977) ajuda:

Kappa Leitura
menor que 0 ruim
0,00 a 0,20 leve
0,21 a 0,40 razoável
0,41 a 0,60 moderada
0,61 a 0,80 substancial
0,81 a 1,00 quase perfeita

E se as saídas tiverem ordem, como os níveis de um Score?

Aí entra o parâmetro weights, que aceita None, 'linear' ou 'quadratic', e passa a tratar discordância entre níveis vizinhos como menos grave que discordância entre extremos

Erro comum deste passo: usar a concordância percentual bruta

Quando uma classe domina, dois avaliadores que só chutam o rótulo mais comum vão coincidir MUITO, e a porcentagem fica inflada. O kappa tira essa linha de base

  1. Monte a tabela de discordância e rode o McNemar

O teste de McNemar compara dois classificadores avaliados nos mesmos itens usando uma tabela 2×2 de resultados pareados

Rival acertou Rival errou
Jev acertou os dois acertaram c
Jev errou b os dois erraram

Aqui o modelo 1 é o Jev: b são os itens que ele errou e o rival acertou, c são os que ele acertou e o rival errou

Só b e c entram na conta: χ² = (b – c)² / (b + c), com hipótese nula de que nenhum dos dois é melhor que o outro

A conta é curta, então dá pra fazer em Python puro mesmo:

b = sum(1 for r, a, z in zip(y_real, y_jev, y_rival) if a != r and z == r)
c = sum(1 for r, a, z in zip(y_real, y_jev, y_rival) if a == r and z != r)

if b + c == 0:
    print("Nenhum par discordante: não dá pra comparar")
else:
    chi2 = (b - c) ** 2 / (b + c)
    print(f"b={b}  c={c}  qui-quadrado={chi2:.2f}")

E por que ignorar os itens em que os dois concordam?

Porque eles não dizem nada sobre qual é melhor, só os discordantes informam a diferença entre os modelos

Erro comum deste passo: tirar conclusão com pouquíssimos pares discordantes

O resultado depende inteiramente desse punhado de casos, então com dois ou três discordantes qualquer veredito é chute com cara de estatística haha

Quando as duas IAs acertam igual, mas erram em pontos opostos

Esse é o cenário que engana mais gente, então vale parar nele

Duas IAs com a mesma acurácia podem ter perfis de erro opostos: uma concentra falsos positivos (dá alarme demais) e a outra concentra falsos negativos (deixa caso passar)

No placar geral, empate. Na prática, são ferramentas diferentes

Como reconhecer esse cenário nos números?

  • Precisão e recall invertidos: um modelo tem precisão alta e recall baixo, o outro o contrário
  • Kappa mais baixo do que a acurácia sugeriria: se os dois acertam muito mas discordam bastante entre si, é sinal de que acertam e erram em itens diferentes
  • b e c parecidos no McNemar: o χ² fica perto de zero, então não tem vencedor estatístico, mas os perfis de erro continuam distintos

Se liga nisso: "sem vencedor estatístico" não quer dizer "tanto faz"

Quer dizer que a escolha sai do campo da estatística e vai pro custo do erro no seu negócio

Quando o caso perdido custa mais caro

Pensa numa triagem em que deixar passar um caso positivo dói muito mais do que revisar um alarme à toa

Aqui você prefere o modelo com menos FN, ou seja, maior recall

Quando o alarme falso custa mais caro

Agora o contrário: cada positivo dispara uma ação cara ou chata pro usuário, tipo bloquear algo ou acionar alguém

Aí o modelo com menos FP, maior precisão, é o que faz sentido

Quando usar a discordância como sinal de revisão

E se os dois erram em pontos opostos, por que não usar isso a seu favor?

Quando o Jev e o concorrente discordam num item, esse item vira candidato a revisão humana

Os casos em que os dois concordam seguem automáticos, e o humano só olha onde as IAs brigaram 😀

Essa lógica de decidir qual modelo responde o quê conversa direto com o controle do roteador de modelos, porque no fundo é a mesma pergunta: quem decide, e quando

Tudo isso aqui é exemplo didático, beleza? Não estou atribuindo perfil de erro real nem ao Jev nem a nenhum concorrente, quem vai dizer isso é a tabela com os SEUS dados

Conclusão: acurácia é o começo, não o veredito

Recapitulando o método:

  • Matriz de confusão: separa FP de FN e te dá precisão e recall de cada modelo
  • Kappa de Cohen: mede o quanto os dois concordam descontando o acaso
  • McNemar: testa se um é melhor que o outro usando só os pares discordantes
  • Leitura dos discordantes: mostra ONDE cada um erra e se a discordância serve de gatilho pra revisão

O próximo passo é bem concreto: separa uma amostra rotulada do seu próprio problema, roda o Jev e o modelo que você usa hoje nela e monta a tabela de discordância antes de pensar em qualquer migração

Se a comparação apontar pro Jev, vale padronizar o uso no time desde o começo, pra cada dev não sair configurando de um jeito

E antes de produção, confere a tarifa vigente do Jev, já que a própria TypeSafe avisa que o preço inicial pode estar subsidiado

Até o próximo post! 🙂

Perguntas frequentes

Qual a diferença entre acurácia e kappa de Cohen ao comparar duas IAs de decisão

Acurácia só diz quanto cada modelo acerta sozinho, sem olhar pro outro. O kappa de Cohen mede a concordância entre os dois nos mesmos itens, descontando o que seria concordância por acaso. Dois modelos com acurácia parecida podem ter kappa baixo, e isso é sinal de que eles erram em casos diferentes.

O teste de McNemar substitui o kappa de Cohen na comparação entre Jev e outro modelo

Não, eles respondem perguntas diferentes. O kappa mede o quanto os dois concordam no geral. O McNemar usa χ² = (b − c)² / (b + c), olhando só pros pares discordantes, pra testar se um modelo erra mais que o outro justamente nesses casos.

Como interpretar o valor do kappa de Cohen depois de comparar duas IAs de decisão

A escala de Landis e Koch (1977) ajuda: abaixo de 0 é ruim, de 0,00 a 0,20 é leve, de 0,21 a 0,40 é razoável, de 0,41 a 0,60 é moderada, de 0,61 a 0,80 é substancial e de 0,81 a 1,00 é quase perfeita. O resultado do cohen_kappa_score do scikit-learn vai de −1 a 1, então dá pra encaixar direto nessa régua.

Dá pra comparar o Jev com um LLM generalista usando esse mesmo método

Dá, desde que o concorrente também devolva uma saída estruturada no mesmo formato de classificação. O ponto chave é que o Jev entrega opção, score ou probabilidade, não texto redigido, então a comparação item a item funciona como se fossem dois avaliadores classificando os mesmos casos.

Por que a confiança do Jev importa na hora de comparar os erros entre modelos

Porque ela mostra se o modelo errou com convicção ou na dúvida, e isso muda o risco de colocar aquele modelo em produção. A confiança do Jev vai de 0 a 1 e sai da concentração das probabilidades: quanto mais a massa fica numa opção só, mais perto de 1.0. A TypeSafe chama essa confiança de calibrada, e isso é uma afirmação do próprio fabricante.

Quanto custa gerar os dados do Jev pra fazer essa comparação

O Jev 1.13 cobra US$ 0,042 por milhão de tokens de entrada e US$ 0,00 na saída, mesmo preço no OpenRouter e direto na TypeSafe. A própria empresa avisa que esse valor inicial pode estar subsidiado, então vale conferir a tarifa atual antes de rodar qualquer comparação pensando em produção.



Escrito por | Matheus Battisti

Matheus Battisti
Fundador da Hora de Codar

Programador apaixonado pelo mundo das tecnologias, sempre buscando em aprender e se aprofundar em linguagens, frameworks e o que mais for necessário para executar um bom trabalho. Agora tem uma nova missão que é de passar seu conhecimento adiante para formar novos programadores e especializar mais os que já são.

Subscribe
Notify of
guest

0 Comentários
Oldest
Newest Most Voted

Formações

Formação Vibe Coding

Formação Vibe Coding

Do Prompt ao Produto: Crie Software Real com IA

  • 474 aulas
  • 20 projetos
  • 39h 27min

Blog | Mais populares