Jebadiah 9B v0

They call me Jeb. Jebadiah 9B, a Texas-made open model. He does not talk much. He just decides.

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-decisions train (Apache-2.0, revision ea930645) and the Kev v7 training sources whose licenses permit derived weights (BoolQ, MNLI, DBpedia14 and Kev's contrastive and composition sets, Kev suites revision a88f56db). 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
-
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for jbrashear/jebadiah-9b-v0

Adapter
(35)
this model

Dataset used to train jbrashear/jebadiah-9b-v0

Evaluation results

  • accuracy on Jevals suite 0.1.0, PubMedQA (noul)
    self-reported
    89.000
  • decision_score_jevals on Jevals suite 0.1.0, PubMedQA (noul)
    self-reported
    64.000
  • accuracy on Jevals suite 0.1.0, Banking77 (choice, 77-way)
    self-reported
    71.000
  • decision_score_jevals on Jevals suite 0.1.0, Banking77 (choice, 77-way)
    self-reported
    57.600
  • accuracy on Nimble public human-labelled subsets (13, macro accuracy)
    self-reported
    75.000