Benchmarks¶
Every model answered the same questions and was scored by the same code. TypeSafe Jev was measured directly through TypeSafe's own API, not taken from published figures. Full tables, per-task results and methodology: COMPARISON.md.
Reproduce every number: python benchmarks/report.py rebuilds all the tables from the committed results, and
python benchmarks/run.py --model <name> re-scores any model
(benchmarks/).

The test sets¶
- typed-decisions (dataset): 2,000 decisions across four business workflows, scored with the Jev-vs-Laya harness published by Kameshwara Pavan kumar Mantha and the Antz AI team. nano, small-td, medium-td, large-td and Laya's typed-decisions checkpoint were fine-tuned on its train split; the test split was never used for training or model selection. Zero-shot models are a reference there, not a head-to-head.
- 200 general decisions none of the models trained on: BANKING77 intent (78 options), BoolQ yes/no, Yelp 1–5 star rating and ChaosNLI (100 human labels per item).
- Laya's application battery: Laya's own 10-task benchmark, at a pinned commit.
OpenDecider vs TypeSafe Jev¶
| benchmark / metric | TypeSafe Jev 1.13 | nano | small | medium-td | large-td |
|---|---|---|---|---|---|
| typed-decisions, 2,000 decisions | 0.754 (zero-shot) | 0.796 | 0.672 (zero-shot) | 0.788 | 0.801 |
| 200 general decisions | 0.730 | 0.680 | 0.735 | 0.765 | 0.750 |
| Laya's application battery, 10 tasks | 0.774 | 0.656 | 0.702 | 0.725 | 0.718 |
| calibration error (ECE), general decisions ↓ | 0.164 | 0.092 | 0.087 | 0.110 | 0.083 |
| distance from the human label spread (ChaosNLI JSD) ↓ | 0.148 | 0.045 | 0.040 | 0.035 | 0.030 |
| median latency, 1 question | 404 ms (API) | 17 ms (L40S) | 40 ms (L40S) | 214 ms (4× L40S) | 440 ms (4× L40S) |
| weights | closed API | Apache-2.0 | Apache-2.0 | Apache-2.0 | Apache-2.0 |
Where Jev leads: Laya's application battery (0.774, and 0.803 on the five tasks Laya was not trained on), phishing (0.897 vs our 0.63–0.70), jailbreak detection (0.940), spam (0.985), model routing (0.975), BoolQ-style yes/no reading (0.94) and typed-decisions without fine-tuning (0.754 vs small's 0.672).
OpenDecider vs Laya¶
| benchmark | Laya | Laya typed-decisions | nano | small | medium-td | large-td |
|---|---|---|---|---|---|---|
| typed-decisions | 0.362 | 0.766 | 0.796 | 0.672 | 0.788 | 0.801 |
| 200 general decisions | 0.545 | 0.570 | 0.680 | 0.735 | 0.765 | 0.750 |
| Laya's battery, all 10 tasks | 0.695 | 0.702 | 0.656 | 0.702 | 0.725 | 0.718 |
| Laya's battery, the 5 tasks Laya was not trained on | 0.579 | 0.609 | 0.656 | 0.743 | 0.768 | 0.757 |
| calibration error (ECE), general decisions ↓ | 0.327 | 0.162 | 0.092 | 0.087 | 0.110 | 0.083 |
Like for like on typed-decisions (both fine-tuned on the train split), nano leads Laya's typed-decisions checkpoint by +0.030 (95% CI +0.014 to +0.044). Where Laya leads: the five datasets it was trained on (AG News 0.95, Enron spam 0.99, phishing 0.98), multilingual use (a 100+ language checkpoint; OpenDecider is evaluated in English only), and single-question speed on short inputs, where it is in the same range as nano.
OpenDecider vs Microsoft-Decision-1¶
Microsoft-Decision-1 is a 9B decision model (built on Qwen3.5-9B) served through Microsoft Foundry. It answers the same
typed questions as Jev, so it ran through the same harness (--model foundry, our own Foundry deployment, 2026-10-10).
Microsoft publishes neither its training data nor per-dataset results.
| benchmark / metric | Microsoft-Decision-1 | nano | small-td | medium-td | large-td | TypeSafe Jev 1.13 |
|---|---|---|---|---|---|---|
| typed-decisions, 2,000 decisions | 0.783 | 0.796 | 0.792 | 0.788 | 0.801 | 0.754 |
| 200 general decisions | 0.795 | 0.680 | 0.715 | 0.765 | 0.750 | 0.730 |
| Laya's application battery, 10 tasks | 0.751 | 0.656 | 0.703 | 0.725 | 0.718 | 0.774 |
| calibration error (ECE), general decisions ↓ | 0.072 | 0.092 | 0.107 | 0.110 | 0.083 | 0.164 |
| distance from the human label spread (ChaosNLI JSD) ↓ | 0.079 | 0.045 | 0.040 | 0.035 | 0.030 | 0.148 |
| weights | Microsoft Foundry API | Apache-2.0 | Apache-2.0 | Apache-2.0 | Apache-2.0 | closed API |
Paired 95% CIs (COMPARISON.md, section 4): on typed-decisions Decision-1 is not distinguishable from nano, small-td and medium-td (OpenDecider's were fine-tuned on the train split), and ahead of Jev (+0.029). On general decisions it is not distinguishable from medium-td and large-td and ahead of Jev (+0.065). On Laya's battery it is ahead of every OpenDecider model and behind Jev (−0.023).
Where Decision-1 leads: general decisions (0.795) and calibration (ECE 0.072, second only to Claude Fable 5.1), BANKING77 in Laya's battery (0.890), and phishing (0.777 vs our 0.63–0.70). Where it trails: toxicity (0.530 vs 0.77–0.81 for OpenDecider's 4B-and-larger models), the spread of human votes (JSD 0.079 vs 0.030–0.045), and it is API-only.
Frontier LLMs (same 200 general decisions)¶
| model | accuracy | ECE ↓ | median latency | $ / 1,000 decisions |
|---|---|---|---|---|
| Claude Fable 5.1 | 0.840 | 0.064 | 4.27 s | $11.81 |
| Microsoft-Decision-1 (decision model, 9B) | 0.795 | 0.072 | 1.13 s | – (see below) |
| GPT-6 Astra | 0.790 | 0.119 | 2.22 s | $6.96 |
| opendecider-medium-td | 0.765 | 0.110 | 214 ms | self-hosted |
| DeepSeek V4.1 Flash | 0.760 | 0.138 | 4.08 s | $0.158 |
| MiniMax M3 | 0.755 | 0.112 | 1.02 s | $0.149 |
| opendecider-large-td | 0.750 | 0.083 | 440 ms | self-hosted |
| Kimi K3 | 0.745 | 0.119 | 6.28 s | $3.64 |
| opendecider-small | 0.735 | 0.087 | 40 ms | self-hosted |
| TypeSafe Jev 1.13 | 0.730 | 0.164 | 404 ms | $0.025 |
| opendecider-nano | 0.680 | 0.092 | 17 ms | self-hosted |
| CLM-8B (Contrastive-LM) | 0.400 | 0.106 | ~35 ms | self-hosted |
Only Claude Fable 5.1, Microsoft-Decision-1 and GPT-6 Astra beat opendecider-medium-td here, all through an API with a per-call bill. The 200-item set is about ±3 points: Decision-1's lead over medium-td is within noise (+0.030, 95% CI −0.025 to +0.090), and medium-td, DeepSeek V4.1 Flash and MiniMax M3 are close. Decision-1's latency is the round trip from India to Foundry's East US region. Foundry lists it at $0.042 per million input tokens (output free); the runs did not record token counts, so there is no per-1,000 figure.
Prompt guard¶
opendecider.guard against Laya's guard on the test splits of three public datasets (2,438 prompts):
deepset/prompt-injections (116, English and German),
jackhhao/jailbreak-classification (262) and
xTRam1/safe-guard-prompt-injection (2,060). Both
ask the same two questions, the attack questions of Laya's guard preset. Each model's threshold was set on the train
splits by a rule fixed before any test result was seen (the threshold that maximises balanced accuracy, averaged over
the three datasets) and applied once to test. No test prompt is in OpenDecider's training data (0 text overlaps).
| model | threshold | all (95% CI) | attacks caught | benign flagged | deepset | jailbreak | safeguard |
|---|---|---|---|---|---|---|---|
| opendecider-small-td | 0.484 | 0.936 (0.927–0.946) | 0.928 | 0.060 | 0.828 | 0.897 | 0.947 |
| opendecider-small | 0.500 | 0.900 (0.888–0.912) | 0.914 | 0.108 | 0.802 | 0.863 | 0.910 |
| Laya (English checkpoint) | 0.271 | 0.898 (0.886–0.910) | 0.934 | 0.121 | 0.767 | 0.969 | 0.897 |
| Laya (default router) | 0.271 | 0.897 (0.884–0.908) | 0.929 | 0.121 | 0.724 | 0.973 | 0.897 |
| opendecider-nano | 0.387 | 0.831 (0.816–0.845) | 0.914 | 0.214 | 0.776 | 0.901 | 0.825 |
Accuracy per dataset. Paired with Laya's English checkpoint, opendecider-small-td is ahead by 0.038 overall (95% CI +0.023 to +0.052) and by 0.050 on safeguard, within noise on deepset (+0.060, CI −0.017 to +0.138), and behind on jailbreak-classification (−0.073, CI −0.111 to −0.034), where it flags 21% of the benign prompts against Laya's 6.5%. safeguard is 85% of the prompts, so it weighs most in the totals; averaged per dataset the two are close (balanced accuracy 0.889 vs 0.884). Tuning the threshold on the train splits did not help on test: at 0.5, small-td scores 0.945 and Laya 0.909, slightly above their tuned results. The guard keeps the train-split thresholds, as the rule set out.
Quantised builds¶
The published GGUF builds (run through Ollama) and MLX builds, on the same test splits. Each build's threshold was set on the train splits by the same rule as its model's. A 4-bit build scores higher than its model, so at 0.5 it flags far more benign prompts; at its own threshold it screens as well as the full model.
| build | threshold | all (95% CI) | attacks caught | benign flagged | at 0.5: all | at 0.5: benign flagged |
|---|---|---|---|---|---|---|
| opendecider-small-td (PyTorch, above) | 0.484 | 0.936 (0.927–0.946) | 0.928 | 0.060 | 0.945 | 0.040 |
| opendecider-small-td GGUF Q8_0 | 0.506 | 0.940 (0.931–0.950) | 0.925 | 0.052 | 0.938 | 0.057 |
| opendecider-small-td GGUF Q4_K_M | 0.557 | 0.957 (0.949–0.966) | 0.936 | 0.031 | 0.922 | 0.106 |
| opendecider-small (PyTorch, above) | 0.500 | 0.900 (0.888–0.912) | 0.914 | 0.108 | 0.900 | 0.108 |
| opendecider-small GGUF Q8_0 | 0.512 | 0.920 (0.910–0.932) | 0.903 | 0.070 | 0.911 | 0.091 |
| opendecider-small GGUF Q4_K_M | 0.558 | 0.934 (0.923–0.944) | 0.915 | 0.057 | 0.842 | 0.225 |
| opendecider-small MLX 8-bit | 0.516 | 0.913 (0.902–0.925) | 0.898 | 0.079 | 0.907 | 0.094 |
| opendecider-small MLX 4-bit | 0.547 | 0.906 (0.894–0.917) | 0.926 | 0.105 | 0.871 | 0.178 |
The guard uses each build's threshold when the model name says which build it is: an Ollama name with its tag
(hf.co/manjunathshiva/opendecider-small-td-GGUF:Q4_K_M), an LM Studio name with its variant
(opendecider-small-td@q4_k_m), or the MLX build's name. A name that does not say (an Ollama name without its tag,
an LM Studio model loaded without its variant in the name, or a GGUF given a plain name) gets its model's threshold
or 0.5, both at or below every build's, so it flags more rather than less. Averaged per dataset (balanced accuracy), the
builds' thresholds and 0.5 are within 0.005 of each other except small's Q4_K_M (0.885 vs 0.853); the totals move
more because two thirds of the test prompts are benign (1,589 of 2,438, 1,410 of them in safeguard), and a 4-bit
build's extra flags at 0.5 fall on them.
python benchmarks/guard.py report prints these tables from the committed results, and two more setups: one yes/no
question (Laya's published deepset question) and Laya's whole guard preset scored with LayaGuardrail's own rule. See
Agent guardrails for what the numbers mean in practice.
In the browser¶
@opendecider/web runs opendecider-nano as ONNX: q8 (8-bit weights, float32 elsewhere; WebAssembly's default), q8f16
(8-bit weights, float16 elsewhere; WebGPU's default) and fp16 (float16 throughout; on WebGPU about 7 times faster than
q8f16 for many questions at once, which is what OpenDecider Focus uses). Each was scored with native ONNX Runtime on the
CPU against the PyTorch model's committed answers. The browser's WebAssembly gives the same logits as native ONNX Runtime
to 1e-6 for q8 and q8f16, and within 0.01 for fp16. WebGPU computes in float16: there (Chrome, Apple M4 Max), fp16 gave
PyTorch's answer on all 400 general and 99.45% of the 2,000 typed-decisions questions, and q8f16 on 99.5% and 99.3%,
with the same typed-decisions accuracy. A build ships only if it gives PyTorch's answer on at least 99% of the questions
and loses at most 0.5 points on each benchmark.
| build | download | typed-decisions (2,000) | general (200) | Laya's battery (10 × 400) | answers as PyTorch |
|---|---|---|---|---|---|
| opendecider-nano (PyTorch, above) | 790 MB (bf16) | 0.796 | 0.680 | 0.656 | – |
| q8 (WebAssembly) | 569 MiB | 0.795 | 0.680 | 0.656 | 99.6–99.8% |
| q8f16 (WebGPU) | 450 MiB | 0.798 | 0.680 | 0.656 | 99.5–99.8% |
| fp16 | 755 MiB | 0.796 | 0.680 | 0.655 | 99.9–100% |
Not shipped: 4-bit builds (286–410 MiB) changed 2.5–4.3% of the answers (typed-decisions 0.790), whatever the quantisation method (symmetric, asymmetric, HQQ), and dynamic int8 gave different logits in the browser's WebAssembly than in native ONNX Runtime, so its benchmark would not describe what runs in the browser.
As a guard (the attack questions, each build at its own train-split threshold):
| build | threshold | all (95% CI) | attacks caught | benign flagged |
|---|---|---|---|---|
| opendecider-nano (PyTorch, above) | 0.387 | 0.831 (0.816–0.845) | 0.914 | 0.214 |
| q8 | 0.391 | 0.828 (0.813–0.843) | 0.914 | 0.218 |
| q8f16 | 0.390 | 0.828 (0.813–0.842) | 0.914 | 0.218 |
| fp16 | 0.388 | 0.830 (0.815–0.845) | 0.913 | 0.215 |
YouTube feed¶
The questions of the Chrome extension on 800 videos from a public set of US trending videos (2019–2020, MIT), 100 from each of 8 categories, with the creator's category as the label: News, Howto, Education and Science & Technology are kept, Music, Gaming, Comedy and Entertainment hidden. Below, the test half (400 videos); the dev half gives the same ranking. Balanced accuracy at 0.5 (the mean of the share of wanted videos kept and of unwanted ones hidden), so a rule that matches 100 of 400 videos cannot score by answering no.
| model | your own rule (mean of 3) | hide music | hide gaming | only news | kinds: keep learning and news (AUC) | Quietly's request |
|---|---|---|---|---|---|---|
| opendecider-nano (fp16, as the extension runs it) | 0.934 | 0.954 | 0.896 | 0.951 | 0.780 (0.872) | 0.502 |
| opendecider-nano (PyTorch) | 0.934 | 0.956 | 0.896 | 0.951 | 0.778 (0.872) | 0.502 |
| TypeSafe Jev 1.13 | 0.940 | 0.931 | 0.919 | 0.971 | 0.865 (0.928) | 0.787 |
| Laya, typed-decisions checkpoint | 0.870 | 0.901 | 0.759 | 0.949 | 0.740 (0.898) | 0.535 |
| Laya | 0.852 | 0.916 | 0.714 | 0.927 | 0.712 (0.875) | 0.500 |
| Laya, multilingual | 0.660 | 0.761 | 0.700 | 0.520 | 0.782 (0.857) | 0.495 |
"Quietly's request" is the one Quietly sends Jev for each video: a yes/no
question with the title in it and Quietly's keep and hide lists as its true and false descriptions, and the same state
for every video. opendecider-nano and Laya judge the state, so they answer it the same way
for every video; the extension puts the video in the state. The creator's category is a noisy label (a cooking show is
often filed under Entertainment), so read the kinds column as a comparison, not as the share of a feed sorted right.
python benchmarks/run.py --suites youtube --model <model> reruns a row.
Speed¶
| questions per call | nano, NVIDIA L40S | nano, Apple M4 Max | small, NVIDIA L40S | small, Apple M4 Max |
|---|---|---|---|---|
| 1 | 16.1 ms | 18.1 ms | 37.6 ms | 141 ms |
| 5 | 24.4 ms (4.9 ms/q) | 54.3 ms (10.9 ms/q) | 190.1 ms (38.0 ms/q) | 680 ms (136 ms/q) |
| 10 | 42.9 ms (4.3 ms/q) | 98.1 ms (9.8 ms/q) | 388.2 ms (38.8 ms/q) | 1.37 s (137 ms/q) |
| 50 | 189.5 ms (3.8 ms/q) | 467 ms (9.3 ms/q) | 1.94 s (38.7 ms/q) | 6.86 s (137 ms/q) |
Throughput under concurrent load is in Serve it.