Rankine 0.6B v1

Fahrenheit Research. The typed decision engine. Zero means zero.

One state in, typed probabilistic decisions out. Rankine reads one piece of unstructured state and answers every typed question about it at once. Each answer is a probability distribution, not a single label. The domain knowledge arrives inside the input at inference time, so one model covers every workflow.

Facts

Backbone Qwen/Qwen3-0.6B, Apache-2.0
Build LoRA fine-tune, fused into the backbone, quantized to 4-bit MLX at group size 64
Size 331 MiB of repository files, of which 320 MiB is weights
Context 40,960 tokens
Options per question up to 255 single-token markers
Primitives choice, score, noul

A choice returns a distribution over named options. A score returns a distribution over ordered rubric levels plus an expected score that may fall between levels. A noul returns the probability that a proposition holds.

Results on typed-decisions, test split

400 cases, 2,000 decisions, P50 99 ms per case on Apple M5.

model n accuracy soft_accuracy macro_f1 kl tv brier ece score_mae within_1
Rankine v1, 4-bit (this model) 2000 0.743 0.546 0.605 0.122 0.173 0.067 0.154 0.256 0.971
Rankine v1, fp16 adapters (unshipped fp16) 2000 0.764 0.567 0.647 0.102 0.153 0.056 0.159 0.229 0.974

The shipped 4-bit build scores 0.743 accuracy against a teacher self-agreement ceiling of 0.735 on this benchmark. Scoring near or above that ceiling means the remaining error is mostly disagreement with the teacher's own spread rather than misreading the state.

Per workflow, 4-bit

workflow n accuracy soft_accuracy macro_f1 kl tv brier ece score_mae within_1
agent_trace_observability 500 0.738 0.500 0.634 0.094 0.159 0.055 0.204 0.204 1.000
customer_service 500 0.730 0.553 0.657 0.161 0.196 0.088 0.129 0.265 0.995
invoice_processing 500 0.800 0.621 0.613 0.137 0.182 0.070 0.144 0.305 0.935
security_incidents 500 0.704 0.511 0.439 0.095 0.156 0.056 0.140 0.251 0.955

Per primitive, 4-bit

primitive n accuracy soft_accuracy macro_f1 kl tv brier ece score_mae within_1
choice 600 0.750 0.527 0.557 0.157 0.189 0.079 0.171 - -
noul 600 0.830 0.651 0.784 0.075 0.137 0.052 0.156 - -
score 800 0.672 0.482 0.560 0.131 0.188 0.069 0.141 0.256 0.971

Weakest cells, and the targets for the next iteration: score accuracy at 0.672 and security_incidents macro F1 at 0.439.

Comparison

Scored on the same test split. Every row is marked specialist, meaning fitted on these workflows, or zero-shot, meaning the model had never seen these schemas.

Model Kind Accuracy Brier ECE
Rankine 0.6B v1, 4-bit (this model) specialist 0.743 0.067 0.154
Rankine 0.6B v1, fp16 adapters (unshipped fp16) specialist 0.764 0.056 0.159
Laya typed-decisions specialist 0.766 0.062 0.213
meraGPT Decider 1 zero-shot 0.768 0.052 reference, not published
TypeSafe Jev 1.13.0 zero-shot 0.727 0.148 0.144
Teacher self-agreement ceiling 0.735 not applicable not applicable

Teacher self-agreement on this benchmark is 0.735. Gold labels are the mean of three samples from a teacher endpoint, so a fresh teacher sample scored against gold built from the other two reaches 0.735. Read that as the point above which accuracy measures agreement with the teacher's idiosyncrasies rather than the task. Read KL and Brier alongside accuracy for that reason.

The Laya, meraGPT Decider 1 and Jev figures are the benchmark card reference values carried by this project's evaluation harness. They were not re-measured here.

Speed

All figures below are Apple M5, 200 runs per measurement, with compiled graphs and packed sequences both enabled. Laya is measured on the same Apple M5 machine from aac6fef/laya-mlx rather than quoted from its own card. Laya wins the single-question rows and the many-questions-per-state row.

end to end, Apple M5 Rankine, Apple M5 Laya, Apple M5
One question, P50 15.96 ms 11.23 ms
One question, P95 16.27 ms 11.57 ms
One question over a prepared state, P50 20.84 ms not available
One question over a prepared state, P95 21.75 ms not available
50 questions on one state 181.8 q/s 384.6 q/s
5-question typed case, packed, P50 47.23 ms 62.42 ms
5-question typed case, packed, P95 55.35 ms 65.10 ms
5-question typed case, batched over a prepared state, P50 46.90 ms not available
5-question typed case, sequential over a prepared state, P50 46.83 ms not available

Rankine keeps one KV cache for the state and runs each question as a short suffix over it, so a question asked over a prepared state costs 20.84 ms at P50 on Apple M5 regardless of how long the state is. Laya has no equivalent prepared-state path. Laya answers a single fresh question faster, at 11.23 ms P50 on Apple M5 against 15.96 ms, and sustains 384.6 q/s against 181.8 q/s when 50 questions run over one state on Apple M5. Rankine is ahead on the 5-question typed case, the shape this model is built for, at 47.23 ms P50 on Apple M5 against 62.42 ms.

Quickstart

