Instructions to use jbrashear/jebadiah-9b-v0 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use jbrashear/jebadiah-9b-v0 with PEFT:
from peft import PeftModel from transformers import AutoModelForCausalLM base_model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3.5-9B-Base") model = PeftModel.from_pretrained(base_model, "jbrashear/jebadiah-9b-v0") - Notebooks
- Google Colab
- Kaggle
Jebadiah 9B v0
Jebadiah (Jeb for short) is an open System One style decision model: it answers typed questions with a
calibrated probability over the option labels instead of generating text. Three question types, the
same three Jev uses: choice (pick one of N), noul (a yes or no statement, returned as P(yes)) and
score (place the state on an ordered rubric). It is trained with AINode's trainer on public data only
and served by AINode's /v1/decide and /v1/systemone routes on any NVIDIA GPU. The routes answer Jev's three question types; the request schema is AINode's own (documented on the route), not Jev's exact wire format.
This repository holds the v0 9B adapter: a LoRA on Qwen/Qwen3.5-9B-Base (pinned revision
68c46c4b), one epoch over 11,072 public training questions, trained on one H100 PCIe in 45 minutes.
Its 4B sibling is jbrashear/jebadiah-4b-v0.
v0 is a fixed version. Newer versions are published as new repositories and never replace this one.
v1 is out: jbrashear/jebadiah-9b-v1, with human-rubric training data and the ordinal score fix.
Made in Texas.
Results
Measured by us with AINode's bench, one logit read per question, the same rendered prompt for every model. Accuracy is the share of questions whose top label is the human label. Decision Score is Jevals' metric: 100 = perfect, 0 = guessing the label base rates, below 0 = worse than that. These are our numbers on the public suites, not rows on the Jevals board.
| Set (questions) | Type | Accuracy | Floor (majority label) | Decision Score (Jevals) | ECE, temperatures applied | Flips over identical repeats |
|---|---|---|---|---|---|---|
| Jevals PubMedQA (300) | noul | 89.0 | 62.0 | 64.0 | 0.048 | 0.0% |
| Jevals Banking77 (300, 77 options) | choice | 71.0 | 1.3 | 57.6 | 0.124 | 0.3% |
| Jevals HelpSteer2 helpfulness (300, 5 levels) | score | 40.3 | 41.7 | -21.4 | 0.392 (raw 0.201) | 1.0% |
| Nimble held-out eval (324) | mixed | 76.9 | 17.6 | 64.2 | 0.078 | 0.3% |
| Kev transfer-v4 test (764) | mixed | 83.0 | 21.5 | 64.5 | 0.075 | 0.0% |
| Kev decision-v7 test (1,440) | mixed | 80.5 | 20.3 | 67.6 | 0.120 | n/a |
| typed-decisions test (2,000) | mixed | 79.4 | 15.3 | 60.9 | 0.061 | 0.2% |
Nimble's 13 public human-labelled subsets (3,880 questions), macro accuracy: 75.0 (per subset: aegis2 78.0, boolq 85.3, civil_comments 85.3, helpsteer2 37.3, massive-de-DE 83.7, massive-en-US 85.4, multinli 85.0, paws 81.6, pubmedqa 72.4, squad2 76.6, summeval-consistency 80.6, summeval-relevance 49.2, vitaminc-dev 74.6). For scale, Bespoke's published table puts Nimble-9B at 74.8 and Jev at 76.0 on the same subsets with their scorer, and the untrained 4B base at 65.7 with ours.
Where it is weak: the score type on human rubrics. HelpSteer2 helpfulness and summeval-relevance sit at their floors, and the fitted score temperature (0.39, a sharpening learned from soft teacher targets) makes HelpSteer2's calibration worse rather than better. That is the first thing v1 changes.
Every eval record (per question: option keys, probabilities, pick, label, repeat, option order) is in
eval/, with eval/results.json carrying the full metric set (Brier, NLL, ECE raw and fitted,
per-question floors, flips with their top-2 gaps) and the resolved training configuration.
How it decides
The prompt is AINode's own decide rendering (ainode.api.decide.build_messages, source commit
e5c08938, prompt_source_sha256 d2660ebe... in prompt_contract.json), through the base chat template
with thinking off. The question's state, instructions and options are rendered as structured text; the
option labels are single tokens (68 of them); the model's answer is the distribution over those label
tokens at the last prompt position, read in fp32 from the last hidden state and then temperature scaled
per type (temperatures.json: choice 0.90, noul 0.91, score 0.39, fitted on a held-out calibration
slice of the training pool). Nothing is generated.
The supported way to run it is AINode, which renders the prompt exactly as trained:
curl -sS https://<your-ainode>/v1/systemone -H "Authorization: Bearer <key>" -H "Content-Type: application/json" -d '{
"model": "jebadiah/jebadiah-9b-v0",
"state": {"ticket": "Customer says the invoice total does not match the quote."},
"questions": {
"route": {"type": "choice", "instructions": "Which team should take this ticket?", "criteria": {"billing": "an invoice, a charge or a refund", "support": "a product question", "sales": "a quote or a renewal"}},
"urgent": {"type": "noul", "instructions": "The customer is blocked from working.", "criteria": {"true": "work has stopped", "false": "it can wait"}}
}
}'
The route takes questions as an object keyed by your id, with type, instructions and criteria (choice and score: name to description; noul: an optional true and false description). Served through AINode at temperature zero with a constrained single token, the picks and the confidences are identical across repeats; the flip rates in the table above come from the local batched logit read, which sees bf16 ties the route does not.
Standalone with transformers and peft (the label tokens, rendering and fp32 read must match the
contract; see prompt_contract.json and the AINode source for the renderer):
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel
base = "Qwen/Qwen3.5-9B-Base"
tok = AutoTokenizer.from_pretrained(base, revision="68c46c4b3498877f3ef123c856ecfde50c39f404")
model = AutoModelForCausalLM.from_pretrained(base, revision="68c46c4b3498877f3ef123c856ecfde50c39f404", torch_dtype=torch.bfloat16, device_map="cuda")
model = PeftModel.from_pretrained(model, "jbrashear/jebadiah-9b-v0").eval()
messages = [{"role": "user", "content": "<the AINode decide rendering of state, question and options>"}]
ids = tok.apply_chat_template(messages, add_generation_prompt=True, enable_thinking=False, return_tensors="pt").to("cuda")
with torch.no_grad():
h = model(ids, output_hidden_states=True).hidden_states[-1][0, -1].float()
labels = ["A", "B", "C"] # the option labels the rendering assigned
label_ids = [tok.encode(l, add_special_tokens=False)[0] for l in labels]
W = model.get_output_embeddings().weight[label_ids].float()
probs = torch.softmax((W @ h) / 0.90, dim=0) # choice temperature from temperatures.json
Thresholds belong to the caller: act on a high probability, confirm or escalate on a middle one, hand a low one to a person or a bigger model. The model never refuses; policy is built from decisions.
Training
- Objective: cross-entropy over the candidate option-label logits at the answer position, with the source's gold distribution as the target where it provides one (typed-decisions) and the hard label otherwise. No text generation is trained.
- Adapter: LoRA r=16, alpha=32, dropout 0.05 on every linear projection including the Gated DeltaNet
projections (
in_proj_qkv,in_proj_z,in_proj_a,in_proj_b,out_proj, plus the attention and MLP projections), 43.3M trainable parameters. bf16, SDPA attention, micro-batch 8, learning rate 1e-4, one epoch, 1,384 steps, gradient checkpointing. - Data (public only):
LocalLLaMA/typed-decisionstrain (Apache-2.0, revisionea930645) and the Kev v7 training sources whose licenses permit derived weights (BoolQ, MNLI, DBpedia14 and Kev's contrastive and composition sets, Kev suites revisiona88f56db). 11,072 training and 272 calibration questions after a 95/5 split by question family. Nimble's train set is excluded (no license stated); the Jevals test sources are excluded from training. No private data of any kind. - Compute: one NVIDIA H100 PCIe 80 GB, 45 min training, 26 min evaluation, torch 2.11, PEFT 0.21.
Limitations
- Single-hop judgments only. A question that hides a chain of inference should be split into hops.
- The score type is not yet trained on human helpfulness rubrics; treat score outputs on such rubrics as uncalibrated until v1.
- AINode caps a choice question at 20 options; Banking77's 77 options were scored with an extended single-token alphabet for the benchmark only.
- English data. Massive's German subset scores well, but nothing else was checked.
- Calibration was fitted on the training distribution. Refit the temperatures on your own data before trusting a threshold.
Versioning and license
v0 is frozen. Later versions land as jebadiah-<size>-v<N> repositories. The adapter is Apache-2.0,
the base model is Apache-2.0. Evaluation data: Jevals suite 0.1.0 (CC-BY-4.0, "Jevals (jevals.com),
release 2026-09-18"), Nimble public subsets (Bespoke Labs), Kev test sets and typed-decisions test,
each under its own license.
- Downloads last month
- -
Model tree for jbrashear/jebadiah-9b-v0
Base model
Qwen/Qwen3.5-9B-BaseDataset used to train jbrashear/jebadiah-9b-v0
Evaluation results
- accuracy on Jevals suite 0.1.0, PubMedQA (noul)self-reported89.000
- decision_score_jevals on Jevals suite 0.1.0, PubMedQA (noul)self-reported64.000
- accuracy on Jevals suite 0.1.0, Banking77 (choice, 77-way)self-reported71.000
- decision_score_jevals on Jevals suite 0.1.0, Banking77 (choice, 77-way)self-reported57.600
- accuracy on Nimble public human-labelled subsets (13, macro accuracy)self-reported75.000