⚠️ Early preview
This is an early preview release of a research model, published so people can try it and send feedback.
- The scores below come from a full run of the S1MB english-v1 suite (137 benchmarks, the suite's own evaluator) and my own rebuild of the Decision Index 0.1 suite (a 40-question slice per benchmark). Neither is an official board listing yet.
- The model, the files and these numbers may change in later versions. Pin a revision if you depend on it.
- It was trained only to pick among options. It is not a chat model.
- v4 (10 Oct 2026) replaces v3: trained further on the S1MB author's own training release (train splits of the sources S1MB tests, in S1MB's question format), on top of v3. Read the overlap notes before comparing its S1MB score with other models. v3 stays downloadable at the
v3tag of this repo, v2 atv2, v1 atv1.
☕ Support this work
Whittle is built by one person on a grocery budget and rented GPU hours. If this research is useful to you, or you want to see it finished: ko-fi.com/davida81328. Every hour of GPU time goes straight into the next checkpoint, and every checkpoint, table and log lands in these repos.
A System 1 decision model, not a chat model. Give it a state, a question and a set of options; it reads them once and returns a calibrated probability for every option, in a single forward pass. No generation, no thinking tokens.
It runs on official llama.cpp (no patches): the GGUFs carry the decision metadata, so llama-server serves the
POST /v1/systemone endpoint out of the box (decision type pplx-decider). See How to run.
The easy path is a GGUF with llama.cpp's built-in decision endpoint.
1. Get llama.cpp build b11455 or newer (tested on b11455). Prebuilt binaries are on the llama.cpp releases page, or build it:
git clone https://github.com/ggml-org/llama.cpp && cd llama.cpp
cmake -B build -DGGML_CUDA=ON # drop -DGGML_CUDA=ON for a CPU-only build
cmake --build build --config Release -j --target llama-server
2. Download a GGUF (Q4_K_M is the smallest one I recommend):
hf download logic65/Whittle-Reflex-25B-A3B-GGUF Whittle-Reflex-25B-A3B-Q4_K_M.gguf --local-dir .
| file | size | skill (40-item slice, stock serving) | runs on (rough guide) |
|---|---|---|---|
| Whittle-Reflex-25B-A3B-Q4_K_M.gguf | 15.7 GB | 0.405 | a 24 GB GPU, or a 16 GB GPU with --n-cpu-moe |
| Whittle-Reflex-25B-A3B-Q6_K.gguf | 21.1 GB | 0.424 | a 24 GB GPU (short states) or 32 GB |
| Whittle-Reflex-25B-A3B-Q8_0.gguf | 27.2 GB | 0.423 | a 32 GB GPU, or 3 x 12 GB; this is the file behind the full-suite numbers |
3. Start the server:
./build/bin/llama-server -m Whittle-Reflex-25B-A3B-Q4_K_M.gguf -ngl 99 -fa on -c 32768 --port 8080
decision model type: pplx-decider shows the decision metadata was read.--n-cpu-moe 20 (keeps the expert weights of the first 20 layers in system RAM; raise it until the model fits).-ngl 99. It works on CPU, just slower.-c is the context for one decision (state + question + options). 32768 covers long states; use less to save memory.4. Ask a question:
curl -s http://localhost:8080/v1/systemone -H 'Content-Type: application/json' -d '{
"state": {"note": "geography quiz"},
"questions": {
"pick": {"type": "choice", "instructions": "Which city is the capital of Australia?",
"criteria": {"sydney": "Sydney", "canberra": "Canberra", "melbourne": "Melbourne"}},
"noul": {"type": "noul", "instructions": "Is the Pacific the largest ocean?"}}}'
The answers from the Q8_0 file:
{"answers": {
"pick": {"type": "choice", "choice": "canberra",
"probabilities": {"sydney": 0.0058, "canberra": 0.9873, "melbourne": 0.0069}, "confidence": 0.981},
"noul": {"type": "noul", "noul": 0.9867}}}
The same from Python:
import requests
r = requests.post("http://localhost:8080/v1/systemone", json={
"state": "Customer message: I was charged twice for my order last week and nobody has replied.",
"questions": {
"route": {"type": "choice", "instructions": "Which team should handle this?",
"criteria": {"billing": None, "shipping": None, "technical": None}},
"urgency": {"type": "score", "instructions": "How urgent is this?",
"criteria": ["can wait", "this week", "today", "right now"]},
},
})
for qid, a in r.json()["answers"].items():
print(qid, a)
Question types:
| type | criteria |
answer |
|---|---|---|
choice |
object: option id -> description (or null), up to 255 options |
choice, probabilities (sum to 1), confidence |
score |
list of 2 to 10 level descriptions, lowest first | score (expected level index), probabilities, confidence |
noul |
optional {"true": ..., "false": ...} descriptions |
noul = probability of yes |
state can be a string, an object or an array; anything that is not a string is given to the model as JSON./v1/systemone section of the
llama-server README.from whittle_load import load_whittle # in this repo; sizes the (empty) n-gram memory from the checkpoint
model = load_whittle("logic65/Whittle-Reflex-25B-A3B")
The root weights load in stock transformers (tested with 5.18) with whittle_load.py. They are meant for research and further training. For decisions,
serve a GGUF as above. If you want the readout in your own code: the prompt is systemone.jinja (in this repo), options get the
single-token labels A, B, C, ... AA..JT, and the answer is the softmax over those labels' next-token logits.
S1MB is a public System 1 benchmark: 137 typed decision benchmarks (yes/no, choice and score questions), each scored 0 to 100 after subtracting a trivial baseline, equal weight per benchmark. The Reflex rows are my own runs with the suite's evaluator (official llama.cpp b11455, the Q8_0 file, 137/137 complete, zero failed decisions); the other rows are the top entries of the suite's public results (hotchpotch/s1mb-result, commit b9c4c60d, 102 complete entries), ranked in the board's default order (mean rank over all 137 benchmarks).
| rank (default order) | model | noul | choice | score | mean of the three |
|---|---|---|---|---|---|
| 1 | Darwin-27B-ZTC-v2 | 67.7 | 71.5 | 60.2 | 66.5 |
| 2 | OpenJev-27B (openjev) | 65.2 | 67.7 | 54.8 | 62.6 |
| 3 | AutoJev-27B | 65.0 | 68.1 | 49.3 | 60.8 |
| 4 | Whittle-Reflex v4 (25B-A3B) | 65.4 | 70.7 | 63.1 | 66.4 |
| 5 | Eikos 27B | 64.1 | 67.6 | 47.8 | 59.9 |
| 6 | Jev 1.13.0 | 64.6 | 67.2 | 46.9 | 59.6 |
| 7 | Cloudflare Clef | 61.6 | 67.2 | 39.1 | 56.0 |
| 8 | KnowLine-4B-Gen3 | 60.0 | 65.5 | 46.4 | 57.3 |
| 9 | KnowLine-4B-Gen2 | 58.7 | 64.1 | 43.0 | 55.3 |
| (not listed) | Whittle-Reflex v3 | 59.9 | 62.2 | 55.2 | 59.1 |
Overlap, please read before comparing. v4 trained on the train splits of hotchpotch/bekko-system-one-dataset-v0, the S1MB author's training release, built with the same converter as the S1MB test set. So most S1MB benchmarks are in-distribution for v4:
Measured on 1,173 requests: the first 40 per benchmark of the Decision Index 0.1 suite, 28 benchmarks. This is my own rebuild of the suite, not an official board run:
Mean chance-corrected skill (0 = chance, 1 = perfect):
| model | 1 option order (stock /v1/systemone) |
2 orders averaged |
|---|---|---|
| Whittle 25B (before) | 0.054 | 0.160 |
| Whittle-Reflex v1 | 0.336 | 0.370 |
| Whittle-Reflex v2 | 0.394 | 0.419 |
| Whittle-Reflex v3 | 0.394 | 0.396 |
| Whittle-Reflex v4 | 0.422 | 0.437 |
| Qwen3.6-35B-A3B | 0.404 | 0.421 |
| Qwen3.8-27B (v2's teacher) | 0.447 | 0.498 |
A full Decision Index 0.3 run of v2 (the board's own kit, stock llama.cpp, Q8_0) was started and stopped early; what it scored:
| benchmark | coverage | metric | skill |
|---|---|---|---|
| BFCL | 1,694 / 1,694 | 93.4% case exact accuracy | 0.91 |
| ToolRet | 142 / 685 queries so far | nDCG@10 0.76 | 0.72 (partial) |
One decision per request, no generation. Measured on v1 (same architecture and file sizes as v2 to v4). On two Tesla T4s (Kaggle), Q8_0, stock llama-server:
| file | size | 1 option order (stock) | 2 orders averaged | answers vs the trained model (64 check prompts) |
|---|---|---|---|---|
| Q8_0 | 27.2 GB | 0.423 | 0.433 | 64/64, gap 0.011 |
| Q6_K | 21.1 GB | 0.424 | 0.433 | 63/64, gap 0.013 |
| Q4_K_M | 15.7 GB | 0.405 | 0.416 | 64/64, gap 0.024 |
Scores come from llama.cpp's own hidden states for each file (read with a llama.cpp build that has a 2-line fix for --embeddings on
this architecture; serving uses official llama.cpp). Q8_0 is the v4 LoRA merged into the Whittle 25B Q8_0 (the file the full-suite run
uses); Q6_K and Q4_K_M are quantized from the bf16 root weights in this repo with official llama.cpp. The last column is the share of the 64 check
prompts where the file picks the same answer as the trained model in PyTorch, and the mean largest probability gap.
1,013 held-out questions (449 from the new training tasks, plus held-out Open-Jev and v2 questions):
pplx-decider type uses.pplx-decider
serving renders them (false first, with the standard option descriptions).v1 (7 Oct) used Qwen3.6-35B-A3B as the teacher and only the 16,000 classification questions; v2 adds the reasoning set and the stronger teacher; v3 adds the Open-Jev control tasks; v4 adds the S1MB-format training release.
pplx-decider serving reads one option order (0.423 on the slice, Q8_0).
Averaging two orders (0.433) needs your own wrapper; llama.cpp averages orders only for lev-type models.sources.json). Check their terms for your use.Same review battery as the other Whittle models, base 25B vs Reflex v1, same harness and machine (not rerun for v2, v3 or v4):
| test | Whittle 25B (base) | Whittle-Reflex |
|---|---|---|
| PopQA factual cloze (exact match) | 74/288 | 68/288 |
| PopQA first answer token | 48/288 | 60/288 |
| 40 knowledge facts | 35/40 | 34/40 |
| stop/loop battery: clean stops | 23/24 | 23/24 |
| loops / leaked user turns | 0 / 0 | 0 / 0 |
| GSM-50 (maths word problems) | 43/50 | 44/50 |
| strict JSON hold-out: valid / exact format | 72/72 / 71/72 | 72/72 / 60/72 |
| agent probes | 91/96 | 96/96 |
| web tool loop: replay A / B | 15/20 / 17/20 | 14/20 / 18/20 |
| web tool loop: episodes | 31/36 | 36/36 |
Same Q8_0 files, same llama.cpp build, same sampler (temperature 0.7, top-p 0.8, top-k 20, repeat penalty 1.05), thinking on, one RTX PRO 6000. The heal left general behaviour roughly where it was (better on the agent and web probes, worse on exact JSON formatting); it is still published as a decision model, because that is what it was trained and measured for. MATH-60 was not run.
model-00001.safetensors 4.7 GBmodel-00004.safetensors 4.6 GBmodel-00005.safetensors 4.6 GBmodel-00006.safetensors 4.6 GBmodel-00007.safetensors 4.6 GBmodel-00008.safetensors 4.6 GBmodel-00009.safetensors 4.6 GBmodel-00010.safetensors 4.6 GBmodel-00002.safetensors 4.6 GBmodel-00003.safetensors 4.6 GBmodel-00011.safetensors 4.5 GBmodel-00012.safetensors 882 MBHave the files? Submit a torrent.
Submit a torrentHave the complete files and permission to share them? Replace the example folder path. The script checks the files, makes a torrent and submits its magnet and checksums. Keep your torrent client seeding. Get your community key from your settings, and read the script before running it.
curl -fsSL https://pirateface.co/package.sh | bash -s -- --repo logic65/Whittle-Reflex-25B-A3B ./model-folder