Files
decision-models-benchmark/reports/test
2026-10-07 20:53:56 -03:00
..

Teste final — 1.744 exemplos, configuração congelada

Sumário executivo

O teste final mediu os quatro candidatos sobre a partição de teste congelada, com a configuração, a calibração e os limiares fixados antes de qualquer acesso ao teste (tag congelamento-d1-v1). Cada medição foi repetida três vezes.

  • Qualidade: SemIf 87,2% (IC 95%: 85,0–89,4) e Rizzo Flow 85,4% (83,2–87,6) empatam estatisticamente: a diferença de 1,8 p.p. tem intervalo que inclui zero. Os dois superam GLiNER (57,0%) e Laya (56,8%) por cerca de 30 p.p., com alta significância.
  • Critério de qualidade (H1, macro F1 ≥ 0,80): atendido pelo SemIf (0,889) e pelo Rizzo Flow (0,877); não atendido por Laya (0,590) e GLiNER (0,580).
  • Critério de latência (H3, p95 ≤ 150 ms em GPU A10): atendido por Laya (23 ms) e GLiNER (32 ms); não atendido pelo SemIf (187 ms) nem pelo Rizzo Flow (181 ms).
  • Critério de risco (H2, cobertura ≥ 80% com ≤ 2% de rotas erradas com confiança alta): nenhum candidato atende. Com os limiares congelados, o SemIf decide sozinho 62% dos casos com 97,4% de acerto, e o Rizzo Flow 47% com 96,7%.
  • Custo: em GPU A10, cerca de US$ 0,07 por mil decisões para os modelos de 4B e US$ 0,012 para os encoders. Em CPU, o Laya custa US$ 0,013 por mil decisões.
  • Principal causa de erro grave: quando a intenção correta não está entre as opções elegíveis, os modelos escolhem a opção mais próxima em vez de sem_correspondencia. É a maior classe de rotas erradas com confiança alta e aponta uma mudança de arquitetura (ver Conclusão).
  • Reprodutibilidade: as predições são idênticas nas três repetições, e o desvio-padrão da latência p95 fica abaixo de 2 ms em GPU.

Resultados gerais

Candidato Acurácia (IC 95%) Macro F1 sem_correspondencia reconhecido Cobertura no limiar congelado Acurácia nos casos decididos Rotas erradas com confiança alta p50 / p95 GPU Vazão GPU Custo GPU por mil decisões
SemIf 87,2% (85,0–89,4) 0,889 76,7% 62,2% 97,4% 1,6% 121 / 187 ms 7,8/s US$ 0,071
Rizzo Flow 85,4% (83,2–87,6) 0,877 62,4% 46,8% 96,7% 1,5% 115 / 181 ms 7,9/s US$ 0,070
GLiNER 57,0% (52,6–61,5) 0,580 58,7% 12,8% 84,8% 1,9% 21 / 32 ms 46,0/s US$ 0,012
Laya 56,8% (52,9–60,5) 0,590 28,6% 10,3% 86,6% 1,4% 22 / 23 ms 45,9/s US$ 0,012

Acurácia por candidato, com IC 95%

Qualidade × latência em GPU

Cobertura × risco por limiar de confiança

Acurácia por número de opções

Latência por decisão: GPU × CPU

Critérios pré-registrados (Q5)

Candidato H1 · macro F1 ≥ 0,80 H2 · cobertura ≥ 80% com risco ≤ 2% H3 · p95 ≤ 150 ms em GPU
SemIf ✅ 0,889 ❌ 62,2% ❌ 187 ms
Rizzo Flow ✅ 0,877 ❌ 46,8% ❌ 181 ms
GLiNER ❌ 0,580 ❌ 12,8% ✅ 32 ms
Laya ❌ 0,590 ❌ 10,3% ✅ 23 ms

(O baseline LLM previsto na Q9 não foi executado neste ciclo; por isso H1 usa o critério absoluto de macro F1.)

Comparações pareadas contra o SemIf (GPU)

