jaredpalmer/kev: tiny Jev-like household of choice fashions constructed on prime of Qwen3.5 you’ll be able to prepare and run by yourself · GitHub


Small Jev-like choice fashions you’ll be able to prepare and run your self.


Weights: Kev-0.8B · 4B · 9B
Frozen eval suites
Research log
License: Apache-2.0

Kev is a household of small choice fashions constructed on Qwen3.5 and primarily based on the structure described in Jev’s Architecture Unmasked. You can use the pretrained weights or prepare your individual. The API matches TypeProtected’s System One, so you’ll be able to level their Python SDK at your native server.

  • 0.8B, 4B, and 9B fashions, with coaching code and analysis information.
  • Yes/no (noul), multiple-choice (alternative), and score (rating) questions in the identical request.
  • Questions share the enter textual content however cannot learn one another.
  • Runs on CUDA and Apple Silicon. The 4B and 9B fashions match a 32 GB Mac utilizing bf16; see Serving Performance for what to anticipate on a Mac.
  • An internet playground for making an attempt your individual inputs and checking how choice order impacts the solutions.

Kev playground

You’ll want Python 3.12+ and uv.

git clone https://github.com/jaredpalmer/kev.git && cd kev
uv sync --extra serve
KEV_DTYPE=bf16 uv run --extra serve python -m kev.serve --run jaredpalmer/kev-4b --port 8009

This begins Kev-4B regionally. The first run downloads the adapter and base mannequin. --run additionally accepts an area checkpoint listing or a Hub revision, comparable to jaredpalmer/kev-4b@qwen3 for the earlier era.

In one other terminal, ship it a ticket:

curl -s localhost:8009/v1/systemone -H 'content-type: software/json' -d '{
  "state": "Shoes arrived two weeks late and within the flawed measurement. Also I see two costs on my card.",
  "mannequin": "kev-latest",
  "questions": {
    "division":  {"sort": "alternative", "directions": "Which staff ought to deal with this?",
                    "standards": {"returns": "Exchanges, refunds, flawed or broken objects",
                                 "transport": "Delivery standing, delays, misplaced packages",
                                 "billing": "Charges, invoices, fee issues"}},
    "escalate":    {"sort": "noul",  "directions": "Does this want pressing human consideration?"},
    "frustration": {"sort": "rating", "directions": "How annoyed is the shopper?",
                    "standards": ["Calm", "Frustrated", "Very angry"]}
  }}'

Example response from Kev-4B, operating in bf16 on an Apple M5:

{
  "mannequin": "kev-latest",
  "solutions": {
    "division":  { "sort": "alternative", "alternative": "returns", "confidence": 0.21,
                     "possibilities": { "returns": 0.47, "transport": 0.28, "billing": 0.25 } },
    "escalate":    { "sort": "noul", "noul": 0.93 },
    "frustration": { "sort": "rating", "rating": 1.44, "confidence": 0.78,
                     "legend": { "0": "Calm", "1": "Frustrated", "2": "Very offended" },
                     "possibilities": { "0": 0.00, "1": 0.56, "2": 0.44 } }
  },
  "utilization": { "input_tokens": 101, "output_tokens": 161 },
  "latency_ms": 495
}

The ticket mentions a return, a late supply, and a billing downside, and the division possibilities say so. That is the purpose of getting possibilities again as an alternative of a single label.

The TypeProtected SDK is included in uv sync --extra serve:

from typesafe_sdk import Choice, Noul, Score, TypeSafeClient

shopper = TypeSafeClient(
    api_key="native",
    base_url="http://127.0.0.1:8009",
    mannequin="kev-latest",
)
response = shopper.system_one(
    state="I used to be charged twice. Please repair this ASAP.",
    questions={
        "billing": Noul(directions="Is this ticket about billing?"),
        "tone": Choice(
            directions="What is the shopper's tone?",
            standards={"calm": None, "annoyed": None, "offended": None},
        ),
        "urgency": Score(
            directions="How pressing is that this ticket?",
            standards=["can wait", "this week", "today"],
        ),
    },
)
print(response.nouls["billing"].noul)
print(response.selections["tone"].alternative)
print(response.scores["urgency"].rating)

With the server nonetheless operating, open one other terminal. You’ll want Node 20.9+:

cd playground
npm set up
npm run dev -- -p 3001

