mirror of
https://github.com/mcloh/decision-models-benchmark.git
synced 2026-11-05 22:04:12 +00:00
Encerramento do ciclo d1-v1 (tarefas 75–78): README executivo, arquivamento e desligamento
- README: apresentação, resultados e recomendação, método e detalhes. - Arquivo em dmb-logs-imutaveis com retenção de 365 dias. - Notebook desativado; sem jobs, NAT ou endpoints ativos. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
169
README.md
169
README.md
@@ -1,74 +1,145 @@
|
||||
# Benchmark de modelos de decisão em PT-BR para roteamento em orquestradores multiagente
|
||||
|
||||
Benchmark reprodutível de modelos de decisão *open source*, do tipo "System 1" e semelhantes ao JEV (`POST /v1/systemone`), aplicados ao **roteamento e à orquestração de enunciados de usuário** (*user utterances*) num sistema multiagente com **A2A Gateway** e **MCP Gateway**.
|
||||
## Apresentação
|
||||
|
||||
O modelo de decisão é avaliado como um componente do **Agente Orquestrador**. A cada turno, ele toma decisões rápidas e estruturadas: identifica a intenção, escolhe o agente de destino, decide entre continuar, alternar ou retomar uma sessão e decide quando é preciso desambiguar. Essas decisões substituem ou complementam chamadas a LLMs generalistas.
|
||||
Num sistema multiagente, o **orquestrador** decide a cada turno para onde vai a mensagem do usuário: qual intenção ela expressa, qual agente deve atendê-la e quando é melhor perguntar antes de agir. Essas decisões ficam no caminho síncrono de toda conversa e precisam ser rápidas, baratas e confiáveis.
|
||||
|
||||
## Objetivo
|
||||
Este benchmark avalia se **modelos de decisão *open source***, do tipo "System 1", podem cumprir esse papel em português do Brasil, no lugar de chamadas a LLMs generalistas. São modelos que respondem a uma pergunta com opções definidas em tempo de execução e devolvem uma distribuição de probabilidades, sem gerar texto, no padrão do contrato JEV `POST /v1/systemone`.
|
||||
|
||||
Comparar os candidatos em duas dimensões, nas mesmas condições:
|
||||
**Candidatos**
|
||||
|
||||
- **Acurácia e calibração** das decisões de roteamento em PT-BR, incluindo casos ambíguos, adversariais e com várias intenções.
|
||||
- **Desempenho operacional**: latência por turno (p50/p95/p99), vazão, memória, tempo de carga e custo por mil decisões, em CPU e GPU na OCI.
|
||||
| Candidato | Modelo | Tipo |
|
||||
|---|---|---|
|
||||
| **SemIf** | `SemIf-OpenJev` + `Qwen/Qwen3.5-4B` (modo `direct`) | LLM de 4B, logits das opções |
|
||||
| **Rizzo Flow** | `rizzoaiacademy/rizzo-flow` (Spark-X2.5 4B + LoRA, GGUF Q8_0) | LLM de 4B, logits das opções |
|
||||
| **Laya** | `convaiinnovations/laya-multilingual` | Encoder de 322M com cabeça de decisão |
|
||||
| **GLiNER** | `fastino/GLiNER2.5-multi-Decide` | Encoder de 287M, classificação com rótulos descritos |
|
||||
|
||||
O resultado é um relatório técnico com uma recomendação. Todos os resultados podem ser reproduzidos a partir dos artefatos versionados.
|
||||
**Escopo deste ciclo:** classificação de intenções no atendimento de telefonia móvel (42 intenções em 13 domínios, mais "sem correspondência"), com 4.054 enunciados sintéticos anotados por três modelos generativos. As medições rodaram na OCI, em CPU e em GPU A10, com a configuração congelada antes do teste final.
|
||||
|
||||
## Participantes
|
||||
## Resultados
|
||||
|
||||
| Candidato | Artefato |
|
||||
|-------------|----------------------------------------------|
|
||||
| Laya | `convaiinnovations/laya-multilingual` |
|
||||
| SemIf | `SemIf-OpenJev` com `Qwen/Qwen3.5-4B` (modo `direct`) |
|
||||
| GLiNER | `fastino/GLiNER2.5-multi-Decide` (`classify_text`) |
|
||||
| Rizzo Flow | `rizzoaiacademy/rizzo-flow` (4B) |
|
||||
Teste final com 1.744 exemplos, configuração congelada e três repetições. Detalhes em [reports/test](reports/test/README.md).
|
||||
|
||||
Cada candidato é exposto por um adaptador local com o mesmo contrato JEV (`POST /v1/systemone`). Assim, o *harness* não sabe qual modelo está respondendo.
|
||||
| Candidato | Acurácia (IC 95%) | Macro F1 | Decide sozinho com risco ≤ 2% | p95 em GPU A10 | Custo por mil decisões |
|
||||
|---|---|---|---|---|---|
|
||||
| **SemIf** | **87,2%** (85,0–89,4) | 0,889 | 62% (97% de acerto) | 187 ms | US$ 0,071 |
|
||||
| **Rizzo Flow** | **85,4%** (83,2–87,6) | 0,877 | 47% (97% de acerto) | 181 ms | US$ 0,070 |
|
||||
| GLiNER | 57,0% (52,6–61,5) | 0,580 | 13% | 32 ms | US$ 0,012 |
|
||||
| Laya | 56,8% (52,9–60,5) | 0,590 | 10% | 23 ms | US$ 0,012 |
|
||||
|
||||
## Andamento
|
||||