Candidato Diferença de acurácia (IC 95%, bootstrap por lote) Acertos só do SemIf / só do candidato McNemar (p)
Rizzo Flow +1,8 p.p. (−0,5 a +4,2) 127 / 96 0,044
GLiNER +30,2 p.p. (+26,1 a +34,3) 603 / 76 < 10⁻¹⁰⁰
Laya +30,5 p.p. (+26,5 a +34,6) 605 / 74 < 10⁻¹⁰⁰

O McNemar trata cada exemplo como independente. Com o bootstrap por lote de geração, que respeita o agrupamento, a diferença entre SemIf e Rizzo Flow não é robusta.

Classes de erro (GPU, tarefa 73)

Classe SemIf Rizzo Flow GLiNER Laya
Intenção correta fora das opções (escolheu a mais próxima) 84 106 88 128
Par difícil da taxonomia 62 69 100 182
Pedido válido marcado como sem_correspondencia 49 10 329 61
Ambiguidade (anotação dividida ou com várias intenções) 17 18 46 71
Pedido fora de escopo aceito como intenção 4 35 66 140
Linguagem (erros de digitação, regionalismo, informalidade) 3 8 56 82
Desempenho do modelo (sem outra causa identificada) 4 8 65 90
Total de erros 223 254 750 754

Erros de alto impacto (tarefa 72). São as rotas erradas acima do limiar de confiança: 28 no SemIf e 27 no Rizzo Flow. A inspeção manual mostra três padrões:

  1. Intenção fora das opções (12 no SemIf, 20 no Rizzo). O pedido é claro, mas a intenção certa não estava entre as elegíveis, e o modelo escolhe a vizinha com alta confiança. Por exemplo, "Quero fazer portabilidade do meu número para outra operadora", com portabilidade fora das opções, vira troca_numero; "tem algum pacote de roaming?" vira roaming_duvida.
  2. Pares difíceis da taxonomia (8 no SemIf). Exemplos: cobrança de roaming lida como contestação de fatura; cancelar uma assinatura lido como contestar a cobrança.
  3. Rótulos discutíveis. Alguns casos têm duas leituras razoáveis, como "Estou sem internet e preciso saber se ainda tenho saldo" (internet_consumo ou recarga_saldo). Isso reflete o limite de uma referência anotada por modelos.

Listas completas em errors-high-impact-<candidato>-<dispositivo>.jsonl; matrizes de confusão em confusion-<candidato>-<dispositivo>.csv.

Resultados detalhados

Por execução (três repetições por candidato e dispositivo; probabilidades brutas; latências sem os 5 exemplos de aquecimento)

Candidato Disp. Precisão n Acurácia Macro F1 ECE (bruto) p50 ms p95 ms p99 ms Carga s RAM pico MiB GPU pico MiB Erros Truncados
gliner cpu r1 float32 1744 57.0% 57.9% 0.099 265.1 468.2 520.2 19.7 3272 — 0 0
gliner cpu r2 float32 1744 57.0% 57.9% 0.099 272.9 490.7 550.1 19.7 3257 — 0 0
gliner cpu r3 float32 1744 57.0% 57.9% 0.099 264.0 485.0 541.3 20.2 3276 — 0 0
gliner cuda r1 float32 1744 57.0% 57.9% 0.099 20.6 31.6 33.8 21.6 3255 1807 0 0
gliner cuda r2 float32 1744 57.0% 57.9% 0.099 20.6 31.7 33.7 21.6 3277 1807 0 0
gliner cuda r3 float32 1744 57.0% 57.9% 0.099 21.2 31.7 34.0 21.8 3254 1807 0 0
laya cpu r1 float32 1744 56.8% 59.0% 0.269 156.9 190.4 240.6 9.3 2682 — 0 0
laya cpu r2 float32 1744 56.8% 59.0% 0.269 158.7 198.9 261.8 8.3 2682 — 0 0
laya cpu r3 float32 1744 56.8% 59.0% 0.269 175.2 213.3 268.6 9.4 2689 — 0 0
laya cuda r1 float32 1744 56.8% 59.0% 0.271 21.5 22.9 25.0 9.4 2794 1811 0 0
laya cuda r2 float32 1744 56.8% 59.0% 0.271 21.9 23.4 24.5 10.8 2795 1811 0 0
laya cuda r3 float32 1744 56.8% 59.0% 0.271 21.7 23.3 25.8 9.3 2791 1811 0 0
rizzo_flow cuda r1 gguf-q8_0 1744 85.4% 87.7% 0.037 114.6 181.1 185.6 5.3 4532 5115 0 0
rizzo_flow cuda r2 gguf-q8_0 1744 85.4% 87.7% 0.037 114.7 181.1 185.3 5.8 4535 5115 0 0
rizzo_flow cuda r3 gguf-q8_0 1744 85.4% 87.7% 0.037 114.7 180.3 185.1 5.3 4533 5115 0 0
semif cuda r1 bfloat16 1744 87.2% 88.9% 0.042 119.5 185.1 187.9 7.1 9029 8513 0 0
semif cuda r2 bfloat16 1744 87.2% 88.9% 0.042 121.0 188.0 190.7 7.2 9029 8513 0 0
semif cuda r3 bfloat16 1744 87.2% 88.9% 0.042 121.6 188.2 190.8 7.7 9028 8513 0 0

