Torchcast Decision 12B β€” MLX, 8-bit

An 8-bit MLX copy of torchcast-ai/torchcast-decision-12b (revision 49107b5589bf2dc4ec3f5acd54316971dd5978b1, tag v1.0.0), made so the model runs on Apple silicon. Upstream ships a vLLM serving package and no MLX artifact; this is one.

It is not a chat model. It is a typed-decision model: one forward pass over a state plus a question plus lettered options, and the answer is the probability of each option letter at the answer slot β€” one output token, no reasoning, no prose. The authors' upstream card is the reference for what the checkpoint is and what it was trained on; this card covers only what changed here and how to run it.

upstream this copy
precision bf16 8-bit affine, group 64 (8.5 bits/weight)
size 23.9 GB, one shard 12.7 GB, three shards
runtime vLLM 0.30.0 + upstream shim mlx_lm.server, letter readout on the client
modality gemma4_unified (text/vision/audio) text only β€” mlx-lm drops the towers it cannot run

Quickstart

python3 -m venv .venv && . .venv/bin/activate    # Python 3.10+
pip install mlx-lm                               # tested with mlx-lm 0.32.2, mlx 0.32.4
MODEL=$(pwd) sh runtime/run.sh                   # serves 127.0.0.1:8080, ~12 GB resident

Then ask one typed question β€” seven difficulty levels, read off the option letters:

python3 runtime/readout.py --state "fix the typo in the readme" \
  --instructions "Rate how hard this task is for an AI coding agent: how much focused work to finish well." \
  "trivial: a typo" "small: a quick edit" "routine: one focused change" "moderate: a feature, a few files" \
  "substantial: design across modules" "large: a refactor or migration" "huge: a multi-day build"
{"choice": "B",
 "probabilities": {"A": 0.266244, "B": 0.49741, "C": 0.207351, "D": 0.024765, "E": 0.002958, "F": 0.00096, "G": 0.000312},
 "prompt_tokens": 183, "ms": 374}

runtime/readout.py is stdlib-only and mirrors the upstream torchcast_shim.py prompt exactly. Any OpenAI-compatible client works the same way: max_tokens: 1, logprobs: true, top_logprobs: 11, chat_template_kwargs: {"enable_thinking": false}.

The readout protocol

The model answers with a letter. Recovery of a distribution is:

  1. Render the state, the instructions and Options: as A. …, B. …, then Answer with the letter of exactly one option, and nothing else: and send it as the user message, with the upstream system message ("You are a calibration engine…"). The scaffolding is load-bearing: without it the model answers in prose and no distribution over options exists.
  2. Read choices[0].logprobs.content[0].top_logprobs at the single output token.
  3. Sum exp(logprob) per letter. A letter can surface as several token ids (A, A, A.), so summing per letter β€” not picking one token β€” is what upstream specifies. The letters come from a bf16 lm_head, so their logprobs sit on a coarse grid and ties happen: a three-way exact tie (C = D = F = -1.25) is reproducible on some inputs. Take the expectation over the levels rather than the argmax alone if a tied pick matters. A long-running server also shifts these low-order bits through its warm prompt cache: restart it before recording numbers you intend to quote.
  4. Renormalize, and apply the per-type temperature from the bundled readout_config.json: score and choice 1.0, noul 0.2 (it fits calibration on public validation sets; do not re-tune it casually).

Types the checkpoint was trained for are noul (yes/no), choice (unordered options) and score (ordered options). Upstream's /v1/systemone wraps this protocol in HTTP; there is no equivalent here, see below.

The upstream /v1/systemone shim does not run on MLX

torchcast_shim.py and readout_config.json are included unchanged, but the shim cannot serve this copy. It needs two things mlx_lm.server does not provide: a structured_outputs letter mask on the upstream request (vLLM-specific, and load-bearing for the single-token answer), and an integer max_model_len in /v1/models. Pointed at MLX it exits at startup or returns 503 rather than answering. The MLX path is the client-side readout above, which is what the Pumpt! Claude Code mod does in production (runtime/readout.py is its Python equivalent, verified to reproduce the mod's distributions exactly).

Numbers, measured on an M5 Pro (48 GB, macOS)

  • Load: ~17 s to /v1/models. First decision after start ~4.7 s (kernel warm-up).
  • Warm decision: 100 ms fixed + ~1.1 ms per prompt token (900 tok/s prefill). 221-token prompt 402 ms; 402-token 593 ms; 931-token 1186 ms; a cached prefix 159 ms.
  • Resident memory ~11 GB. mlx_lm.server keeps an LRU prompt cache, so a constant system+instructions prefix is nearly free.

What was checked here, and what was not: three decisions recorded from a live session of the mod were re-run against this copy β€” same argmax every time, max|Ξ”p| between 0.0004 and 0.043 (the larger deltas come from context trimming, not the quantization). No bf16-vs-8-bit or MLX-vs-vLLM probability comparison exists. The upstream card's public-231 result (203/231, 87.88%) was measured on vLLM at bf16; it is not reproduced here, and 8-bit quantization can move calibrated probabilities β€” possibly toward over-confidence. If you depend on the calibration, measure the delta against the upstream bf16 artifact on the same inputs before trusting thresholds.

Limits

  • Text only. Images and audio were in the upstream checkpoint; this copy cannot take them.
  • top_logprobs is capped at 11 by mlx_lm.server, so this readout path reads up to 11 options (up to 26 with the upstream shim and SHIM_TOP_LOGPROBS=20).
  • The protocol is one answer per question. Multi-question / multi-span cases are served upstream by serving/decision_server.py and are not covered here.
  • English, decision-style inputs. The upstream card's intended-use and limitation notes apply unchanged.

Licence and attribution

Weights are CC BY-NC 4.0 β€” non-commercial use only, as upstream: they are a modified (8-bit quantized, text-only) copy of torchcast-ai/torchcast-decision-12b, which is a fine-tune of google/gemma-4-12B-it. Attribution to Torchcast AI (checkpoint), Google DeepMind (Gemma), and Cygnet/blockbrain-ai and NInfer (serving/readout foundation) is required; the changes made here are listed in NOTICE. LICENSE (the upstream CC BY-NC 4.0 text), LICENSE-gemma-Apache-2.0 and LICENSE-serving-MIT are carried over untouched β€” preserve them.

Use is also subject to Google's Gemma Prohibited Use Policy. The CC BY-NC label does not establish clearance of every training-source right; see the upstream card. This copy is not affiliated with Torchcast AI, Google, or the JevBench maintainers.

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

8-bit

Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Model tree for GenbaLabs/torchcast-decision-12b-mlx

Quantized
(385)
this model