Instructions to use JohnP1/d1a-e4b-it with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use JohnP1/d1a-e4b-it with PEFT:
from peft import PeftModel from transformers import AutoModel base_model = AutoModel.from_pretrained("google/gemma-4-E4B-it") model = PeftModel.from_pretrained(base_model, "JohnP1/d1a-e4b-it") - Notebooks
- Google Colab
- Kaggle
Configuration Parsing Warning:In adapter_config.json: "peft.base_model_name_or_path" must be a string
![]()
D1A-E4B-it v0.6
D1A is a small open decision model. One document and a set of typed questions go in (yes/no, choice, score), and a calibrated probability for every option comes out, in one forward pass, with no generated text. It speaks the TypeSafe System One API (POST /v1/systemone), so the TypeSafe SDK and existing clients work against it.
One model for decisions and chat. This is D1A-E2B-it v0.6's recipe on the larger instruction-tuned trunk, google/gemma-4-E4B-it. With the D1A adapter on it answers decisions; with the adapter off it is Gemma 4 E4B-it exactly, so one model in memory also serves OpenAI-format chat (Enable chat).
Measured against D1A-E2B-it v0.6 on every D1A suite (2026-10-17, both as served):
- accuracy up on 21 of 22 suites, pooled +2.5 points [+1.7, +3.4]: hard decisions +6.6, developer tools +3.2, long documents +2.3, JGLUE +2.2, PR labels (newer PRs) +1.8, and +5.1 on PR severity with the served decode offsets;
- the one significant loss is the unknowable-facts monitor (−2.9);
- about 2.9× slower per decision than E2B-it (a model about twice the size; p50 0.25 s on an M4 Mac mini);
- calibration is mixed (ECE better on 9 suites, worse on 12, all by ≤ 0.03).
<bos>: encode with it. The Gemma 4 -it tokenizers add no <bos>, but this model was trained with one at the start of every record. d1a from jonpol01/d1a#261 on puts it back (bos_token_id 2). If you encode requests yourself (another runtime, an app), prepend id 2; without it the answers are not the ones measured here.
D1A models: what each can do (2026-10-17)
| D1A-E4B-it v0.6 | D1A-E4B v0.6.1 | D1A-E2B v0.6.1 | D1A-E2B-it v0.6 | |
|---|---|---|---|---|
| Base model (trunk) | Gemma 4 E4B-it (instruction-tuned) | Gemma 4 E4B (pretrained base) | Gemma 4 E2B (pretrained base) | Gemma 4 E2B-it (instruction-tuned) |
Decisions (/v1/systemone) |
yes | yes | yes | yes (experimental) |
Photos, voice and video (MLX builds with media/) |
yes, zero-shot | yes, zero-shot | yes | yes |
| Chat / text generation | yes: unmerged build, adapter off = Gemma 4 E4B-it (Enable chat) | no | no | yes (same way) |
| Embeddings | from a GGUF embedder served beside it (D1A_EMBED_GGUF) |
— | — | same |
| Routing temperature | no (measured, not shipped) | yes, T 1.18 | yes, T 0.95 | no |
| Calibration temperature | 1.55 | 1.95 | 1.45 | 1.41 |
| Builds | PyTorch adapter JohnP1/d1a-e4b-it; MLX -mlx-q8 (7.0 GB with media) and -mlx-q4 (4.9 GB with media), both merged |
PyTorch, MLX 8-bit, Core ML int8 preview | PyTorch, MLX 8-bit, Core ML int8 | PyTorch adapter, MLX q8/q4, Core ML int8/int4 |
Kept current in the D1A repository: docs/MODELS.md.
What's inside
A LoRA adapter (rank 16 on the attention and MLP projections: q, k, v, o, gate, up, down) and a small pointer head (256-dimensional) on google/gemma-4-E4B-it at revision ee0ef602.
| Stage | Training data | Settings |
|---|---|---|
1. General decisions (recipes/d1a-e2b.yaml, what made E2B v0.2) |
decision-v7 suite: public classification datasets plus generated policy and rule data | 2 epochs, lr 1e-4, batch 4 × accum 2, from the -it trunk; not published |
| 2. Every later D1A skill, in one run (E2B v0.6's mix) | PR labels: 4,000 English (severity-stratified), 753 Japanese, 1,500 with a blast-radius label, and 479 hermes-agent PRs created 2026-10-02 to 10-05 shown twice (once in each half); hard-v1 4,000; devtools-v1 4,000; documents-v1 2,500; JGLUE 2,000; routing: agent factory 1,216, generic 1,000; decision-v7 replay 1,500: 23,427 records, none truncated | from stage 1, 1 epoch, lr 5e-5, states up to 5,120 tokens, 2,929 steps |
The mix is E2B v0.6's and E2B-it v0.6's, byte for byte (sha256 efff4b16), screened before training against every evaluation partition. Where it ran:
- Stage 1: steps 1–2,038 on one NVIDIA L4 (Hugging Face Jobs, bf16 autocast); steps 2,039–3,128 on an Apple M1 Max (MPS, fp32 forward), resumed from the saved step when the cloud job stopped.
- Stage 2: on the M1 Max (MPS, fp32 forward, bf16 frozen weights), finished 2026-10-17.
- LoRA and head master weights are fp32 on both machines, so only the forward precision changed between them.
provenance.jsonhas the details.
Calibration: a single temperature, T = 1.55 (90% interval [1.48, 1.62]), fitted on pooled rows of the decision-v7 calibration split and the PR-labelling development set (3,178 questions). Calibration error (ECE) is 0.057 before and 0.015 after, out of fold. It is stored in d1a_config.json.
No routing temperature. A routing-specific temperature (T 1.20) was fitted and not shipped: out of fold it did not separate from the general one, and on held-out transfer it made calibration worse (ECE 0.018 → 0.031). Routing requests use T 1.55, the same outcome as E2B-it.
Results
Every D1A suite, both models as served (MLX 8-bit, unmerged, each at its own temperature), on a Mac mini M4. Δ is paired with 95% bootstrap intervals; bold where the interval excludes 0.
| Suite | n | E2B-it v0.6 | E4B-it v0.6 | Δ [95% CI] |
|---|---|---|---|---|
| General decisions (decision-v7) | 1,264 | 84.8 | 85.7 | +0.9 [−0.7, +2.5] |
| Transfer (transfer-v4, sources never trained on) | 656 | 75.0 | 77.4 | +2.4 [−0.9, +5.9] |
| Hard decisions (hard-v1) | 1,083 | 69.2 | 75.7 | +6.6 [+4.0, +9.2] |
| Developer tools (devtools-v1) | 1,074 | 71.1 | 74.3 | +3.2 [+0.9, +5.4] |
| Long documents (documents-v1) | 920 | 86.3 | 88.6 | +2.3 [+0.5, +4.2] |
| Japanese JGLUE, development / test | 1,500 / 1,500 | 78.6 / 76.4 | 80.8 / 78.6 | +2.2 / +2.2 |
| PR labels, test (newer PRs): severity / type / blast | 953 / 953 / 139 | 70.5 / 87.8 / 52.5 | 72.9 / 88.4 / 58.3 | +2.4 / +0.5 / +5.8 |
| PR severity with the served decode offsets | 953 | 64.3 | 69.5 | +5.1 [+3.0, +7.3] |
| PR labels, Japanese test | 193 | 74.6 | 77.7 | +3.1 [−1.0, +7.2] |
| Routing: agent factory / generic / hand-labelled | 640 / 270 / 45 | 92.3 / 97.0 / 100 | 93.6 / 97.4 / 100 | +1.2 / +0.4 / 0.0 |
| External: TypeSafe / wanli-v2 | 102 / 1,002 | 69.6 / 68.9 | 86.3 / 72.7 | +16.7 / +3.8 |
| Dates (monitor) | 900 | 87.0 | 90.8 | +3.8 [+1.7, +5.8] |
| Unknowable facts (monitor) | 525 | 69.5 | 66.7 | −2.9 [−5.5, −0.2] |
The live PR-labeler replay (98–193 questions) is flat on type and down on blast radius (64.3 → 58.2, not significant at this n). Against the older D1A-E4B v0.6.1 the comparison is indirect (both measured against E2B-it): E4B-it is ahead on decision-v7, transfer, hard and developer tools, and 1–2 points behind on long documents, JGLUE and dates.
Photos, voice and video
With the media extra, d1a.serving.serve answers questions about a photo, a voice clip or a video through Gemma 4 E4B-it's own vision and audio encoders, unchanged by the adapter (POST /v1/systemone/media). No media in training (zero-shot).
Measured on the playground's 14 photo, voice and video demo requests (28 answers): all answered. 7 answers differ from E2B-it v0.6; read by hand, 6 are better (it now calls the crushed-truck photo and video damaged, places the intact mailbox photo "in a mailbox", and no longer calls the English directions and Japanese not-at-home voice clips urgent) and 1 is worse (the intact front-door photo placed "on a sidewalk").
The questions it was trained for
PR labelling works best with these questions, worded exactly so, over a document of the form title / author / stats / body / files (one - status path +added/-deleted line per file):
type(choice): "Primary change type from files and body, not the title prefix." Options: type/bug, type/docs, type/feature, type/perf, type/refactor, type/security, type/test.blast(choice): "How far a mistake in this PR spreads in production." Options: review:blast-contained (one module), -moderate (one subsystem), -broad (shared helper or config), -massive (auth, permissions, or all paths).sev(choice): "How serious the problem this PR addresses is — not the risk of merging the diff as-is." Options P0 to P4.
The PR-labeler recipe has the exact wording, the document builder and the training and scoring scripts.
Run it
Needs d1a with jonpol01/d1a#261 (the <bos> above):
pip install "d1a[serve] @ git+https://github.com/jonpol01/d1a"
python -m d1a.serving.serve --run JohnP1/d1a-e4b-it@v0.6 --port 8009
or in-process: from d1a import D1A; D1A.load("JohnP1/d1a-e4b-it@v0.6").decide(state, questions). Builds of the same model: MLX 8-bit JohnP1/d1a-e4b-it-mlx-q8 and MLX 4-bit JohnP1/d1a-e4b-it-mlx-q4, both with the photo, voice and video encoders and both merged (decisions only).
Enable chat
With its D1A adapter switched off, this model is Gemma 4 E4B-it, so one model in memory can answer D1A decisions (adapter on) and OpenAI-format chat (adapter off). This needs an unmerged build: the published MLX repos have the adapter merged into their weights and cannot chat. No chat build is published; build one from this adapter on Apple Silicon (downloads the E4B-it base, ~16 GB), with d1a from jonpol01/d1a#276 on:
git clone https://github.com/jonpol01/d1a && cd d1a
uv run --extra serve python scripts/export_mlx.py --run JohnP1/d1a-e4b-it@v0.6 --q-bits 8 --q-group-size 64 \
--unmerged --media --out runs/exports/d1a-e4b-it-chat
Serve it, with embeddings if your app needs them (mem0 does; the GGUF is nomic-ai/nomic-embed-text-v1.5-GGUF, file nomic-embed-text-v1.5.Q4_K_M.gguf, the one LM Studio serves):
uv sync --extra serve --extra embed
D1A_EMBED_GGUF=<path to nomic-embed-text-v1.5.Q4_K_M.gguf> \
uv run --extra serve python -m d1a.serving.serve --run runs/exports/d1a-e4b-it-chat --port 8009
Then point any OpenAI client at http://localhost:8009/v1: POST /v1/chat/completions (streaming, tools, JSON mode by prompt), POST /v1/embeddings and GET /v1/models. Any model id is answered by this one model. Decisions stay on /v1/systemone with the adapter on. With d1a from jonpol01/d1a#291 on, a decision that arrives during a chat is answered between two of its tokens (0.24 s on this model during a 200-token answer, instead of waiting for the whole answer), and the chat's text is unchanged. Details: Chat with D1A.
Limits
- Slower than E2B-it: about 2.9× the model time per decision. Use E2B-it or E2B where latency matters more than accuracy.
- Calibration is mixed against E2B-it: ECE worse on 12 suites (largest +0.028 on Japanese PR test), better on 9.
- Unknowable facts (questions whose answer is not in the document): −2.9 against E2B-it.
- Gate tool calls through D1A's fail-safe thresholds (
d1a.agents.presets.advise: deny at p ≥ 0.5, allow only at p ≥ 0.8, otherwise ask), never through the raw top answer. <bos>: requests encoded without the leading id 2 are out of distribution (see above).- Media: zero-shot, measured on the playground's demo requests only.
- One temperature for every question, and no use-case temperatures (the routing one was measured and not shipped).
- The recent PR labels come from one large open-source project and a few days of it. If its conventions move again, so will these numbers.
- Questions are in English. The documents can be English or Japanese (trained on both).
Versions
| Tag | What it is |
|---|---|
v0.6 |
E2B v0.6's recipe on the Gemma 4 E4B-it trunk; decisions and chat in one model |
License and data
Apache-2.0. Base model: Gemma 4 by Google (Apache-2.0). Code: github.com/jonpol01/d1a, built on Kev by Jared Palmer (Apache-2.0). Japanese decision data derived from JGLUE by Yahoo Japan Corporation and Waseda University (CC BY-SA 4.0). Pull-request data from NousResearch/hermes-agent (MIT); the labelled PR dataset itself, including the recent PRs, is private.
- Downloads last month
- 10