Desempenho consolidado (média ± desvio-padrão das três repetições)

Candidato Disp. p50 ms p95 ms Vazão (decisões/s) Custo por mil decisões Carga s RAM pico GPU pico Pesos Ambiente
SemIf GPU 120,7 ± 1,1 187,1 ± 1,8 7,8 US$ 0,071 7,3 8,8 GiB 8,3 GiB 8,7 GiB 4,0 GiB
Rizzo Flow GPU 114,7 ± 0,1 180,8 ± 0,4 7,9 US$ 0,070 5,4 4,4 GiB 5,0 GiB 4,1 GiB 0,6 GiB
GLiNER GPU 20,8 ± 0,4 31,7 ± 0,1 46,0 US$ 0,012 21,6 3,2 GiB 1,8 GiB 1,1 GiB 4,0 GiB
GLiNER CPU 267,3 ± 4,9 481,3 ± 11,7 3,6 US$ 0,023 19,9 3,2 GiB — 1,1 GiB 4,0 GiB
Laya GPU 21,7 ± 0,2 23,2 ± 0,3 45,9 US$ 0,012 9,8 2,7 GiB 1,8 GiB 0,6 GiB 4,0 GiB
Laya CPU 163,6 ± 10,1 200,9 ± 11,6 6,5 US$ 0,013 9,0 2,6 GiB — 0,6 GiB 4,0 GiB

Vazão por instância com lote 1 (1 / latência média). Custo = preço público por hora do shape × tempo médio por decisão (config/pricing.yaml: A10 a US$ 2,00/h; E4 com 8 OCPU e 64 GB a US$ 0,296/h). O ambiente inclui PyTorch com CUDA, exceto no Rizzo Flow, que usa llama.cpp.

Acurácia por corte (GPU)

Corte SemIf Rizzo Flow GLiNER Laya
4 opções (451) 88,7% 90,2% 60,3% 69,4%
8 opções (431) 89,1% 88,9% 61,0% 57,8%
12 opções (422) 85,8% 83,4% 55,2% 51,4%
16 opções (440) 85,2% 79,1% 51,4% 48,0%
Pedido dentro do escopo (1.508) 85,6% 85,5% 54,8% 59,4%
Pedido fora de escopo (236) 97,5% 84,8% 71,2% 39,8%
Intenção correta fora das opções (142) 40,9% 24,6% 38,0% 9,2%
Curto e neutro 90,4% 89,2% 56,2% 60,2%
Informal, com abreviações 86,6% 85,2% 60,7% 59,3%
Erros de digitação 88,6% 84,7% 49,6% 57,0%
Regionalismo 93,6% 87,6% 62,0% 53,6%
Emocional 85,8% 85,4% 60,8% 58,6%
Longo, com contexto 86,9% 86,9% 60,2% 55,4%
Indireto ou com várias intenções 78,7% 78,7% 48,1% 53,1%

Todos os cortes, por candidato e dispositivo, estão em analysis.json.

Metodologia

