Instructions to use yotambr/safedecide-400m with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use yotambr/safedecide-400m with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-classification", model="yotambr/safedecide-400m")# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModelForSequenceClassification tokenizer = AutoTokenizer.from_pretrained("yotambr/safedecide-400m") model = AutoModelForSequenceClassification.from_pretrained("yotambr/safedecide-400m", device_map="auto") - Notebooks
- Google Colab
- Kaggle
yotambr/safedecide-400m
The larger SafeDecide: a decision model that knows when not to decide.
Give it a state and a typed question (yes/no, pick-one, or score). It returns a
probability per option and an automate / escalate flag backed by a
statistical guarantee:
With probability >= 90% over the calibration draw, the error rate among decisions marked 'automate' is <= 10%, for data exchangeable with the calibration set. Everything else is marked 'escalate'.
Certified levels (pick one with decide(request, alpha=...)):
| Error level α | Threshold | Automated on the calibration carve |
|---|---|---|
| 5% | 0.740 | 19.7% |
| 10% (default) | 0.620 | 35.0% |
| 20% | 0.420 | 90.7% |
Out of the box, the default threshold applied unchanged to typed-decisions test (2,000
decisions, never used for training or calibration) automated 39.7% of them, and 4.3% of
those were wrong (budget 10%).
The guarantee does not rely on the model's probabilities being calibrated. It comes from Learn-then-Test risk control (exact Clopper–Pearson bounds, fixed-sequence testing over a fixed threshold grid) on a held-out calibration set.
Code: github.com/yotambraun/safedecide · raw predictions behind every number: yotambr/safedecide-results · the smaller model: yotambr/safedecide-140m
Results
typed-decisions test: 400
cases, 2,000 decisions. The model was fine-tuned on typed-decisions train, so it belongs
in that benchmark's "fitted or fine-tuned on train" table. It never saw test.
| Model | Accuracy ↑ | KL from gold ↓ | Brier ↓ | ECE ↓ | Automation @ 10% ↑ |
|---|---|---|---|---|---|
| SafeDecide-400M v0.2 (this model) | 0.787 | 0.083 | 0.045 | 0.171 | 52.4% ± 3.8% |
| SafeDecide-140M v0.2 | 0.748 | 0.113 | 0.061 | 0.140 | 40.6% ± 3.0% |
| SafeDecide-140M v0.1 (yotambr/safedecide-140m) | 0.754 | 0.126 | 0.069 | 0.147 | 33.2% ± 5.2% |
Paired on the same decisions, this model's accuracy is +3.3 points over v0.1
(95% bootstrap interval over cases: +1.4 to +5.2). It is ahead on every question type
(v0.1: noul 0.840, choice 0.717, score 0.718) and on three of the four workflows; on
agent_trace_observability it is behind (0.706 vs 0.738):
| n | Accuracy | KL | Brier | ECE | |
|---|---|---|---|---|---|
| noul | 600 | 0.858 | 0.042 | 0.033 | 0.135 |
| choice | 600 | 0.748 | 0.115 | 0.060 | 0.169 |
| score | 800 | 0.762 | 0.089 | 0.045 | 0.202 |
| Workflow | n | Accuracy | KL | Brier | ECE |
|---|---|---|---|---|---|
| agent_trace_observability | 500 | 0.706 | 0.089 | 0.053 | 0.157 |
| customer_service | 500 | 0.822 | 0.094 | 0.047 | 0.196 |
| invoice_processing | 500 | 0.842 | 0.078 | 0.044 | 0.129 |
| security_incidents | 500 | 0.778 | 0.069 | 0.038 | 0.209 |
How to read these:
- Accuracy is agreement with the gold
label, as in the 140M model's row. On 35 test decisions the gold probabilities tie; counting a tie as correct gives 0.794, and the benchmark'sbench/score_with_jobs.py(first tied option) gives 0.784. - ECE is 15 equal-width bins on top-option confidence, pooled over the 2,000 decisions (10 bins: 0.172). It is higher than v0.1's: this model's probabilities are sharper than its accuracy warrants. The automate/escalate guarantee does not depend on it.
- Automation @ 10% is the share of decisions the model may take alone with the error
among them certified at most 10% (δ = 10%), averaged over 100 random calibration/test
splits of
testby case (± is the standard deviation over splits). - Precision. The numbers above are the sealed test pass, run once on an A100 with bf16
autocast. In full precision on CPU (what
SafeDeciderruns there, and what the thresholds were certified on) the same weights give accuracy 0.7875, KL 0.0825, Brier 0.0455 and ECE 0.172, the same as the sealed pass to within 0.001. Against v0.1, also in full precision (0.7545), the paired gain is the same +3.3 points [+1.4, +5.2].
Chosen on train, sealed before test
Every choice was made on train. The training recipe was chosen by 5-fold
cross-validation of the 140M model on the 1,080 train cases outside a 600-decision
calibration carve (out-of-fold accuracy: 0.658 for v0.1's schedule, 0.748 for the chosen
recipe). This model reuses that recipe, fixed in advance, with no cross-validation of its own.
Before test was scored, the SHA-256 of recipe.json (the code commit, every
out-of-fold score, the choice, and the hash of each final model's weights and
configuration) was posted in
discussion #39:
11a60a13db03e1e8c831d7003d7a51bb8e20c4acc2a15b8d6a013872251812e7. test was then
scored once, by a notebook pass that refuses to run if any hash has changed. Check it:
sha256sum recipe.json model.safetensors safedecide_config.json
One disclosure: before posting the seal, both models were compared with v0.1 on the
600-decision calibration carve (this model +4.8 points there, +3.3 on test). The same
carve certifies the thresholds, so it was looked at twice; test was not looked at.
Speed
PyTorch on 1 CPU thread, one 3-option decision: 605 ms p50 (622 ms p90). The 140M model takes 80 ms on the same input and thread, so pick it when CPU latency matters. There is no ONNX export of this model yet.
Usage
pip install safedecide
A held-out customer-service case from typed-decisions test, in the /v1/systemone shape:
from safedecide import SafeDecider
decider = SafeDecider.from_pretrained("yotambr/safedecide-400m")
response = decider.decide(
{
"state": {
"account": {
"lifetime_value_usd": 228,
"prior_tickets_90d": 0,
"seats": 1,
"tenure_months": 3,
"tier": "standard",
},
"thread": [
{"role": "customer", "text": "My payment didn’t go through, and I’m now locked out of my account."}
],
},
"questions": {
"topic": {
"type": "choice",
"instructions": "What is this customer conversation primarily about?",
"criteria": {
"account": "Login, plan changes, profile or access management.",
"billing": "A charge, invoice, subscription or payment problem.",
"delivery": "Shipping, fulfilment or delivery of a physical item.",
"refund": "The customer is explicitly asking for money back.",
"technical": "The product or service is not working as expected.",
},
},
"needs_human": {
"type": "noul",
"instructions": "This conversation requires a human agent rather than automated handling.",
"criteria": {
"false": "Automation can carry this to resolution.",
"true": "A human must take over: judgement, authority or empathy is required.",
},
},
},
}
)
response["answers"]["topic"] # choice "billing", confidence 0.54 ("account" 0.43), action "escalate"
response["answers"]["needs_human"] # noul 0.37 (no), confidence 0.63, action "automate"
response["guarantee"]["statement"] # the promise behind every "automate", in words
The case really is split: the gold distribution for its topic is billing 0.58, account 0.33 (and 0.30 for needs a human), so the model hands the topic to a person instead of guessing.
Inputs unlike typed-decisions (free text, options without descriptions) are outside the
shipped guarantee: re-certify on your own labelled decisions with
safedecide calibrate --model yotambr/safedecide-400m --data my_decisions.jsonl (format in
the README).
Serve it behind the same /v1/systemone API as Jev: safedecide serve --model yotambr/safedecide-400m.
How it works
- Architecture: each (state, question, option) triple is scored by a cross-encoder with
one logit; softmax over a question's options. Option-order invariance is exact by
construction. Standard
AutoModelForSequenceClassificationon Ettin-encoder-400m (MIT). - Training: one stage, straight from the base encoder: soft-label cross-entropy against
the teacher distributions + Brier score + ranked probability score for ordinal questions,
at 640 tokens (no typed-decisions input is truncated). Each epoch also draws about one
training-only factor question per two real decisions: questions built from the
typed-decisions
factorsof the training cases, never model input and never fromtest. Trained on 90% of the 1,080 cases (972) with early stopping on the other 10%; best validation NLL at step 3,000, stopped at 3,500. - Calibration: per-kind temperature scaling fitted on that 10% (540 decisions;
temperatures:
{"noul": 1.168, "choice": 1.025, "score": 1.021}), then the selective thresholds above on the calibration carve (600 decisions by case, never trained on; nevertest).
Data and license
Trained only on the typed-decisions train split (Apache-2.0), with no other decision
data. Base encoder MIT. Released under Apache-2.0.
Limitations
- Decisions, not text. Questions that need multi-step reasoning or world knowledge belong to a generative model.
- The guarantee is marginal over the calibration distribution, not per class and not per customer, and only for data like the calibration set.
- Trained on four typed-decisions workflows only; other workflows need re-calibration at the very least.
- English only as evaluated.
- Not for fully automated decisions with legal, medical, financial or employment effects on people.
Citation
@misc{braun2026safedecide,
title = {SafeDecide: small decision models with guaranteed automation},
author = {Yotam Braun},
year = {2026},
url = {https://huggingface.co/yotambr/safedecide-400m}
}
- Downloads last month
- -
Model tree for yotambr/safedecide-400m
Base model
jhu-clsp/ettin-encoder-400m