Open localhost:3001, load a preset, and edit the textual content and questions. Press ⌘↵ to run it. “Packed vs separate” compares asking all questions without delay with asking them separately. “Permute” runs a Choice query with six choice orders. There are additionally presets for testing query isolation and pretend delimiter tokens.

There’s a chess demo, too. The board is the enter, authorized strikes are Choice choices, and a Score query charges the place. You can play towards Kev or let it play itself. Games are saved in localStorage.

Kev chess

Start with Kev-4B. Use Kev-9B when accuracy and calibration matter greater than reminiscence. Use Kev-0.8B in the event you want the smallest mannequin. All three are constructed on Qwen3.5 bases with the identical coaching information and settings.

Model Base Accuracy: Trained Sources Accuracy: New Sources Brier: New Sources Model Card
Kev-0.8B Qwen3.5-0.8B-Base 0.829 / 0.827 0.643 / 0.668 0.513 / 0.473 Details
Kev-4B Qwen3.5-4B-Base 0.877 / 0.870 0.794 / 0.832 0.316 / 0.266 Details
Kev-9B Qwen3.5-9B-Base 0.876 / 0.873 0.812 / 0.837 0.291 / 0.243 Details
Jev Hosted 0.845 / – 0.857 / – 0.211 / –

Each cell is improvement / take a look at. “Trained sources” means held-out examples from the datasets used to coach Kev. “New sources” means datasets and coverage rule varieties Kev wasn’t skilled on. Every mannequin was evaluated on the identical improvement units (decision-v7, transfer-v4) and the identical take a look at units, which had been learn as soon as per launched checkpoint, after mannequin choice. Lower Brier is best.

Kev-9B trails Jev by about 4.5 factors on the new-source improvement set. We do not know which datasets Jev was skilled on, so this is not a managed comparability of the 2 architectures.

Accuracy by source for Kev and Jev

All weights are within the Kev collection and the GitHub release, which incorporates tarballs and SHA-256 checksums.

Previous era (Qwen3) and the prototype

The first Kev household used Qwen3 bases with the identical information and settings. Those weights keep revealed and are the quicker alternative on a Mac (see Serving Performance), however they’re not developed.

Model Base Accuracy: Trained Sources Accuracy: New Sources Brier: New Sources Model Card
Kev-0.6B (Qwen3) — jaredpalmer/kev-0.6b Qwen3-0.6B-Base 0.801 / 0.808 0.620 / 0.642 0.536 / 0.483 Details
Kev-4B (Qwen3) — jaredpalmer/kev-4b@qwen3 Qwen3-4B-Base 0.854 / 0.856 0.790 / 0.806 0.328 / 0.294 Details
Kev-8B (Qwen3) — jaredpalmer/kev-8b Qwen3-8B-Base 0.863 / 0.870 0.796 / 0.780 0.337 / 0.327 Details

Because solely the bottom modified, the 2 generations are a managed comparability. On the event set the accuracy achieve is inside noise; on the take a look at set Kev-9B is 7.3 factors forward of Kev-8B (95% CI +2.8 to +11.7) with a Brier rating 0.08 decrease, Kev-4B is 2.9 factors forward of its predecessor (−0.9 to +6.4), and Kev-0.8B is 4.8 factors forward of Kev-0.6B (+0.2 to +9.3). PLAN_Qwen35.md has the complete experiment, together with the standards we set prematurely and the way the outcomes measured towards them.

The unique Kev-0.5B used Qwen2.5-0.5B and is stored for reference; see its model card.

state is the textual content to judge. Each query has directions and, the place wanted, a set of solutions to select from.

Type Criteria Answer
noul Optional descriptions for true and false noul: likelihood of sure
alternative 1–255 choice names, every with an outline or null alternative: almost certainly choice; possibilities and confidence
rating 2–255 descriptions, ordered from lowest to highest rating: imply stage index, beginning at 0; legend, possibilities, and confidence

For Choice with Okay > 1 choices, confidence is (p_max − 1/Okay) / (1 − 1/Okay). A single choice has confidence 1. Score confidence measures how shut the distribution is to its almost certainly stage. It’s an approximation of TypeProtected’s method, which is not public. Neither area is a measured accuracy fee.

Objects and arrays are transformed to labeled textual content. Delimiter-like strings in person enter are escaped earlier than tokenization. Invalid requests return 422. utilization.output_tokens counts tokens within the serialized solutions, not generated tokens.