|
||||
|
||||
O andamento por fase fica no topo de [docs/03-plano-de-tarefas.md](docs/03-plano-de-tarefas.md), regenerado com `python tools/plan_progress.py` a cada atualização do plano.
|
||||
- **Qualidade:** os modelos de 4B (SemIf e Rizzo Flow) acertam cerca de 86% e empatam estatisticamente entre si. Os encoders compactos ficam cerca de 30 p.p. abaixo.
|
||||
- **Latência:** os encoders respondem em cerca de 20 ms e funcionam até em CPU. Os modelos de 4B ficam em cerca de 120 ms de mediana, mas passam do limite pré-registrado de p95 de 150 ms na A10.
|
||||
- **Abstenção:** com probabilidades calibradas, o SemIf decide sozinho 62% dos casos com 97% de acerto e encaminha o resto para desambiguação. Nenhum candidato atinge a meta pré-registrada de 80% de cobertura com 2% de risco.
|
||||
- **Principal fonte 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 com alta confiança.
|
||||
|
||||
**Primeiro ciclo:** classificação de intenções (D1) no atendimento de telefonia móvel, com dados 100% sintéticos anotados por três modelos generativos. CPU em us-chicago-1 (sub-rede privada) e GPU A10 em sa-saopaulo-1.
|
||||
**Recomendação.** Usar o **SemIf** como modelo de decisão do orquestrador, com o **Rizzo Flow** como alternativa equivalente e mais leve em memória de GPU. Junto com isso:
|
||||
- classificar contra o **catálogo completo** de intenções e aplicar a elegibilidade **depois**, de forma determinística;
|
||||
- usar o **limiar calibrado** para pedir esclarecimento nos casos incertos;
|
||||
- buscar uma GPU mais rápida que a A10 ou otimizações de inferência para cumprir o p95 de 150 ms.
|
||||
|
||||
## Documentação
|
||||
Encoders compactos não servem como roteador principal neste domínio.
|
||||
|
||||
| Critério pré-registrado | SemIf | Rizzo Flow | GLiNER | Laya |
|
||||
|---|---|---|---|---|
|
||||
| H1 · macro F1 ≥ 0,80 | ✅ | ✅ | ❌ | ❌ |
|
||||
| H2 · cobertura ≥ 80% com risco ≤ 2% | ❌ | ❌ | ❌ | ❌ |
|
||||
| H3 · p95 ≤ 150 ms em GPU | ❌ | ❌ | ✅ | ✅ |
|
||||
|
||||
**Etapas e relatórios**
|
||||
|
||||
| Etapa | Conjunto | Destaque | Relatório |
|
||||
|---|---|---|---|
|
||||
| Piloto | 50 exemplos de dev | Execução validada em CPU e GPU; SemIf e Rizzo inviáveis em CPU | [reports/pilot](reports/pilot/README.md) |
|
||||
| Desenvolvimento | 1.183 exemplos | Dois grupos de qualidade; o Laya cai com mais opções | [reports/dev](reports/dev/README.md) |
|
||||
| Calibração | 1.127 exemplos | Temperatura e limiar por candidato; ECE do Laya de 0,33 para 0,08 | [reports/calibration](reports/calibration/README.md) |
|
||||
| Teste final | 1.744 exemplos × 3 repetições | Resultados acima, com IC, cortes, custos e análise de erros | [reports/test](reports/test/README.md) |
|
||||
|
||||
**Limitações.** Os dados são sintéticos e os rótulos de referência vêm do consenso de três modelos generativos, não de pessoas. Não houve baseline LLM neste ciclo. A latência foi medida numa única GPU (A10) e com lote 1. O Rizzo Flow roda em Q8_0, enquanto os demais rodam na precisão nativa.
|
||||
|
||||
## Método
|
||||
|
||||
1. **Contrato único.** Todos os candidatos ficam atrás do mesmo contrato `POST /v1/systemone` (`jev-compat-v1`), com adaptadores que preservam a ordem e a descrição das opções. Testes de conformidade e de sanidade garantem que trocar de candidato não muda a requisição nem a resposta.
|
||||
2. **Dados sintéticos controlados.** São 42 intenções e 5 categorias fora de escopo, com 7 perfis de escrita (curto, informal, com erros de digitação, regional, emocional, longo, indireto ou com várias intenções), escritos por dois modelos geradores. Os rótulos vêm de três anotadores generativos de outros fornecedores, em rodízio, com dois anotando de forma independente e o terceiro desempatando (kappa de 0,98 a 0,99). As opções de cada exemplo simulam um serviço de elegibilidade (4, 8, 12 ou 16 opções); em 10% dos exemplos, a intenção correta fica de fora.
|
||||
3. **Partições disjuntas por lote de geração:** desenvolvimento (1.183), calibração (1.127) e teste (1.744), congeladas com SHA-256.
|
||||
4. **Protocolo pré-registrado.** Critérios, limites e regras ficam em `config/benchmark.yaml` antes das medições: piloto → desenvolvimento → calibração (temperatura e limiar só na partição de calibração) → congelamento da configuração com hashes (tag `congelamento-d1-v1`) → teste final, que só abre se nada tiver mudado.
|
||||
5. **Execução isolada e reprodutível na OCI.** Pesos e ambientes vêm de buckets, com SHA-256 conferido; a inferência roda sem acesso a fontes externas (sub-rede privada ou bloqueio no processo, com autoteste); cada medição repete três vezes. GPU `VM.GPU.A10.1`; CPU `VM.Standard.E4.Flex` com 8 OCPU.
|
||||
6. **Análise:** IC 95% por bootstrap agrupado por lote, comparações pareadas, calibração (ECE, Brier), cobertura contra risco, cortes por perfil e número de opções, classificação dos erros e custo a preço público.
|
||||
|
||||
Detalhes em [docs/02 — desenho experimental](docs/02-desenho-experimental.md) e [docs/04 — decisões de projeto](docs/04-decisoes-de-projeto.md).
|
||||
|
||||
## Detalhes do projeto
|
||||
|
||||
### Plano de tarefas
|
||||
|
||||
As 78 microtarefas, organizadas em 11 fases e com o andamento de cada uma, estão em [docs/03-plano-de-tarefas.md](docs/03-plano-de-tarefas.md). O resumo por fase é regenerado com `python tools/plan_progress.py`.
|
||||
|
||||
### Documentos
|
||||
|
||||
| Documento | Conteúdo |
|
||||
|-----------|----------|
|
||||
| [docs/01-contexto-arquitetural.md](docs/01-contexto-arquitetural.md) | Arquitetura de referência do orquestrador e onde o modelo de decisão atua |
|
||||
| [docs/02-desenho-experimental.md](docs/02-desenho-experimental.md) | Tarefas de decisão, formato dos dados, partições, métricas e regras de isolamento |
|
||||
| [docs/03-plano-de-tarefas.md](docs/03-plano-de-tarefas.md) | As 78 microtarefas organizadas em fases, com dependências e adaptações ao contexto de roteamento |
|
||||
| [docs/02-desenho-experimental.md](docs/02-desenho-experimental.md) | Tarefas de decisão, formato dos dados, partições, métricas e conjunto d1-v1 |
|
||||
| [docs/03-plano-de-tarefas.md](docs/03-plano-de-tarefas.md) | Plano de 78 tarefas, com o andamento |
|
||||
| [docs/04-decisoes-de-projeto.md](docs/04-decisoes-de-projeto.md) | Decisões de projeto (Q1–Q14) e os mecanismos que as aplicam |
|
||||
| [docs/06-guia-de-anotacao.md](docs/06-guia-de-anotacao.md) | Guia de anotação, usado literalmente pelos anotadores |
|
||||
| [docs/05-cenario-de-execucao.md](docs/05-cenario-de-execucao.md) | Cenário de execução: onde cada etapa roda, isolamento e fluxo dos dados |
|
||||
| [config/benchmark.yaml](config/benchmark.yaml) | Parâmetros e critérios pré-registrados, congelados na tarefa 62 |
|
||||
| [docs/06-guia-de-anotacao.md](docs/06-guia-de-anotacao.md) | Guia de anotação, usado literalmente pelos anotadores |
|
||||
| [reports/](reports/) | Relatórios do piloto, desenvolvimento, calibração e teste final, com dados, gráficos e análise |
|
||||
|
||||
## Estrutura do repositório
|
||||
### Reprodução
|
||||
|
||||
```
|
||||
config/ Configuração pré-registrada (benchmark.yaml)
|
||||
dmb/ Código comum: contrato JEV, formato canônico, servidor /v1/systemone, isolamento de rede
|
||||
tests/ Testes de contrato, formato canônico, servidor e isolamento
|
||||
infra/oci/ Compartment, IAM, VCN, buckets, Data Science, VM e NAT (tarefas 1–10, 17, 78)
|
||||
infra/ds/ Jobs do Data Science: build dos ambientes, execução do benchmark e logs
|
||||
infra/vm/ remote.sh: sincroniza o repositório e executa na VM de trabalho
|
||||
env/ Aquisição de artefatos, manifesto, Dockerfile por candidato e dependências fixadas (11–16)
|
||||
contracts/jev/ Contrato JEV jev-compat-v1: esquemas, mapeamento de tipos, fixtures de conformidade (36–41)
|
||||
data/taxonomy/ Taxonomia de intenções (intents-v1.yaml: 42 intenções, 13 domínios) (20–23)
|
||||
datagen/ Pipeline sintético: geração, mascaramento/deduplicação, anotação por 3 LLMs, partições (24–36)
|
||||
data/raw/ Enunciados coletados e anonimizados — não versionar dados sensíveis (24–25)
|
||||
data/annotated/ Anotações, adjudicação e referência (29–32)
|
||||
data/splits/ Partições dev / calibração / teste congeladas (33–35)
|
||||
adapters/<modelo>/ Adaptadores JEV locais por candidato (42–51)
|
||||
harness/ Execução nos jobs (job.py), sanidade, servidor, auditoria do bucket (18–19, 41, 51–66)
|
||||
tools/ Utilitários do repositório (andamento do plano)
|
||||
analysis/ Métricas, cortes, análise de erros e gráficos (67–74)
|
||||
reports/ Relatório técnico e anexos de reprodução (75–76)
|
||||
| Artefato | Onde |
|
||||
|---|---|
|
||||
| Manifesto de artefatos (origem, revisão, licença, SHA-256, tamanho) | [env/artifacts-manifest.json](env/artifacts-manifest.json) |
|
||||
| Configuração pré-registrada, calibração e congelamento | [config/benchmark.yaml](config/benchmark.yaml), [config/calibration.json](config/calibration.json), [config/frozen.json](config/frozen.json) |
|
||||
| Partições congeladas | [data/splits/](data/splits/) ([MANIFEST.json](data/splits/MANIFEST.json)) |
|
||||
| Contrato e fixtures de conformidade | [contracts/jev/](contracts/jev/) |
|
||||
| Predições, resumos de execução e análise | [reports/](reports/) |
|
||||
| Logs de cada execução (stdout, stderr, `run.json` com gate de rede e ambiente) | Buckets `dmb-resultados` e `dmb-resultados-gru`, `runs/<run_id>/` |
|
||||
|
||||
```bash
|
||||
# testes locais do contrato, formato, servidor, isolamento, métricas, congelamento e dados sensíveis
|
||||
python -m pytest -q
|
||||
|
||||
# avaliação de um candidato numa partição (job do OCI Data Science)
|
||||
PYTHONPATH=infra/oci .venv/bin/python infra/ds/jobs.py run --name test-laya --entrypoint infra/ds/run_job.sh \
|
||||
--private --ocpus 8 --memory 64 --env DMB_CANDIDATE=laya DMB_MODE=evaluate DMB_SPLIT=test DMB_REP=1
|
||||
PYTHONPATH=infra/oci:infra/ds .venv/bin/python infra/ds/gpu_queue.py evaluate semif rizzo_flow laya gliner \
|
||||
--env DMB_SPLIT=test DMB_REP=1
|
||||
|
||||
# coleta, análise e gráficos
|
||||
PYTHONPATH=infra/oci .venv/bin/python infra/ds/collect.py --split test --examples 1744 --all-reps --dest reports/test
|
||||
python -m analysis.report reports/test
|
||||
python -m analysis.charts reports/test --kind test --label "teste final"
|
||||
```
|
||||
|
||||
## Princípios
|
||||
### Estrutura do repositório
|
||||
|
||||
1. **Isolamento de rede.** Na inferência, os modelos usam só artefatos locais com hash conhecido. Qualquer tentativa de download faz o job falhar.
|
||||
2. **Contrato único.** Todos os candidatos recebem a mesma requisição JEV e devolvem o mesmo formato de resposta.
|
||||
3. **Teste final congelado.** Prompts, opções, pesos e limiares não mudam depois que o conjunto de teste final é aberto.
|
||||
4. **Partição por conversa.** Turnos de uma mesma conversa ou caso nunca aparecem em mais de uma partição.
|
||||
5. **Reprodutibilidade.** Versões, seeds, hashes, configurações e comandos ficam registrados em manifestos anexados ao relatório.
|
||||
```
|
||||
config/ Configuração pré-registrada, calibração, congelamento e preços
|
||||
contracts/jev/ Contrato jev-compat-v1: esquemas e fixtures de conformidade
|
||||
dmb/ Código comum: contrato, formato canônico, servidor /v1/systemone, isolamento de rede, cliente de LLM
|
||||
adapters/<modelo>/ Adaptadores JEV por candidato
|
||||
harness/ Execução nos jobs, avaliação, sanidade, servidor e auditoria do bucket
|
||||
datagen/ Pipeline sintético: geração, preparação, anotação por 3 LLMs, partições
|
||||
data/ Taxonomia de intenções e partições congeladas
|
||||
analysis/ Métricas, calibração, análise final e gráficos
|
||||
env/ Aquisição de artefatos, manifesto e dependências por candidato
|
||||
infra/oci/ Compartment, IAM, rede, buckets, réplica entre regiões, NAT
|
||||
infra/ds/ Jobs do OCI Data Science: builds, execuções, fila de GPU, coleta
|
||||
infra/vm/ Preparação e execução remota na VM de trabalho
|
||||
models/ Metadados dos modelos (cards, configs, licenças); pesos ficam no Object Storage
|
||||
reports/ Relatórios por etapa
|
||||
tests/ Testes automatizados
|
||||
tools/ Andamento do plano e congelamento da configuração
|
||||
```
|
||||
|
||||
### Princípios
|
||||
|
||||
1. **Isolamento.** Na inferência, os modelos usam só artefatos com hash conhecido, sem acesso a fontes externas.
|
||||
2. **Contrato único.** Todos os candidatos recebem a mesma requisição e devolvem o mesmo formato de resposta.
|
||||
3. **Teste congelado.** Nada muda depois que o teste final é aberto, e o executor confere os hashes.
|
||||
4. **Partições disjuntas.** Exemplos do mesmo lote de geração nunca aparecem em mais de uma partição.
|
||||
5. **Reprodutibilidade.** Versões, seeds, hashes, configurações e comandos ficam versionados neste repositório.
|
||||
|
||||
Reference in New Issue
Block a user