decider
5 TagsUpdated Apache-2.0by Mapika
Decoder decision models by Mapika on Qwen3.5: the answer is read from option-letter logits in one forward pass.
ollaya run decider --preset triage "I was charged twice for my subscription this month and want a refund."curl http://localhost:11435/api/decide \
-H "Content-Type: application/json" \
-d '{
"model": "decider",
"state": "I was charged twice for my subscription this month and want a refund.",
"questions": {
"department": {
"type": "choice",
"instructions": "Which team should handle this?",
"criteria": {
"billing": "Payments, invoices and refunds",
"technical": "Bugs, errors and outages",
"account": "Login, profile and settings"
}
},
"refund": {
"type": "noul",
"instructions": "Is the customer asking for a refund?"
}
}
}'# Already using a TypeSafe SDK? Set TYPESAFE_BASE_URL=http://localhost:11435 instead.
import requests
response = requests.post(
"http://localhost:11435/api/decide",
json={
"model": "decider",
"state": "I was charged twice for my subscription this month and want a refund.",
"questions": {
"department": {
"type": "choice",
"instructions": "Which team should handle this?",
"criteria": {
"billing": "Payments, invoices and refunds",
"technical": "Bugs, errors and outages",
"account": "Login, profile and settings"
}
},
"refund": {
"type": "noul",
"instructions": "Is the customer asking for a refund?"
}
}
},
)
answers = response.json()["answers"]
print(answers["department"]["choice"], answers["refund"]["noul"])const response = await fetch("http://localhost:11435/api/decide", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
model: "decider",
state: "I was charged twice for my subscription this month and want a refund.",
questions: {
department: {
type: "choice",
instructions: "Which team should handle this?",
criteria: {
billing: "Payments, invoices and refunds",
technical: "Bugs, errors and outages",
account: "Login, profile and settings"
}
},
refund: {
type: "noul",
instructions: "Is the customer asking for a refund?"
}
}
}),
});
const { answers } = await response.json();
console.log(answers.department.choice, answers.refund.noul);Models
Every tag| Name | Accuracy | Latency | |||
|---|---|---|---|---|---|
| Most accurateHighest typed-decisions accuracy of the family. | |||||
| decider:4bQwen3.5-4B base (v3), 0.678 on typed decisions, one fitted temperature per answer type. Best on a GPU. | 0.678 | 197 ms | |||
| FasterFastest first; accuracy as measured on the bench. | |||||
| decider:0.8bQwen3.5-0.8B base, 0.505 on typed decisions: smaller and faster. | 0.505 | 60 ms | |||
| decider:2bQwen3.5-2B base (v12), 0.608 on typed decisions, one fitted temperature per answer type. | 0.608 | 84 ms | |||
| deciderlatestSame as decider:2b. | 0.608 | 84 ms | |||
| Reads imagesA PNG with the state, through the author’s projector. | |||||
| decider:2b-visionReads an image as well as the state: Qwen3.5-2B vision-language with v5 text weights. One PNG per request, up to 10 options. | — | — | |||
Accuracy: typed-decisions, argmax against the majority label on 400 states (left out for a tag trained on that data). Latency: the median five-question request on an RTX 5090, Ollaya Bench.
Readme
decider is a family of open decision models by Mapika, built on Qwen3.5 base models and released under Apache-2.0. For each question it lays out the context, the question and lettered options, then reads the model's next-token logits for the option letters at an answer slot. It never generates text; every question is one forward pass.
Models
| Tag | Base | Params | Typed-decisions accuracy |
|---|---|---|---|
decider:latest, decider:2b | Qwen3.5-2B (v12) | 1.9B | 0.608 |
decider:4b | Qwen3.5-4B (v3) | 4.2B | 0.678 |
decider:0.8b | Qwen3.5-0.8B | 0.75B | 0.505 |
decider:2b-vision | Qwen3.5-2B vision-language (v5 text weights) | 2.2B | reads images; see below |
Accuracy is the argmax against the majority label on all 400 typed-decisions states. For comparison, nli scores 0.536, gliclass 0.477 and laya:en 0.357. The labels have low annotator agreement, so compare the numbers against each other rather than reading them as absolutes. On Mapika's own numbers 4b (v3) is ahead of 2b (v12): JevBench public items hard 0.640 vs 0.595, a 4,500-request sample of the Decision Index 0.3 at 51.0 vs 38.2.
decider:4bneeds Ollaya 0.7.0 or newer, which keeps its weights BF16 in memory. Older versions widen them to fp32 (about 17 GB).
Usage
ollaya run decider --preset triage "My order never arrived and support ignores me. Refund me today or I'm switching to your competitor."
ollaya run decider:4b --preset triage "My order never arrived and support ignores me. Refund me today or I'm switching to your competitor."Images: decider:2b-vision
decider:2b-vision answers questions about an image as well as the state: a photo, a screenshot, a diagram or a game frame. Pass a PNG with --image, or base64 in images on /api/decide:
ollaya run decider:2b-vision --image shelf.png --questions '{"blocked":{"type":"noul","instructions":"Is the aisle blocked?"}}' "A photo from the warehouse camera."- One PNG per request, up to about one megapixel (1024x1024). The model's preprocessing is reproduced value for value, so convert a JPEG to PNG first: Rust's JPEG decoders differ from the authors' by a few levels on some pixels.
- Up to 10 options per question (v5's lettered prompt, A to J). Text-only requests work too.
- Parity. On 404 test questions, 12 of them with images: identical resized pixels, token ids and positions, the same decision on every question, and option logits within 1.6e-4 of the Python reference, on CPU and CUDA.
- Speed. On an RTX 4090, five questions about a 256x240 image take about 200 ms, and about 0.9 s about a 1000x750 one. On the CPU, 3 to 16 seconds.
/v1/systemonetakes no images: TypeSafe's API has no field for them.
decider:2b-visionneeds Ollaya 0.7.5 or newer.
Speed
- RTX 5090, through the HTTP API (Ollaya Bench): five questions with a short state take 60 ms on
0.8b, 84 ms on2band 197 ms on4bat the median: slower than the encoders (laya:en: 18 ms), and for0.8band2bstill faster than hosted Jev (236–276 ms). - State length: cost grows with the number of options times the context length.
- Memory: on a 24 GB GPU,
2bhandles states up to about 8k tokens. Longer states spill out of GPU memory and become very slow.
How it works
- Weights. They come from Mapika's own
model.safetensors, downloaded from Hugging Face, pinned to a commit and verified by sha256. Ollaya hosts only the ONNX graph (8 to 11 MB). - Precision. fp32 compute on the BF16 weights.
0.8band2bwiden the weights when they load;4bkeeps them BF16 (half the memory) and widens each layer just before it runs, with the same answers and about 12% more time per pass. - Calibration.
4b(v3) and2b(v12) have one temperature per answer type from Mapika's config: choice 2.098 and 2.465, score 3.152 and 2.833, yes/no 0.05 on both. The yes/no value is Mapika's choice for JevBench's rule that a yes/no probability between 0.2 and 0.8 counts as wrong, so yes/no answers come out near 0 or 1 and are not calibrated probabilities (the fitted values would be 2.795 and 3.185, per the model cards).0.8bhas one temperature. - Parity. Ollaya's Rust runtime matches the Python reference exactly: identical token ids and answer-slot positions, and the same decision on every test question, on CPU and CUDA.
Limits
- Memory. With requests of about 1,400 tokens,
2btook about 13 GB of GPU memory and4babout 14 GB. All three are slow on the CPU, where4bpeaked at 21 GB;4bbelongs on a GPU. - Score criteria. Criteria given as an object instead of a list are rejected, as TypeSafe's API does.
- Instructions. Every question needs
instructions. Mapika's newer package also accepts a yes/no question without them; Ollaya rejects it.
Badge
For the model card or a README. Day-0 support for a new model
[](https://ollaya.dev/library/decider)