Method Path Purpose
GET /v1/fashions Loaded mannequin and checkpoint info
POST /v1/systemone/permute Run one Choice query with totally different choice orders
POST /v1/systemone/separate Run every query in its personal ahead go

The server binds to 127.0.0.1 and has no authentication. Keep it native except you add authentication your self.

Each checkpoint is a rank-16 LoRA adapter and a small pointer head on a Qwen base mannequin. On an attention-only base (Qwen3), the state and questions go into one token sequence:

 …state…
 directions  choice 1   choice 2 
 directions  choice 1   choice 2 

The consideration masks lets a token learn the state and its personal query, however not different questions or future tokens. Each query’s place IDs restart simply after the state. This lets the mannequin course of the state as soon as and reply every query independently.

Qwen3.5 mixes consideration layers with Gated DeltaNet layers, that are recurrent and ignore consideration masks. For these fashions, every query runs as its personal row: the state adopted by that query, with the identical positions as above. The rows are unbiased, so isolation is precise, and the server computes the state as soon as and reuses its cache for each row. On attention-only fashions the 2 kinds give similar possibilities (assessments/test_v3.py).

The pointer head scores every choice’s hidden state towards the query’s hidden state. A softmax turns these scores into possibilities. Because comes final, it could possibly attend to the complete choice checklist.

Training makes use of cross-entropy on the proper reply. The adapter and head are skilled collectively; the remainder of the bottom weights keep mounted. Training examples and API requests use the identical textual content format. No Jev outputs had been used for coaching.

Asking questions collectively or individually produces possibilities inside 4e-6 within the fp32 assessments. This does not imply choice order is irrelevant: choices inside a query can nonetheless have an effect on each other. See the model code and parity tests.

On CUDA, set up flash-linear-attention for the Qwen3.5 fashions (the Modal picture does this); a five-question request takes tens of milliseconds on an H100.

On Apple Silicon there are not any quick kernels for the DeltaNet layers, so PyTorch runs reference code. Median mannequin time in bf16 on an M5, 5 questions with three choices every on a ~230-token state:

Model Time Previous era on the identical request
Kev-0.8B 329 ms Kev-0.6B (Qwen3): 123 ms
Kev-4B 779 ms Kev-4B (Qwen3), jaredpalmer/kev-4b@qwen3: 174 ms
Kev-9B about 2 s Kev-8B (Qwen3): about 300 ms

If you serve on a Mac and wish low latency, use the Qwen3 fashions for now. An MLX backend for the Qwen3.5 fashions is the subsequent deliberate change.

For the attention-only fashions the server merges the LoRA weights in fp32 earlier than casting, makes use of SDPA consideration on Apple GPUs, pads MPS inputs to 64-token buckets, and caches the state prefix for repeated requests (4 states of at the least 384 tokens by default). With a repeated 772-token state, Kev-4B (Qwen3) solutions in 242 ms as an alternative of 861 ms.

You can disable these with KEV_MERGE=0, KEV_ATTN=keen, KEV_SHAPE_BUCKET=1, and KEV_PREFIX_CACHE=0. On 24 new-source information, bf16 possibilities differed from fp32 by at most 0.017, with no change within the highest-probability reply. That is a small verify, not a assure for each enter.

The launched fashions use decision-v7: 10,000 examples from ten public datasets, 896 generated coverage examples, and 1,680 examples from 60 generated rule constructions. All prepare for 2 epochs with LoRA rank 16 and cross-entropy. The studying fee is 1e-4 for 0.8B and 5e-5 for 4B/9B. For Qwen3.5 bases the adapter additionally covers the DeltaNet projections; kev.prepare picks the proper targets from the mannequin config.

# sanity run, ~1 minute
uv run python -m kev.prepare --n_per_source 40 --accum 4 --out runs/smoke

# Kev-0.8B (~20 min on one H100; the Mac path works however is gradual for Qwen3.5 bases)
uv run python -m kev.prepare --suite evals/v7/decision-v7 --base Qwen/Qwen3.5-0.8B-Base --base_revision dc7cdfe2ee4154fa7e30f5b51ca41bfa40174e68 
    --epochs 2 --lr 1e-4 --batch 8 --dtype bf16 --p_none_pair 0.25 --device cuda --out runs/kev-0.8b

