Um Modelo de Decisão "System 1" para Atendimento em PT-BR — Parte 3: A Régua Estava Errada (Benchmark, Ouro e a Trilogia v3→v4→v5)
- decisum
- making-of
- benchmarks
Decisum é o nome público do modelo que chamamos internamente de "decisor". Esta série de making-of preserva a nomenclatura interna usada durante o desenvolvimento.
Raphael Pizzo — Especialista em Machine Learning Outubro de 2026 · Série técnica, parte 3
Nota de anonimização: como nas Partes 1 e 2, todos os nomes de empresas, produtos, plataformas e clientes foram omitidos ou generalizados. O canal de mensagens que domina o volume segue chamado de
canal_msg. O único nome real neste texto é o do autor.
1. O incômodo que abriu esta parte
A Parte 2 terminou com o decisor-v3 recomendado para produção: acurácia geral 0,650 contra a prata corrigida, ECE pós-temperatura abaixo de 0,07 nas três perguntas, 30,9% das linhas roteáveis com 91% de acurácia no automático. Bons números — com uma ressalva que não saía da minha cabeça:
A prata continua prata. Regex melhorado ainda é regex.
Todo o edifício do v3 — treino, avaliação, o veredito negativo sobre o RLCD — estava apoiado em rótulos extraídos por regras determinísticas sobre os textos dos chamados. A adjudicação cega da Parte 2 já tinha mostrado que, nos pontos em que o v3 discorda da prata, a prata está errada em 63% dos casos de categoria. Ou seja: a régua não era só imperfeita, era imperfeita exatamente nos pontos que decidem a nota final.
Esta Parte 3 conta o que aconteceu quando paramos de discutir a régua e construímos uma nova — e o efeito dominó que isso provocou:
- Um benchmark pareado contra o próprio backbone em zero-shot, para isolar quanto do v3 é modelo e quanto é vazamento da régua;
- Uma adjudicação cega de 175 desacordos, para medir a acurácia real do v3 sem depender da prata;
- Um ouro de 1.000 chamados rotulado por leitura semântica (não por regex), mais 500 aleatórios — a primeira régua honesta do projeto;
- O v4, um resultado negativo curto e instrutivo: class weighting sobre rótulos ruidosos;
- O v5, a correção pela causa raiz: re-rotular o train inteiro com um juiz forte, e treinar de novo.
É a parte com mais reviravoltas por hora de GPU. E com o bug mais absurdo do projeto inteiro (seção 5.2 — envolve a loss chegar a 666).
2. Benchmark pareado: quanto do v3 é modelo?
2.1 Desenho
Antes de qualquer ouro, a primeira pergunta era de isolação: o v3 é um encoder mmBERT de 322M parâmetros com uma cabeça de classificação sobre option-markers. Se eu pegar o mesmo backbone, sem fine-tune, e fizer as mesmas três perguntas (categoria, decisão, urgência) em prompt zero-shot, quanto ele acerta? A diferença entre os dois é, por construção, o efeito do treinamento — nem mais, nem menos.
Protocolo idêntico ao da Parte 2 para os dois lados:
- gold: 5.193 linhas / 1.731 casos da prata corrigida;
- split por caso (seed 42): 862 casos para calibração, 869 para teste;
- temperature scaling idêntico (grid 0,25–5,0, minimizando ECE, ajustado só no calib) — nenhum modelo ganha calibração de graça;
- contexto de 1.024 tokens nos dois; limiar de roteamento 0,8 nos dois.
2.2 Resultado
| métrica | decisor-v3 | backbone zero-shot |
|---|---|---|
| acurácia categoria | 0,603 | 0,131 |
| acurácia decisão | 0,750 | 0,196 |
| acurácia urgência | 0,597 | 0,267 |
| acurácia geral | 0,650 | 0,198 |
| macro-F1 categoria | 0,267 | 0,092 |
| roteamento: % linhas no automático | 30,9% | 0,5% |
| roteamento: acurácia no automático | 0,909 | 0,286 |
Leituras:
- O fine-tune é o modelo. +45 pontos percentuais de acurácia geral
sobre o mesmo encoder. O backbone cru acerta 13% em categoria — menos
do que chutar a classe majoritária com disciplina — e erra de um jeito
específico e revelador: a confusão mais frequente dele é
canal_msg → fraude_suspeita(155 vezes). Para quem conhece o vocabulário do domínio, faz sentido: os textos decanal_msgestão cheios de palavras como "bloqueio", "conta restrita", "não autorizado" — que, sem contexto de produto, parecem fraude. O fine-tune não ensinou só categorias; ensinou o que essas palavras significam dentro desta plataforma. - O backbone cru é hiperconfiante. A temperatura ótima dele bateu no teto do grid (4,95) nas três perguntas, com ECE cru de até 0,545 — ele aposta tudo em respostas erradas. O v3, em contraste, calibra com T entre 1,3 e 1,8. Saber o que não sabe também é aprendido.
- Zero casos de concordância contra a prata. Em 2.117 linhas de desacordo entre v3 e backbone, não existe um único caso em que os dois concordem entre si divergindo da prata. Esse fato, curioso à primeira vista, é consistente com a hipótese de que os dois erram por mecanismos completamente diferentes — e montou o palco para a adjudicação da seção 3.
3. A adjudicação cega: quanto vale a prata nos pontos difíceis?
O benchmark mede concordância com a prata, não acurácia. Para medir acurácia de verdade sem esperar o ouro, desenhamos uma adjudicação:
- 175 casos amostrados dos desacordos do benchmark, estratificados: para categoria, 40 casos em que todos divergem, 25 em que o v3 erra e o backbone acerta a prata, 30 em que o v3 acerta a prata e o backbone erra; para decisão e urgência, 40 aleatórios cada.
- Juiz cego à procedência: o juiz via o estado do chamado e 2–3 respostas candidatas anonimizadas (A/B/C), sem saber qual era da prata, do v3 ou do backbone. Podia escolher uma letra, "nenhuma", ou propor um rótulo livre.
- O gabarito (qual letra era qual fonte) só foi aberto depois do 175º veredito.
3.1 Resultado central
| pergunta · estrato | n | prata certa | v3 certo | backbone certo | nenhum |
|---|---|---|---|---|---|
| categoria · todos divergem | 40 | 35% | 28% | 8% | 30% |
| categoria · v3 erra, backbone=prata | 25 | 40% | 28% | 40%* | 32% |
| categoria · v3=prata, backbone erra | 30 | 80% | 80% | 7% | 13% |
| categoria · total | 95 | 51% | 44% | 16% | 25% |
| decisão · total | 40 | 65% | 75% | 20% | 5% |
| urgência · total | 40 | 42% | 45% | 42% | 0% |
* nesse estrato, backbone e prata são a mesma letra por construção.
Três conclusões:
1. A prata é mais ruidosa do que se assumia. Nos desacordos de categoria em que v3≠prata, a prata erra 63% (decisão: 75%; urgência: 65%). A régua contra a qual o v3 foi medido — e treinado — está errada na maioria dos pontos contestados.
2. A acurácia real do v3 é maior que a reportada. Corrigindo pelos desacordos adjudicados (acc_prata + (1 − acc_prata) × P(v3 certo | desacordo)):
| pergunta | acurácia vs prata | acurácia real estimada |
|---|---|---|
| categoria | 0,603 | ≈ 0,71 |
| decisão | 0,750 | ≈ 0,90 |
| urgência | 0,597 | ≈ 0,76 |
(O leitor atento vai segurar esta tabela até a seção 4 — o ouro contou uma história diferente, e a diferença entre as duas é uma das lições desta parte.)
3. A confiança do v3 separa acerto de erro. Quando o juiz concordou com o v3, a confiança média dele era 0,650; quando discordou, 0,349. A calibração não é só um número agregado bonito — ela é informativa caso a caso, que é o que o roteamento por limiar precisa.
3.2 Os 24 "nenhum": lacunas de esquema, não ruído
Nos casos de categoria em que nenhum candidato tinha a resposta, os
rótulos livres propostos pelo juiz se concentraram em
duvida_produto (6), bug_produto (5) e conta_config (4) — "onde
fica o módulo de chamados?", erro 500 ao salvar usuário, troca de
responsáveis de fila. Ou seja: os desacordos mais duros vivem fora do
eixo incidente × canal_msg, nas fronteiras finas entre produto,
dúvida e configuração — exatamente onde uma regex sobre palavras-chave
é estruturalmente cega. Este parágrafo é a previsão que o ouro da seção
4 confirmou com força.
3.3 Urgência: o problema é a régua, não o modelo
Em urgência, a votação saiu quase em três vias (prata 42%, v3 45%,
backbone 42%) e zero "nenhum": os três candidatos costumam ser
defensáveis porque a urgência-prata é derivada de regex sobre palavras
("urgente", "erro", "parou"), sem noção de escopo. O cliente que escreve
"é urgente" para uma dúvida de configuração recebe alta da prata e
moderada do juiz; a plataforma "sem carregamento e sem gerar tickets"
descrita sem ênfase recebe baixa da prata e alta do juiz. Urgência
era, claramente, a pergunta que mais precisava de uma régua nova.
4. O ouro de 1.000 chamados
4.1 Desenho da amostra
O ouro foi desenhado para medir onde dói. Dos 1.731 casos do gold de prata, selecionamos 1.000 (999 válidos ao final) em três estratos:
- T1 — erros confiantes do v3 em categoria (v3≠prata com confiança ≥ 0,70): os pontos em que o modelo "jura" que a prata erra;
- T2 — qualquer desacordo (categoria, decisão ou urgência, incluindo v3×backbone);
- T3 — concordância plena, aleatórios estratificados pela categoria-prata, para não esquecer o universo dos casos fáceis.
Os textos foram para uma planilha cega (sem os rótulos da prata, sem as respostas dos modelos), acompanhada de um guia de anotação com definições e exemplos por categoria.
4.2 Quem rotulou — e a honestidade sobre isso
A rotulagem foi feita por leitura semântica assistida por IA: três agentes leram os textos individualmente, cada lote passou por revisão do próprio agente e por revisão cruzada de outro agente (202 casos revistos na íntegra, 16 com rótulo alterado nessa etapa), com adjudicação final de ambiguidades por um coordenador. Sem regex, sem consulta à aba de referência da planilha. Revisão humana por amostragem sobre o resultado final.
Eu chamo isso de ouro de leitura, não de "gold humano puro" — e a distinção importa. 73 casos ficaram marcados como baixa confiança do anotador, pendentes de confirmação humana. É um ouro de qualidade muito acima da prata, com um processo de revisão documentado, mas não é um comitê de especialistas humanos. O preço dessa escolha aparece na seção 6, sob a forma de um risco de circularidade que precisa ser declarado.
(Anotação operacional: 7 chamados continham credenciais explícitas — chaves de API, tokens — que foram mascaradas antes de qualquer modelo ver os textos. Dez ocorrências. Se você opera dados de atendimento real, espere encontrar segredos vazados pelos próprios clientes nos textos.)
4.3 O susto: um bug de linhagem quase contaminou o ouro
No meio do processo, descobri que o sampler que gerou a planilha tinha
lido o gold v1 — aquele, do capítulo da urgência degenerada — em vez
do gold v3 corrigido. Por sorte, os campos que a planilha usa (o texto
do chamado) são os mesmos nos dois; o estrago seria nos estratos de
amostragem. A correção foi apontar o sampler para o arquivo certo e
regenerar. Fica o registro porque é o terceiro bug de dados do
projeto que só foi pego porque alguém olhou o arquivo, não o nome do
arquivo: depois do <mask> e da urgência constante, o critério de
verificação de linhagem (hash do arquivo + contagem de linhas + spot
check de três casos) virou passo obrigatório de todo pipeline deste
projeto.
4.4 O que o ouro revelou
A concordância da prata com o ouro, nos 997 casos válidos:
| pergunta | concordância prata×ouro |
|---|---|
| categoria | 0,327 |
| decisão | 0,566 |
| urgência | 0,345 |
Uma em cada três etiquetas de categoria da prata não sobreviveu à leitura. As confusões mais frequentes (prata → ouro) são exatamente as fronteiras previstas pelos "nenhum" da adjudicação:
| confusão prata → ouro | n |
|---|---|
| canal_msg → bug_produto | 78 |
| canal_msg → conta_config | 69 |
| canal_msg → duvida_produto | 54 |
| incidente → bug_produto | 44 |
| outro → duvida_produto | 39 |
| canal_msg → integracao | 29 |
| canal_msg → plano_creditos | 27 |
A distribuição de categorias mudou de figura. Na prata, canal_msg
respondia por cerca de 49% dos casos do gold; no ouro (núcleo),
canal_msg cai para 19,6%, incidente despenca para 0,6% (6
casos em 999!), e as três categorias que a prata mal conhecia —
bug_produto (19,4%), duvida_produto (16,3%), conta_config (16,4%)
— passam a dominar. A prata não errava aleatoriamente: ela
super-etiquetava sistematicamente as duas classes do seu vocabulário
e sub-etiquetava tudo o que exigia leitura.
Urgência, a suspeita da Parte 2, confirmou-se: o ouro distribui
498 baixa / 365 moderada / 112 alta / 24 crítica no núcleo — enquanto a
prata inflava alta (a confusão alta → moderada sozinha responde por
228 casos; alta → baixa, mais 125). E decisão, a pergunta mais
"estável", mostrou um deslocamento conceitual importante: a prata dizia
executar_acao onde o ouro diz pedir_mais_info (136 casos) ou
escalar (123) — a regex via uma ação mencionada e concluía que ela
devia ser executada; a leitura percebia que o caso não estava pronto
para agir.
E onde fica o v3 nessa régua nova? Contra o ouro, a acurácia dele cai para 0,317 em categoria (vs 0,603 contra a prata), 0,569 em decisão e 0,330 em urgência. A estimativa da adjudicação (≈0,71) não se confirmou — porque adjudicação e ouro discordam entre si nas fronteiras finas: dois juízes, dois desenhos, duas definições implícitas de fronteira. A lição não é que uma das duas medidas "mente"; é que abaixo de certa granularidade, a fronteira entre bug_produto, duvida_produto e conta_config é uma decisão de taxonomia, não um fato da natureza — e quem define a taxonomia é o guia de anotação mais a consistência do anotador. O v3 aprendeu a taxonomia da prata; o ouro carrega a taxonomia do guia. O próximo modelo precisava aprender a taxonomia certa.
5. v4: o resultado negativo (class weighting não conserta rótulo)
5.1 A hipótese, o experimento, o veredito
Antes do ouro ficar pronto, a hipótese na mesa era: as categorias órfãs
do v3 (macro-F1 de 0,267, com conta_config em 0,133 e
duvida_produto em 0,048) sofriam de desbalanceamento — canal_msg
tinha ~49% do train. A resposta padrão de manual é class weighting.
Treinamos o v4 com pesos sqrt(1/freq) limitados a um teto de 5×, mais
label smoothing 0,1, tudo o mais igual ao v3.
Resultado na mesma régua (gold prata, split idêntico, temperaturas recalibradas no calib):
| métrica | v4 | v3 |
|---|---|---|
| acurácia geral | 0,660 | 0,650 |
| acurácia categoria | 0,585 | 0,603 |
| macro-F1 categoria (a métrica-alvo!) | 0,222 | 0,267 |
| F1 bug_produto | 0,111 | 0,289 |
| F1 conta_config | 0,000 | 0,133 |
| F1 pagamento | 0,200 | 0,519 |
A acurácia geral "subiu" um ponto — e a métrica que o experimento existia
para melhorar piorou, com as classes-minoria que o peso deveria
proteger sendo destruídas (conta_config zerou). A explicação ficou
óbvia depois que o ouro saiu: peso de classe amplifica o rótulo que
existe, não o rótulo certo. Dar 5× de peso a exemplos de
conta_config cujos rótulos estavam errados em grande proporção é pagar
5× mais atenção ao ruído. Class weighting é uma ferramenta de
frequência; o problema era de veracidade.
5.2 O interlúdio da loss 666
O v4 ainda rendeu o bug mais exótico do projeto. O log do primeiro
treino mostrava a loss abrir em ~666 e descer devagar — três ordens de
grandeza acima do esperado para uma cross-entropy de 17 classes. A causa:
o label_smoothing do PyTorch espalha a massa de probabilidade
uniformemente por todos os logits da camada — e a cabeça do decisor
tem espaço para 17 opções, mas cada exemplo só apresenta as opções
válidas da sua pergunta, com os slots de padding mascarados a −1e4.
Espalhar 10% de massa por slots que valem −1e4 produz um termo de loss
gigante (e gradientes absurdos apontando para opções inexistentes). A
correção foi reescrever o smoothing manualmente, restrito às opções
válidas de cada exemplo — e a loss passou a abrir em ~1,3. Fica a
vacina: smoothing e máscara de padding não se combinam de graça; se a
sua loss abre num valor que parece uma piada numerológica, provavelmente
é um bug, não uma coincidência.
6. v5: corrigir a causa raiz — re-rotular o train inteiro
Se o problema era a taxonomia dos rótulos de treino, a solução era trocar os rótulos de treino. Com o ouro provando que leitura semântica em lote era viável, o passo seguinte foi escalar a mesma ideia para o train completo.
6.1 O juiz e o protocolo
Juiz: um modelo de linguagem grande de raciocínio, servido em endpoint dedicado (sem custo de GPU local — as duas placas ficaram livres para o treino). Protocolo desenhado para minimizar contaminação:
- uma chamada por caso, com o texto integral do chamado;
- o juiz recebe o guia de anotação e few-shots no system prompt;
- o juiz não vê o rótulo da prata — cego à régua antiga, para não herdar o viés dela;
- saída estruturada com o rótulo das três perguntas + confiança do juiz;
- 16 workers paralelos.
Resultado da operação: 3.982 casos re-rotulados, zero falhas, ~18 minutos (3,7 casos/segundo). Mais 500 casos aleatórios do universo (sem estratificação por desacordo) re-rotulados pelo mesmo juiz, para compor o ouro de avaliação com um subset não-enviesado. Dedup final contra o conjunto de teste: 2 casos vazados removidos (6 linhas), train final de 11.946 linhas / 3.982 casos, zero sobreposição com o teste.
6.2 O train mudou de cara
A re-rotulagem redistribuiu o train na mesma direção do ouro:
| categoria | train v3 (prata) | train v5 (juiz forte) |
|---|---|---|
| incidente | classe gigante | 935 |
| bug_produto | sub-representada | 605 |
| duvida_produto | quase órfã | 590 |
| conta_config | quase órfã | 573 |
| canal_msg | ~metade do train | 475 |
| outro | — | 348 |
| integracao | — | 176 |
E urgência, que na prata era uma classe quase única com variação por palavra-gatilho, virou uma distribuição de verdade no train: 1.256 baixa / 1.330 moderada / 736 alta / 660 crítica.
6.3 Config do v5
Com o v4 provando que peso de classe é veneno sobre rótulo ruidoso e o log do v4 mostrando platô de loss já na transição época 2→3, a config do v5 é o v3 com duas mudanças conservadoras: 2 épocas (em vez de 3) e smoothing 0,05 (a versão corrigida, restrita às opções válidas). Sem pesos de classe. Batch 24, padding dinâmico, mesmo encoder mmBERT, mesmo split por caso, mesma seed. O v5 é um experimento de uma variável: só mudaram os rótulos do train.
7. Resultados do v5 contra o ouro
A avaliação definitiva rodou ao fim do treino: v5 × v3 × backbone zero-shot contra o ouro de 1.499 casos (999 núcleo + 500 aleatórios), protocolo idêntico ao do benchmark — split por caso seed 42, temperature scaling ajustado só no calib, métricas no teste (753 casos), limiar 0,8. O critério de promoção, fixado antes dos números, era a acurácia geral no subset núcleo.
Tabela principal (teste, 753 casos)
| métrica | decisor-v5 | decisor-v3 | backbone zero-shot |
|---|---|---|---|
| acurácia categoria | 0,530 | 0,303 | 0,100 |
| acurácia decisão | 0,620 | 0,622 | 0,191 |
| acurácia urgência | 0,639 | 0,324 | 0,311 |
| acurácia geral | 0,596 | 0,416 | 0,201 |
| macro-F1 categoria | 0,386 | 0,188 | 0,089 |
| ECE categoria (pós-temp) | 0,046 | 0,059 | 0,086 |
| ECE decisão (pós-temp) | 0,052 | 0,096 | 0,092 |
| ECE urgência (pós-temp) | 0,044 | 0,125 | 0,037 |
| roteamento: % linhas no automático | 10,8% | 0,0% | 0,4% |
| roteamento: acurácia no automático | 0,848 | — (vazio) | 0,300 |
Headline: o subset aleatório (amostragem não-enviesada do universo; o desconto de circularidade da seção 7.1 aplica-se a ele, nunca ao núcleo)
| pergunta | v5 | v3 | backbone |
|---|---|---|---|
| categoria | 0,555 | 0,305 | 0,113 |
| decisão | 0,703 | 0,684 | 0,223 |
| urgência | 0,606 | 0,348 | 0,328 |
| todas | 0,621 | 0,445 | 0,221 |
Núcleo duro (999 adversariais, juiz independente — o critério)
| pergunta | v5 | v3 | backbone |
|---|---|---|---|
| categoria | 0,517 | 0,302 | 0,093 |
| decisão | 0,578 | 0,590 | 0,175 |
| urgência | 0,656 | 0,312 | 0,302 |
| todas | 0,584 | 0,401 | 0,190 |
F1 por categoria (teste) — onde o redesenho do train apareceu
| categoria | n | v5 | v3 |
|---|---|---|---|
| canal_msg | 138 | 0,659 | 0,450 |
| outro | 69 | 0,634 | 0,495 |
| conta_config | 122 | 0,578 | 0,048 |
| plano_creditos | 46 | 0,537 | 0,254 |
| integracao | 48 | 0,524 | 0,366 |
| duvida_produto | 131 | 0,471 | 0,058 |
| bug_produto | 146 | 0,459 | 0,142 |
| pagamento | 15 | 0,444 | 0,286 |
| incidente | 22 | 0,325 | 0,161 |
| duvida_comercial | 12 | 0,000 | 0,000 |
Leitura honesta:
- A causa raiz era mesmo a taxonomia. +18,2 pontos no núcleo, +17,6
no aleatório, com a maior subida exatamente nas três categorias que a
prata sub-etiquetava (
conta_config0,048→0,578,duvida_produto0,058→0,471,bug_produto0,142→0,459). O único ponto em que o v5 perde para o v3 é decisão no núcleo (0,578 vs 0,590) — empate técnico dentro do ruído, mais que coberto pela urgência (+34 pontos no mesmo subset). Na tabela principal, decisão é literalmente um empate (0,620 vs 0,622): a pergunta que a prata menos distorcia é a que mais o v3 já acertava, e a re-rotulagem não tinha muito o que consertar lá. - Onde o v5 não ganhou: cobertura. 10,8% das linhas no automático
(a 84,8% de acurácia) contra os 30,9% que o v3 alcançava na régua de
prata. Parte é régua mais dura com todo mundo — o v3, contra o ouro,
não coloca uma única linha acima do limiar 0,8: a confiança dele foi
aprendida sobre a taxonomia da prata e não sobreviveu à régua nova.
Parte é o limiar conservador da Parte 2, que segue valendo até haver
motivo para mexer. E
duvida_comercialcontinua zerada nos dois modelos (n=12, amostra pequena demais para qualquer conclusão). - A calibração acompanhou a acurácia. ECE pós-temperatura do v5 abaixo de 0,06 nas três perguntas (a do v3 chega a 0,125 em urgência), com temperaturas estáveis (T entre 1,05 e 1,70). O único ECE melhor do backbone (urgência, 0,037) vem acompanhado de 31% de acurácia — estar calibrado no errado não é calibração útil.
Pelo critério fixado antes dos números — acurácia geral no subset núcleo — o v5 venceu, e a troca da API de produção foi feita na mesma execução que gerou esta tabela.
7.1 A ressalva de circularidade (escrita antes dos números, de propósito)
Registro aqui, antes de ver os resultados, a limitação que esta avaliação carrega, para que ela não seja "descoberta" depois caso os números venham bonitos: o subset aleatório do ouro foi rotulado pelo mesmo juiz que re-rotulou o train do v5. Uma acurácia alta do v5 nesse subset mede, em parte, concordância com o juiz — o que é exatamente o que o treino otimizou. O subset núcleo (999 casos) foi rotulado por um pipeline de leitura independente (três agentes + revisão cruzada), o que o torna a medida menos contaminada do par — mas ele é enviesado para casos difíceis (estratos T1/T2) por desenho. A leitura honesta será: o núcleo mede qualidade em regime duro com juiz independente; o aleatório mede o universo real, com o desconto da circularidade. Se o v5 vencer nos dois, a evidência é forte. Se vencer só no aleatório, o veredito fica em aberto e o próximo passo é a confirmação humana dos 73 casos de baixa confiança mais uma rodada de adjudicação cega v3×v5.
Desfecho real: o v5 venceu nos dois subsets — a previsão a priori se confirmou, e esta ressalva permanece como desconto honesto sobre o aleatório, não como desculpa para ignorá-lo.
7.2 O v5 em carne e osso
Tabelas dizem quanto; casos dizem o quê. Rodei os dois modelos sobre
os 1.499 casos do ouro e separei os desacordos: v3 e v5 divergem em
61% dos casos — e, nesses desacordos, o v5 acerta 448 contra 107
do v3 (razão 4,2:1), com 360 em que ambos erram. Quando os dois
concordam, acertam apenas 59%: a discordância concentra exatamente os
casos difíceis. Cinco casos reais (textos anonimizados; o rótulo
canal_msg segue a convenção da série):
Caso 1 — o vício da prata, desaprendido. Cliente pede backup dos
dados da conta para migração ("Solicitar Backup / Para migração de
dados / Regularmente"). Ouro: conta_config. O v3 diz canal_msg com
confiança 0,95 — qualquer menção a número ou exportação de
conversas, ele jogava na classe que a prata super-etiquetava, com certeza
absoluta. O v5 diz conta_config com 0,88, e ainda acerta a urgência
(baixa, onde o v3 dizia alta). Este padrão se repete em dezenas de
casos: o v5 não decorou novas palavras — desaprendeu um reflexo.
Caso 2 — a fronteira que a regex não via. Cliente pergunta por que a
atribuição de uma mensagem a um vendedor aparece no histórico com outro
nome. Ouro: duvida_produto, urgência moderada. O v3 diz incidente
(0,56) — "apareceu algo errado" virava incidente. O v5 diz
duvida_produto (0,75) e moderada — entendeu que é uma pergunta sobre
como o produto funciona, não uma falha.
Caso 3 — bug de verdade, enfim reconhecido. "Pesquisa em campo de
ticket de lista de subníveis não localiza as classificações" — um
relato de comportamento quebrado na v2 do helpdesk. Ouro:
bug_produto. O v3 diz canal_msg com 0,96 (!). O v5 diz
bug_produto com 0,73. O F1 de bug_produto ter saltado de 0,142 para
0,459 é feito de centenas de casos assim.
Caso 4 — onde o v5 perde (honestidade). Cliente pergunta da nova
política de cobrança da provedora do canal e do recurso de otimização de
bot para reduzir custos. Ouro: canal_msg. O v3 crava canal_msg
(0,98) ✅; o v5 diz conta_config (0,35) ❌. O pêndulo balançou: quem
antes super-etiquetava a classe do canal agora às vezes a sub-etiqueta.
Mas note a confiança: 0,35 está muito abaixo do limiar de 0,8 — o erro
do v5 vai para a fila humana, não vira decisão automática errada.
Perder com confiança baixa é o jeito certo de perder.
Caso 5 — a fronteira que resta (ambos erram). "Os clientes estão
ficando presos no bot, está dando erro de envio das mensagens, estou com
850 conversas no bot." Ouro: duvida_produto (o juiz leu como dúvida de
configuração do bot). v3: canal_msg (0,98); v5: bug_produto (0,56).
Razoável dos dois lados e errado nos dois — é exatamente a fronteira
bug_produto × duvida_produto × conta_config que a seção 4.4
identificou como decisão de taxonomia. Esses casos não se resolvem com
mais GPU; se resolvem com guia de anotação mais afiado e mais exemplos
rotulados exatamente nessa fronteira.
O mapa completo de 20 casos (14 vitórias do v5, 3 do v3, 3 empates no
erro) está em docs/comparativo_v3_v5.md, com textos, confianças e os
comentários do juiz do ouro.
8. O que separa isto de "um modelo que as pessoas queiram usar"
Inventário honesto do que resta, em ordem de alavanca:
- Cobertura no automático: 10,8% das linhas a 84,8% de acurácia (v5, régua nova) é um produto menor do que os 30,9% do v3 na régua de prata — e mais honesto. O caminho para 60–80% passa por mais dados de domínio nas categorias duras — agora, com rótulos de leitura, cada novo lote rotulado vale mais do que valia na era da prata.
- Ouro ampliado e com confirmação humana: 1.499 casos é uma régua; 5.000 é um ativo. E os 73 casos de baixa confiança precisam de olhos humanos.
- Serving: o decisor-v5 já responde em API local (as três perguntas, probabilidades calibradas, roteamento por limiar de confiança) — a "configuração, não um projeto" prometida acima foi exatamente o que aconteceu: temperaturas recalibradas no ouro, checkpoint trocado, smoke test, ~5 segundos de indisponibilidade. O v3 permanece no host intocado como rollback.
- Revisita ao RL? A Parte 2 encerrou o assunto com "inócuo não é útil". Com rótulos de leitura e uma régua confiável, a recompensa do RLCD deixaria de ser ruidosa — mas o baseline escalar (temperature scaling) continua capturando o ganho fácil. RL volta à mesa só quando houver evidência de que a fronteira restante é de calibração fina, não de rótulo.
9. Lições da Parte 3
- Meça a régua antes de medir o modelo. O benchmark contra o backbone zero-shot isolou o efeito do treino; a adjudicação cega mediu o erro da régua (63% nos pontos contestados); o ouro mediu o resto. Cada camada de medição mudou a conclusão anterior.
- Régua errada em duas direções. A prata não só inflava a nota do v3 (0,603 contra ela vs 0,317 contra o ouro) como também escondia acertos (a adjudicação estimava 0,71). Ruído de régua não "se cancela" — ele distorce o ranking dos modelos e o mapa de onde investir.
- Resultado negativo com mecanismo claro vale mais que positivo confuso. O v4 falhou por uma razão identificável — peso amplifica ruído de rótulo — e essa razão apontou diretamente para o v5.
- Conserte a causa raiz, não o sintoma. O sintoma era macro-F1 baixo; a causa era a taxonomia dos rótulos. Class weighting tratou o sintoma e piorou o quadro; re-rotular o train tratou a causa.
- Juiz cego à régua antiga. O re-rotulador não viu a prata de propósito — herdar o viés da régua anterior na régua nova teria invalidado o exercício inteiro.
- Declare a circularidade antes dos números. A seção 7.1 foi escrita antes da avaliação rodar. Limitação declarada a priori é método; declarada a posteriori é desculpa.
- Todo pipeline precisa de verificação de linhagem. Três bugs de
dados (
<mask>, urgência constante, sampler lendo o gold v1) foram pegos olhando o arquivo, não o nome do arquivo. Hash, contagem e spot check — sempre.
Na sequência
A seção 7 foi preenchida assim que o treino saiu: o v5 venceu o v3 no subset núcleo (0,584 vs 0,401 na acurácia geral — o critério fixado a priori) e no aleatório (0,621 vs 0,445), e a API de produção já roda o v5 — calibrado no ouro, com o v3 preservado no host como rollback e ~5 segundos de indisponibilidade no swap. A ressalva de circularidade do subset aleatório foi declarada antes dos números e segue valendo como desconto, não como veto. O próximo capítulo não é mais treino — é produto: subir a cobertura do automático além dos 10,8% atuais, confirmar os 73 casos de baixa confiança com olhos humanos, e medir latência e a experiência de quem usa.
Raphael Pizzo é Especialista em Machine Learning. Este projeto foi desenvolvido em infraestrutura própria (AMD ROCm), com dados anonimizados e aprovados para uso em pesquisa.