Text Classification
PEFT
Safetensors
Portuguese
support-automation
e-commerce
portuguese
ticket-routing
decision-model
multi-task
lora
multi-specialist
Eval Results (legacy)
Instructions to use syvorai/veredicto with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use syvorai/veredicto with PEFT:
Task type is invalid.
- Notebooks
- Google Colab
- Kaggle
Upload folder using huggingface_hub
Browse files- README.md +18 -0
- REPRODUCAO.md +7 -7
- manifest.json +4 -4
- scripts/auditoria_card.py +69 -2
README.md
CHANGED
|
@@ -115,6 +115,24 @@ this card are measured, never estimated.
|
|
| 115 |
The ruler was **never** used for training or fitting; all numbers at T=1,
|
| 116 |
same split, same protocol, paired per-case predictions.
|
| 117 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 118 |
| system | category | decision | urgency | overall |
|
| 119 |
|---|---|---|---|---|
|
| 120 |
| JEV (frontier decision API, teacher/reference) | **0.7251** | **0.6892** | 0.7238 | **0.7127** |
|
|
|
|
| 115 |
The ruler was **never** used for training or fitting; all numbers at T=1,
|
| 116 |
same split, same protocol, paired per-case predictions.
|
| 117 |
|
| 118 |
+
**This release:**
|
| 119 |
+
|
| 120 |
+
| metric | Trium (this release) | best single model (E1) |
|
| 121 |
+
|---|---|---|
|
| 122 |
+
| Overall accuracy (all questions) | **0.7118** | 0.6835 |
|
| 123 |
+
| Accuracy on the human-adjudicated hard core | **0.6895** | 0.6566 |
|
| 124 |
+
| Category accuracy | **0.7012** | 0.6773 |
|
| 125 |
+
| Decision accuracy | **0.6892** | 0.6892 |
|
| 126 |
+
| Urgency accuracy | **0.7450** | 0.6839 |
|
| 127 |
+
| Category macro-F1 (classes present in the test split) | **0.6018** | 0.5714 |
|
| 128 |
+
|
| 129 |
+
The hard core is the 497 human-adjudicated hard cases of the ruler
|
| 130 |
+
(subset `nucleo`, 1,491 of the 2,259 test answers); macro-F1 follows the
|
| 131 |
+
lineage's standard rule (mean F1 over every category appearing in the
|
| 132 |
+
split's gold or predictions — 13 here). Category accuracy/macro-F1 of
|
| 133 |
+
Trium come from its B2 head; decision from E1; urgency from the v4
|
| 134 |
+
adapter.
|
| 135 |
+
|
| 136 |
| system | category | decision | urgency | overall |
|
| 137 |
|---|---|---|---|---|
|
| 138 |
| JEV (frontier decision API, teacher/reference) | **0.7251** | **0.6892** | 0.7238 | **0.7127** |
|
REPRODUCAO.md
CHANGED
|
@@ -21,13 +21,13 @@ few hundredths of a pp between library versions):
|
|
| 21 |
|
| 22 |
```
|
| 23 |
# 753 casos, 2259 respostas
|
| 24 |
-
TRIUM cat 0.7012 dec 0.6892 urg 0.7450 geral 0.7118
|
| 25 |
-
CompA cat 0.6826 dec 0.6494 urg 0.7450 geral 0.6923
|
| 26 |
-
v6 cat 0.6826 dec 0.6494 urg 0.6521 geral 0.6614
|
| 27 |
-
b2 cat 0.7012 dec 0.6680 urg 0.6707 geral 0.6799
|
| 28 |
-
e1 cat 0.6773 dec 0.6892 urg 0.6839 geral 0.6835
|
| 29 |
-
v4 cat 0.2470 dec 0.1633 urg 0.7450 geral 0.3851
|
| 30 |
-
base cat 0.5817 dec 0.2988 urg 0.5511 geral 0.4772
|
| 31 |
bootstrap Trium vs v6: Δ +5.05 p.p. IC95 [+3.54; +6.60]
|
| 32 |
bootstrap Trium vs CompA: Δ +1.95 p.p. IC95 [+1.15; +2.74]
|
| 33 |
bootstrap Trium vs base (clef-flash zero-shot): Δ +23.46 p.p. IC95 [+21.16; +25.72]
|
|
|
|
| 21 |
|
| 22 |
```
|
| 23 |
# 753 casos, 2259 respostas
|
| 24 |
+
TRIUM cat 0.7012 dec 0.6892 urg 0.7450 geral 0.7118 hard 0.6895 macroF1 0.6018(13)
|
| 25 |
+
CompA cat 0.6826 dec 0.6494 urg 0.7450 geral 0.6923 hard 0.6693
|
| 26 |
+
v6 cat 0.6826 dec 0.6494 urg 0.6521 geral 0.6614 hard 0.6398 macroF1 0.5898(13)
|
| 27 |
+
b2 cat 0.7012 dec 0.6680 urg 0.6707 geral 0.6799 hard 0.6506 macroF1 0.6018(13)
|
| 28 |
+
e1 cat 0.6773 dec 0.6892 urg 0.6839 geral 0.6835 hard 0.6566 macroF1 0.5714(13)
|
| 29 |
+
v4 cat 0.2470 dec 0.1633 urg 0.7450 geral 0.3851 hard 0.3803
|
| 30 |
+
base cat 0.5817 dec 0.2988 urg 0.5511 geral 0.4772 hard 0.4681
|
| 31 |
bootstrap Trium vs v6: Δ +5.05 p.p. IC95 [+3.54; +6.60]
|
| 32 |
bootstrap Trium vs CompA: Δ +1.95 p.p. IC95 [+1.15; +2.74]
|
| 33 |
bootstrap Trium vs base (clef-flash zero-shot): Δ +23.46 p.p. IC95 [+21.16; +25.72]
|
manifest.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
| 1 |
{
|
| 2 |
-
"gerado": "2026-10-
|
| 3 |
"release": "veredicto",
|
| 4 |
"arquivos": {
|
| 5 |
-
"README.md": "
|
| 6 |
-
"REPRODUCAO.md": "
|
| 7 |
"heads/veredicto_e1_step-2576/joint_head.pt": "2665935d6b018483015d09739165cbf4248425922c60754f105f1cfb8011e92a",
|
| 8 |
"heads/veredicto_e1_step-2576/joint_head_config.json": "71018e6a3d73723a5a8b4a151c5ceb82a1c2a5658f7d80168fe6c82afede0f36",
|
| 9 |
"heads/veredicto_e1_step-2576/manifesto.json": "620e185e8d527bfa36415b89236b3510155a781436b1b531c37701a75a8a9d29",
|
|
@@ -20,7 +20,7 @@
|
|
| 20 |
"heads/veredicto_b2_step-2208/processor/tokenizer_config.json": "7488550a894dcf741616126e322ea31d66cf9457b59ec5825f4c7efdced421f8",
|
| 21 |
"adapters/veredicto-lora-v4/adapter_config.json": "719d9a473d3f9fd7d9fbe729b77bf58accae8d1d733cb8f875b5ecfe82e3b6b4",
|
| 22 |
"adapters/veredicto-lora-v4/adapter_model.safetensors": "efe526ccca100a32b11d44a62fbf2ebaf659c499f8f14db1543c0abd0420a07f",
|
| 23 |
-
"scripts/auditoria_card.py": "
|
| 24 |
"scripts/avaliar_veredicto.py": "14fe1a5624977a9fb3004c0eebb5066a6560e7fa77a04c707e9df2922a2f8c66",
|
| 25 |
"scripts/paridade_multi.py": "16d8eff0af7d3e045f3453420137ed6f13550d39dc61decc232f8448b5c4ba04",
|
| 26 |
"scripts/servir_veredicto_multi.py": "485eeb2731e0d3c3a887a4226ff446683deb9fd8f88865d1a84fe07569a778f4",
|
|
|
|
| 1 |
{
|
| 2 |
+
"gerado": "2026-10-23T16:08:13-03:00",
|
| 3 |
"release": "veredicto",
|
| 4 |
"arquivos": {
|
| 5 |
+
"README.md": "9688d0912fd17c9917e4d37ac914049b39a898dff6f7d6aa774da2d897f22584",
|
| 6 |
+
"REPRODUCAO.md": "e56439e8311f274cb28c1b17e8e91d943b506adfdbf6784a88b99e37f6d8ff30",
|
| 7 |
"heads/veredicto_e1_step-2576/joint_head.pt": "2665935d6b018483015d09739165cbf4248425922c60754f105f1cfb8011e92a",
|
| 8 |
"heads/veredicto_e1_step-2576/joint_head_config.json": "71018e6a3d73723a5a8b4a151c5ceb82a1c2a5658f7d80168fe6c82afede0f36",
|
| 9 |
"heads/veredicto_e1_step-2576/manifesto.json": "620e185e8d527bfa36415b89236b3510155a781436b1b531c37701a75a8a9d29",
|
|
|
|
| 20 |
"heads/veredicto_b2_step-2208/processor/tokenizer_config.json": "7488550a894dcf741616126e322ea31d66cf9457b59ec5825f4c7efdced421f8",
|
| 21 |
"adapters/veredicto-lora-v4/adapter_config.json": "719d9a473d3f9fd7d9fbe729b77bf58accae8d1d733cb8f875b5ecfe82e3b6b4",
|
| 22 |
"adapters/veredicto-lora-v4/adapter_model.safetensors": "efe526ccca100a32b11d44a62fbf2ebaf659c499f8f14db1543c0abd0420a07f",
|
| 23 |
+
"scripts/auditoria_card.py": "8b9799a54474d7ab6e37a701dabfa3ef29daa817c9dfc19539f61ee0ca4c7575",
|
| 24 |
"scripts/avaliar_veredicto.py": "14fe1a5624977a9fb3004c0eebb5066a6560e7fa77a04c707e9df2922a2f8c66",
|
| 25 |
"scripts/paridade_multi.py": "16d8eff0af7d3e045f3453420137ed6f13550d39dc61decc232f8448b5c4ba04",
|
| 26 |
"scripts/servir_veredicto_multi.py": "485eeb2731e0d3c3a887a4226ff446683deb9fd8f88865d1a84fe07569a778f4",
|
scripts/auditoria_card.py
CHANGED
|
@@ -43,6 +43,16 @@ def load_raw(path):
|
|
| 43 |
return d
|
| 44 |
|
| 45 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
def load_ops(path):
|
| 47 |
"""(caso,q) -> lista de option_ids (ordem em que pred/rotulo indexam)."""
|
| 48 |
d = {}
|
|
@@ -53,6 +63,16 @@ def load_ops(path):
|
|
| 53 |
return d
|
| 54 |
|
| 55 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
def load_ouro(path, seed=42):
|
| 57 |
"""rótulos do teste (mesmo split da régua) como hit-flags de um oráculo."""
|
| 58 |
here = Path(__file__).resolve().parent
|
|
@@ -111,6 +131,24 @@ def acc(casos, fonte):
|
|
| 111 |
return out
|
| 112 |
|
| 113 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 114 |
def main():
|
| 115 |
ap = argparse.ArgumentParser()
|
| 116 |
ap.add_argument("--dir", required=True)
|
|
@@ -126,6 +164,24 @@ def main():
|
|
| 126 |
casos = sorted({c for c, _ in keys})
|
| 127 |
print(f"# {len(casos)} casos, {len(keys)} respostas")
|
| 128 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 129 |
base_path = d / "preds_base_clef.jsonl"
|
| 130 |
base = load_preds(base_path) if base_path.exists() else None
|
| 131 |
|
|
@@ -138,8 +194,19 @@ def main():
|
|
| 138 |
modelos.append(("base", base))
|
| 139 |
for nome, fonte in modelos:
|
| 140 |
a = acc(casos, fonte)
|
| 141 |
-
|
| 142 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 143 |
|
| 144 |
def compose(fonte):
|
| 145 |
if all(isinstance(k, str) for k in fonte):
|
|
|
|
| 43 |
return d
|
| 44 |
|
| 45 |
|
| 46 |
+
def load_pred_raw(path):
|
| 47 |
+
"""(caso,q) -> índice predito, na ordem de option_ids do próprio arquivo."""
|
| 48 |
+
d = {}
|
| 49 |
+
with open(path, encoding="utf-8") as f:
|
| 50 |
+
for line in f:
|
| 51 |
+
r = json.loads(line)
|
| 52 |
+
d[(r["caso"], r["q"])] = int(r["pred"])
|
| 53 |
+
return d
|
| 54 |
+
|
| 55 |
+
|
| 56 |
def load_ops(path):
|
| 57 |
"""(caso,q) -> lista de option_ids (ordem em que pred/rotulo indexam)."""
|
| 58 |
d = {}
|
|
|
|
| 63 |
return d
|
| 64 |
|
| 65 |
|
| 66 |
+
def load_subset(path):
|
| 67 |
+
"""(caso,q) -> subset ('nucleo' = hard core arbitrado por humano)."""
|
| 68 |
+
d = {}
|
| 69 |
+
with open(path, encoding="utf-8") as f:
|
| 70 |
+
for line in f:
|
| 71 |
+
r = json.loads(line)
|
| 72 |
+
d[(r["caso"], r["q"])] = r.get("subset", "nao_informado")
|
| 73 |
+
return d
|
| 74 |
+
|
| 75 |
+
|
| 76 |
def load_ouro(path, seed=42):
|
| 77 |
"""rótulos do teste (mesmo split da régua) como hit-flags de um oráculo."""
|
| 78 |
here = Path(__file__).resolve().parent
|
|
|
|
| 131 |
return out
|
| 132 |
|
| 133 |
|
| 134 |
+
def macro_f1_categoria(raw_cat, pred_cat, ops):
|
| 135 |
+
"""macro-F1 de categoria com a mesma regra da linhagem Decisum (avaliar_v4_bench):
|
| 136 |
+
média do F1 sobre as classes que aparecem no ouro OU nas predições do teste
|
| 137 |
+
(no teste atual: 12 classes; fraude_suspeita e reembolso têm n ínfimo no ouro)."""
|
| 138 |
+
cls = {}
|
| 139 |
+
def slot(lab):
|
| 140 |
+
return cls.setdefault(lab, [0, 0, 0])
|
| 141 |
+
for key, gold_idx in raw_cat.items():
|
| 142 |
+
real, pred = ops[key][gold_idx], ops[key][pred_cat[key]]
|
| 143 |
+
if real == pred:
|
| 144 |
+
slot(real)[0] += 1
|
| 145 |
+
else:
|
| 146 |
+
slot(real)[2] += 1
|
| 147 |
+
slot(pred)[1] += 1
|
| 148 |
+
f1s = [2 * tp / max(1, 2 * tp + fp + fn) for tp, fp, fn in cls.values()]
|
| 149 |
+
return sum(f1s) / len(f1s), len(f1s)
|
| 150 |
+
|
| 151 |
+
|
| 152 |
def main():
|
| 153 |
ap = argparse.ArgumentParser()
|
| 154 |
ap.add_argument("--dir", required=True)
|
|
|
|
| 164 |
casos = sorted({c for c, _ in keys})
|
| 165 |
print(f"# {len(casos)} casos, {len(keys)} respostas")
|
| 166 |
|
| 167 |
+
subset = load_subset(d / "preds_v6.jsonl")
|
| 168 |
+
assert all(subset[k] in ("nucleo", "aleatorio") for k in keys), "subsets inesperados"
|
| 169 |
+
nucleo = [k for k in keys if subset[k] == "nucleo"]
|
| 170 |
+
ops = load_ops(d / "preds_v6.jsonl")
|
| 171 |
+
|
| 172 |
+
def hard(src):
|
| 173 |
+
"""acc no hard core (subset 'nucleo'); src = roteado (tarefa->hits) ou mono."""
|
| 174 |
+
roteado = all(isinstance(k, str) for k in src)
|
| 175 |
+
return sum((src[k[1]] if roteado else src)[k] for k in nucleo) / len(nucleo)
|
| 176 |
+
|
| 177 |
+
def macro_f1(src_raw_cat):
|
| 178 |
+
"""macro-F1 de categoria no critério da linhagem Decisum (ver macro_f1_
|
| 179 |
+
categoria); src_raw_cat: (caso,'categoria') -> índice predito."""
|
| 180 |
+
raw_cat = load_raw(d / "preds_v6.jsonl")
|
| 181 |
+
raw_cat = {k: v for k, v in raw_cat.items() if k[1] == "categoria"}
|
| 182 |
+
return macro_f1_categoria(raw_cat, src_raw_cat,
|
| 183 |
+
{k: ops[k] for k in raw_cat})
|
| 184 |
+
|
| 185 |
base_path = d / "preds_base_clef.jsonl"
|
| 186 |
base = load_preds(base_path) if base_path.exists() else None
|
| 187 |
|
|
|
|
| 194 |
modelos.append(("base", base))
|
| 195 |
for nome, fonte in modelos:
|
| 196 |
a = acc(casos, fonte)
|
| 197 |
+
line = (f"{nome:6s} cat {a['categoria']:.4f} dec {a['decisao']:.4f} "
|
| 198 |
+
f"urg {a['urgencia']:.4f} geral {a['geral']:.4f} "
|
| 199 |
+
f"hard {hard(fonte):.4f}")
|
| 200 |
+
# macro-F1 de categoria:TRIUM usa a cabeça de categoria (b2). A base
|
| 201 |
+
# zero-shot fica de fora: preds_base_clef.jsonl não traz option_ids,
|
| 202 |
+
# então seus índices não podem ser rotulados a partir do arquivo.
|
| 203 |
+
cat_file = {"TRIUM": "preds_b2.jsonl", "v6": "preds_v6.jsonl",
|
| 204 |
+
"b2": "preds_b2.jsonl", "e1": "preds_e1.jsonl"}.get(nome)
|
| 205 |
+
if cat_file is not None:
|
| 206 |
+
src_pred = load_pred_raw(d / cat_file)
|
| 207 |
+
m, n_cls = macro_f1({k: v for k, v in src_pred.items() if k[1] == "categoria"})
|
| 208 |
+
line += f" macroF1 {m:.4f}({n_cls})"
|
| 209 |
+
print(line)
|
| 210 |
|
| 211 |
def compose(fonte):
|
| 212 |
if all(isinstance(k, str) for k in fonte):
|