# the Kev-4B recipe (one H100 by way of Modal, ~1 h; see under). Swap in Qwen/Qwen3-4B-Base for the earlier era.
uv run python -m kev.prepare --suite evals/v7/decision-v7 --base Qwen/Qwen3.5-4B-Base --base_revision 1001bb4d826a52d1f399e183466143f4da7b741b 
    --epochs 2 --lr 5e-5 --batch 4 --accum 2 --dtype bf16 --checkpointing 1 --p_none_pair 0.25 --device cuda --out runs/kev-4b

Fine-tuning by yourself information

The launched fashions had been skilled on public datasets and generated coverage examples. If your questions look totally different — your individual routing classes, your individual escalation guidelines, one other language — a brief fine-tune on a number of hundred labelled examples often helps greater than any immediate change.

Put your examples in a JSONL file, one request per line. It’s the identical form as an API request, plus a label on each query:

{"state": {"topic": "Charged twice", "physique": "I see two costs for order #4411. Please refund one."},
 "questions": {
   "staff":     {"sort": "alternative", "directions": "Which staff ought to deal with this ticket?",
                "standards": {"billing": "Payments and refunds", "transport": "Delivery issues", "entry": "Login and account entry"}, "label": "billing"},
   "offended":    {"sort": "noul",   "directions": "Is the shopper offended?", "label": false},
   "precedence": {"sort": "rating",  "directions": "How pressing is that this ticket?", "standards": ["low", "normal", "high"], "label": 1}}}

For alternative the label is the choice identify, for noul it is true or false, and for rating it is the extent’s place beginning at 0. Keep 10–20% of the file apart for analysis.

Then begin from a launched checkpoint with --init_from:

uv run python -m kev.prepare --data prepare.jsonl --base Qwen/Qwen3.5-4B-Base --init_from jaredpalmer/kev-4b 
    --epochs 2 --lr 2e-5 --batch 1 --accum 8 --dtype bf16 --checkpointing 1 --device cuda --out runs/mine

uv run python -m kev.benchmark --run runs/mine --data heldout.jsonl --out runs/mine-eval
KEV_DTYPE=bf16 uv run --extra serve python -m kev.serve --run runs/mine --port 8009

--init_from hundreds the adapter and pointer head from the launched mannequin earlier than coaching, so you retain what Kev already is aware of and add your area on prime. Starting from the bottom mannequin as an alternative throws that away: in a single person’s take a look at on 836 support-tool selections, a fine-tune from the bottom scored 0.33 on Kev’s personal analysis set, towards 0.84 for the launched mannequin; the identical information with --init_from stored 0.83 there and reached 0.88 on the brand new area. Use a smaller studying fee than the from-scratch recipe (2e-5 is an effective begin), and decide --base to match the checkpoint you begin from; the coach checks that the bottom, revision, LoRA rank, and head measurement agree earlier than it hundreds something.

--batch 1 --accum 8 in bf16 suits the 0.8B mannequin on a 4 GB GPU. The benchmark reviews accuracy, Brier rating, and calibration per query sort, so you’ll be able to see which of your questions the fine-tune helped. The checkpoint you began from is recorded in runs/mine/training_config.json.

Use uv run python -m kev.prepare --help for all coaching choices. The launched fashions do not use the optionally available --perm_kl or --ord_w losses. The model cards have the coaching settings and dataset lists; PLAN.md information what was tried and what helped.

On a Mac, run one coaching job at a time. Two jobs on the identical Apple GPU are a lot slower. Use Modal for longer runs.

Each trial will get its personal H100. The examine retains operating in the event you disconnect, and you may obtain the outcomes when it finishes:

uv run modal token new                                    # as soon as; opens the browser
KEV_GPU=T4 uv run modal run modal_app.py::smoke           # end-to-end verify, ~1 minute of GPU

uv run modal deploy modal_app.py                          # as soon as; research run on the deployed app and survive disconnects
uv run modal run modal_app.py::examine 
    --suite evals/v7/decision-v7 --plan experiments/v7-final.json 
    --name my-study --transfer evals/v4/transfer-v4 --budget 30 --timeout 7200
uv run modal run modal_app.py::pull --name my-study       # outcomes -> runs/my-study, ranked

Study plans checklist coaching settings. Each trial saves the settings, code hashes, dataset hashes, and outcomes. Choose fashions utilizing the event outcomes, not the locked take a look at. After selecting a last candidate, you’ll be able to learn its take a look at outcomes as soon as:

uv run modal run modal_app.py::locked_test --trial my-study/00-trial-0 --name my-candidate   # one learn, ever