Dados. A partição de teste do conjunto congelado d1-v1 inteira, sem amostragem: 1.744 exemplos de 146 lotes de geração, com os 43 rótulos. São 236 pedidos fora de escopo, 142 exemplos com a intenção correta fora das opções e opções por pergunta distribuídas entre 4 (451), 8 (431), 12 (422) e 16 (440). A partição é disjunta da de desenvolvimento e da de calibração por lote de geração, e ficou congelada (SHA-256) antes de qualquer ajuste. O tamanho atende à análise de poder pré-registrada (≥ 1.300 decisões, Q12).

Configuração congelada. Contrato jev-compat-v1, adaptadores, partições, temperatura e limiar de cada candidato ficaram fixos em config/frozen.json antes da abertura do teste (tarefa 62). O executor só abre a partição de teste se todos os hashes conferirem.

Execução. Lote 1 (o lote de produção, Q6), precisão nativa de cada candidato e inferência isolada de fontes externas. Três repetições independentes por candidato e dispositivo, cada uma num job novo. GPU VM.GPU.A10.1 (sa-saopaulo-1) para os quatro; CPU VM.Standard.E4.Flex com 8 OCPU e 64 GB (us-chicago-1) para Laya e GLiNER, os viáveis em CPU.

Métricas (analysis/report.py, tarefas 67–74):

  • Qualidade: acurácia, macro F1, precisão e revocação macro, e matriz de confusão, calculadas na repetição 1. As três repetições têm predições idênticas.
  • Incerteza: IC 95% por bootstrap agrupado por lote de geração (2.000 reamostragens). Comparações pareadas com bootstrap da diferença e McNemar exato.
  • Calibração e abstenção: probabilidades calibradas com a temperatura congelada; cobertura e rotas erradas com confiança alta medidas no limiar congelado.
  • Desempenho: latência média ± desvio entre as três repetições, vazão por instância, pico de RAM e de GPU, armazenamento de pesos e ambiente, e custo por mil decisões a preço público.
  • Erros: classificação automática por regras (par difícil da taxonomia, intenção fora das opções, ambiguidade de anotação, perfil de linguagem etc.) e inspeção manual das rotas erradas acima do limiar.

Conclusão

  1. Qualidade: os modelos de 4B vencem com folga. SemIf e Rizzo Flow acertam cerca de 86% das decisões e são os únicos que atendem ao critério de qualidade; entre eles, a diferença não é estatisticamente robusta. Os encoders compactos ficam cerca de 30 p.p. abaixo.
  2. Latência: os encoders vencem. Laya e GLiNER respondem em cerca de 20 ms em GPU e são viáveis em CPU. Os modelos de 4B passam do limite de p95 de 150 ms na A10 (181 a 187 ms).
  3. Nenhum candidato cumpre os três critérios ao mesmo tempo, e nenhum atinge a meta de abstenção (80% de cobertura com risco ≤ 2%).
  4. Recomendação para o orquestrador:
    • Modelo de decisão: SemIf como primeira opção, pela maior acurácia, pelo melhor reconhecimento de pedidos sem correspondência (77%) e pela maior cobertura com risco controlado (62%). Rizzo Flow é a alternativa equivalente em qualidade, com metade da memória de GPU (5 GiB contra 8,3 GiB) e menos falsas abstenções.
    • Latência: para cumprir o p95 de 150 ms, avaliar uma GPU mais rápida que a A10 ou otimizações de inferência (quantização, compilação, cache do prefixo da pergunta). Na A10, a mediana já fica em cerca de 120 ms.
    • Elegibilidade depois da classificação: classificar contra o catálogo completo de intenções e aplicar a elegibilidade depois, de forma determinística, em vez de oferecer ao modelo só as opções elegíveis. Isso remove a maior classe de erros de alto impacto (intenção fora das opções).
    • Abstenção: usar o limiar calibrado para encaminhar à desambiguação os casos de baixa confiança (cerca de 38% com o SemIf), com 97% de acerto nos casos decididos.
    • Encoders compactos: Laya e GLiNER não servem como roteador principal neste domínio. Podem atuar como filtro rápido de primeira camada, se combinados com um modelo de 4B nos casos incertos.
  5. Limitações: os dados são sintéticos e os rótulos vêm do consenso de três modelos generativos; não houve baseline LLM neste ciclo; a latência foi medida em uma única GPU (A10) e com lote 1; o Rizzo Flow roda em Q8_0 enquanto os demais rodam na precisão nativa.