Rankine uses its own prompt layout, not a chat transcript. The state is encoded once as a prefix, each question is a short suffix ending in Answer:, and the answer is read from the logits over the option marker tokens. Nothing is generated. The rankine package builds those strings and does the readout.

The rankine package ships inside this repository, under rankine/. The package named rankine on PyPI is an unrelated project and is not this one, so do not install it from there.

pip install mlx-lm huggingface_hub
hf download FahrenheitResearch/Rankine-0.6B-v1-mlx-4bit --local-dir rankine-v1
cd rankine-v1

From that directory:

import rankine

agent = rankine.load(".")          # the directory you just downloaded

state = {
    "channel": "email",
    "subject": "Charged twice for the October plan",
    "body": "My card shows two charges of 49.00 on 3 October. Please refund one.",
    "account_age_days": 412,
}

out = agent.predict(state, {
    "department": {
        "type": "choice",
        "instructions": "Which team should handle this message?",
        "criteria": {
            "billing": "payments, refunds, invoices",
            "technical": "bugs, outages, integration errors",
            "sales": "pricing questions from prospects",
        },
    },
})

answer = out["answers"]["department"]
print(answer["label"], round(answer["probabilities"][answer["label"]], 3))
# billing 0.958

Several questions in one call share one encoding of the state:

out = agent.predict(state, {
    "department": {"type": "choice", "instructions": "Which team should handle this message?",
                   "criteria": {"billing": "payments, refunds, invoices",
                                "technical": "bugs, outages, integration errors",
                                "sales": "pricing questions from prospects"}},
    "urgent":     {"type": "noul", "instructions": "This needs a reply today."},
    "refund":     {"type": "noul", "instructions": "The customer is asking for money back."},
    "severity":   {"type": "score", "instructions": "How severe is the issue for the customer?",
                   "criteria": ["Cosmetic", "Minor", "Major", "Blocking"]},
    "churn_risk": {"type": "score", "instructions": "How likely is this customer to leave?",
                   "criteria": ["Very low", "Low", "Moderate", "High"]},
})

For a state that is reused across many questions, encode it once:

prepared = agent.prepare(state)
out = agent.predict(prepared, questions)

rankine.load also accepts the repository id, rankine.load("FahrenheitResearch/Rankine-0.6B-v1-mlx-4bit"), which pulls the weights into the Hugging Face cache instead of reading them from the current directory.

The MLX backend is selected automatically on Apple silicon when mlx-lm is installed. The PyTorch backend exposes the same interface elsewhere.

chat_template.jinja ships in this repository so that generic tooling can load the tokenizer, and it is the stock Qwen3 template inherited from the backbone. It is not used by the typed decision path and applying it would break the marker readout.

Calibration

Training targets are soft: half the teacher distribution and half the gold label, so the loss is a soft-label cross-entropy rather than a hard-label one. A proper scoring rule is then read off the held-out split, so the reported Brier score and KL from gold measure the distribution and not only the argmax.

After training, one temperature is fitted per question bucket on held-out data and stored in calibration.json. A bucket is the primitive plus its option count, because a three-option choice and a nine-option choice are not sharpened by the same amount. rankine.load reads the file and applies the temperature before the softmax.

bucket temperature
choice:3 0.980
choice:4 0.994
choice:5 1.035
choice:6 1.152
choice:9+ 1.192
noul 1.508
score:4 1.070
score:5 1.130

Choices with nine or more options share one 9+ bucket. A bucket with no fitted entry falls back to the mean of the fitted temperatures for its own primitive, and to 1.0 only when that primitive has none. A temperature above 1.0 softens the distribution, which is what a bucket that was overconfident needs. Calibrated overall ECE on the test split is 0.154 and Brier is 0.067.

Calibration can be disabled per call with agent.predict(..., calibrate=False).

Limitations

  • English only. Every training and evaluation row is English.
  • Four workflows: agent_trace_observability, customer_service, invoice_processing and security_incidents. Behaviour on an unseen schema is not characterised by the numbers above.
  • Quantization costs 0.021 accuracy against the fp16 adapters, 0.764 down to 0.743. The fp16 build is not shipped.
  • The zero-shot score is not yet measured. Every Rankine number on this card is a specialist number, fitted on these four workflows. It is not comparable like for like with the zero-shot rows for meraGPT Decider 1 and Jev.
  • Accuracy is agreement with a teacher-derived gold label, not ground truth. The per-question ceiling varies widely across the benchmark.
  • This is a typed decision engine, not a chat model. It does not generate text.

Citation

@misc{rankine-0.6b-v1,
  title  = {Rankine 0.6B v1: typed probabilistic decisions on device},
  author = {Fahrenheit Research},
  year   = {2026},
  url    = {https://huggingface.co/FahrenheitResearch/Rankine-0.6B-v1-mlx-4bit}
}

Links

License

Apache-2.0, inherited from the Qwen3-0.6B backbone.

Downloads last month
16
Safetensors
Model size
0.6B params
Tensor type
U32
·
BF16
·
MLX
Hardware compatibility
Log In to add your hardware

4-bit

Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for FahrenheitResearch/Rankine-0.6B-v1-mlx-4bit

Finetuned
Qwen/Qwen3-0.6B
Quantized
(452)
this model

Dataset used to train FahrenheitResearch/Rankine-0.6B-v1-mlx-4bit

Evaluation results