The analysis information below evals/ is frozen: dataset variations and file checksums are recorded in every manifest. Large coaching recordsdata are downloaded from the Hub mirror and checked towards these hashes.

uv run python -m kev.benchmark --run jaredpalmer/kev-4b --suite evals/v4/transfer-v4 --out runs/my-eval      # out of area
uv run python -m kev.benchmark --run jaredpalmer/kev-4b --suite evals/v9/transfer-v9 --out runs/my-eval-v9   # + MMLU-Pro, buried states, unknowable objects
uv run python -m kev.benchmark --run jaredpalmer/kev-4b --suite evals/v7/decision-v7 --out runs/my-eval-id   # in distribution
uv run python -m kev.benchmark --remote http://127.0.0.1:8009 --suite evals/v4/transfer-v4 --out runs/my-remote   # any System One endpoint

These instructions use improvement information. Test information requires --allow-test. The benchmark reviews accuracy, Brier rating, calibration error, the share of choices you would automate at a 5% error price range, option-order modifications, and query isolation. transfer-v9 provides 10-way MMLU-Pro, information buried amongst unrelated textual content, and “unknowable” information whose deciding proof was eliminated; for these it reviews how typically the mannequin nonetheless solutions with at the least 0.9 confidence (Kev-9B 5%, Jev 9%, Kev-8B 26%). Published accuracy numbers use fp32 analysis, not the bf16 serving path.

evals/exterior/ holds two different tasks’ take a look at units transformed to this format, with their revealed stay Jev outcomes: SemIf‘s 144 authored selections (Kev-9B 0.917, Jev 0.965) and scienthoon‘s 900 help tickets (Kev-9B 0.952 on routing and 0.911 on tone, Jev 0.897 and 0.914).

kev.jev runs the identical questions towards Jev via Vercel AI Gateway. kev.examine compares two saved runs with paired bootstrap confidence intervals. For the complete experiment historical past, see PLAN.md and the leaderboard.

  • Probabilities aren’t nicely calibrated on new sources. On the new-source improvement set, Kev-4B assigns at the least 0.9 likelihood to a flawed reply on 8.2% of questions (Kev-9B: 7.5%). Test it by yourself information earlier than selecting a likelihood threshold.
  • Fine-tuning could make the bottom mannequin worse at particular person duties. Date arithmetic is the clearest case: the untrained Qwen3.5-9B base will get 0.82 on the deadline coverage questions and Kev-9B will get 0.72, as a result of coaching erodes the talent (issue #8, PLAN_Qwen35.md). Knowledge questions (MMLU 0.74 vs Jev 0.90) are the opposite massive hole.
  • The present fashions are gradual on Apple Silicon (see Serving Performance) and wish transformers >= 5.17.
  • Changing choice order can change a solution. Question isolation would not forestall this.
  • Training makes use of at most 384 state tokens and 1,024 tokens for the state plus one query. Serving permits 8,192 tokens for the state plus one query; longer context wasn’t lined by coaching.
  • The server handles one request at a time. It caches repeated state textual content, however would not batch requests from totally different callers.
uv run --extra serve python -m pytest assessments/test_unit.py assessments/test_research.py -q  # no weights, no server; runs in CI
KEV_BASE_URL=http://127.0.0.1:8009 uv run --extra serve python -m pytest assessments/test_api.py -q   # towards a operating server
cd playground && npm run lint && npx subsequent typegen && npx tsc --noEmit -p .

The API assessments run TypeProtected’s instance requests and the official SDK towards your native server.

Troubleshooting
  • If MPS runs out of reminiscence throughout coaching, verify that you simply’re operating just one job. Don’t allow output_hidden_states or add tokens with peft’s trainable_token_indices; each have brought on reminiscence issues right here.
  • If the playground hundreds however buttons do not work, use localhost:3001. Next.js checks improvement hostnames. Other hosts want an entry in allowedDevOrigins in playground/subsequent.config.ts.
  • If dataset loading reviews Dataset scripts are not supported, use legacy-datasets/banking77. This repo already makes use of it.

Built with Devin. Thanks to Archer Hume for the structure write-up, TypeSafe for the API design, Qwen for the bottom fashions, 3x3xX3N0N for displaying the place the date-arithmetic failure actually is, and Radexito for --init_from.

Related work: Hydragen, DeFT, FIRST.

Apache-2.0. The Qwen3 and Qwen3.5 base fashions are additionally Apache-2.0. Training datasets have their very own licenses; see the model cards.



Source link