DecisionFairy-4B

A 4B non-autoregressive decision model: a Qwen3.5-4B backbone plus a joint schema head. One forward pass scores every option of every requested field at once — it never generates text.

Auto-generated snippets from this card only load the backbone. Typed decisions need the bundled joint_schema_model.py (or Unsloth's FastDecisionModel), as shown below.

What it does

Input is a state (a string or any JSON) plus one or more questions. Each question has a type:

type meaning answer
noul yes / no probability that it is true, 0…1
choice pick one option best option, plus a probability per option
score rate on 2–10 levels expected level (may be fractional), plus a probability per level

All fields are decided jointly in a single pass; there is no token-by-token output. The head uses the same design as Cloudflare's Clef (projection + routing over each question and option span), and is trained with Unsloth's FastDecisionModel / DecisionTrainer.

Files

file contents
model.safetensors-0000{1,2}-of-00002 Qwen3.5-4B backbone, bf16, ~4.66B params, 9.3 GB
joint_head.safetensors, joint_head_config.json decision head: 32.05M params, 122 tensors, 64 MB (width 512, 4 blocks, 8 heads, 2 routing layers)
joint_schema_model.py standalone loader + systemone() (torch + transformers only)
infer.py, serve_systemone.py Unsloth-based CLI and FastAPI server
config.json, tokenizer*, processor_config.json, chat_template.jinja base model files
LICENSE Apache-2.0

Inference

Option A — standalone (joint_schema_model.py, no Unsloth)

from joint_schema_model import load_release_model, systemone

model, processor = load_release_model("wesjos/DecisionFairy-4B", device="cuda")  # or "cpu"

request = {
    "model": "decisionfairy",              # required by systemone()
    "state": "The production API returns 502 and p99 latency is 15s.",
    "questions": {
        "severity": {
            "type": "choice",
            "instructions": "Assign the incident tier",
            "criteria": {"P0": "total outage", "P1": "partial degradation", "P2": "minor"},
        },
        "page_oncall": {"type": "noul", "instructions": "Page the on-call engineer now?"},
        "urgency": {"type": "score", "instructions": "How urgent is it?",
                    "criteria": ["can wait", "today", "right now"]},
    },
}
print(systemone(model, processor, request, max_length=1024))

Requires a transformers build that ships Qwen3_5ForConditionalGeneration (the checkpoint was saved with transformers 5.10.4). systemone() also accepts images / videos keys on the record.

Response (same shape as the /v1/systemone API; values illustrative):

{
  "model": "decisionfairy",
  "answers": {
    "severity":    {"type": "choice", "choice": "P0", "confidence": 0.98,
                    "probabilities": {"P0": 0.98, "P1": 0.015, "P2": 0.005}},
    "page_oncall": {"type": "noul", "noul": 0.99},
    "urgency":     {"type": "score", "score": 2.1, "confidence": 0.91,
                    "legend": {"0": "can wait", "1": "today", "2": "right now"},
                    "probabilities": {"0": 0.01, "1": 0.08, "2": 0.91}}
  },
  "usage": {"input_tokens": 210, "output_tokens": 0}
}

Option B — Unsloth

from unsloth import FastDecisionModel

model, tokenizer = FastDecisionModel.from_pretrained(
    model_name="wesjos/DecisionFairy-4B",
    load_in_4bit=True,          # False for full bfloat16
    max_seq_length=1024,
)
FastDecisionModel.for_inference(model)

answers = FastDecisionModel.predict(model, tokenizer, state, questions)
for name, result in answers.items():
    print(name, result["answer"], {k: round(v, 3) for k, v in result["probabilities"].items()})

predict takes the same question format as systemone(); each answer carries answer plus the Decision API fields.

System One server

python3 serve_systemone.py --model . --port 18095        # add --load-in-4bit to halve VRAM
curl -s http://127.0.0.1:18095/v1/systemone \
  -H "Content-Type: application/json" \
  -d '{"state": "Customer says the invoice was charged twice.",
       "questions": {"refund": {"type": "noul", "instructions": "Is a refund requested?"}}}'

The wrapper accepts {state, questions} and returns {model, answers, timings}.

Notes and limits

  • Context: trained with max_seq_length = 1024 (unsloth_decision_config.json). Keep state + questions under ~1024 tokens, and pass max_length=1024 to systemone() (its default is 16384, which the model was never trained on).
  • Text decisions: the backbone architecture is multimodal and the loader accepts images / videos, but this release contains no image or video evaluation — treat it as a text model.
  • Probabilities are per-field softmax outputs, not calibrated on your data. Threshold on a single option's probability; confidence is not comparable across models.
  • No text generation: there is no LM output to read.

License

Apache-2.0, following the Qwen3.5-4B backbone.

Downloads last month
49
Safetensors
Model size
5B params
Tensor type
BF16
·
F32
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for wesjos/DecisionFairy-4B

Finetuned
Qwen/Qwen3.5-4B
Finetuned
(1170)
this model
Quantizations
2 models

Datasets used to train wesjos/DecisionFairy-4B

Collection including wesjos/DecisionFairy-4B