Tacit 需从 Hugging Face 额外下载权重;用 vLLM 服务端模式需先自行启动 vllm serve 并装 anyjev[client];HTTP 网关默认监听 127.0.0.1 且无自带鉴权。
AnyJev
nokia-applied-researchApache-2.0活跃维护把任意 LLM 改造成 Jev 风格决策模型,输出带类型的决策和真实概率,无需训练即可使用,适合需要可靠置信度的决策场景。
Turn any LLM into a Jev-style decision model: typed decisions, real probabilities, no training. (continue updating, welcome any issue and PR request)
pip install "anyjev[hf]"
from anyjev import Tacit
tacit = Tacit.from_pretrained("morriszjm/Tacit-9B")README 未给出显存要求;Tacit 模型示例注明单 GPU 运行,支持 transformers、进程内 vLLM 或 vllm serve 部署。
把任意开源 LLM 变成带概率的类型化决策模型,无需训练即可输出可自动化的决策
把任意 LLM 改造成 Jev 风格决策模型,输出带类型的决策和真实概率,无需训练即可使用,适合需要可靠置信度的决策场景。
核心能力
- 用 L0 读出消除选项顺序翻转和标签偏好偏差
- 返回选项概率分布,无需解析模型文本输出
- Tacit 自蒸馏模型单次前向即出决策,可选自适应升级推理
- 按旋转预算自适应停止,无标签校准阈值
- 提供 vLLM 服务端与 HTTP 决策网关,支持批量与统计
容易踩的坑
- v0.3.0最新正式版2026-10-07 · 2026-10-07 00:48 UTC
AnyJev now has two directions: training-free (
Decider, levelsrawandL0, any open LLM) and self-distilled (Tacit, the Tacit models on Hugging Face). This release adds the second and removes the label-trained levels. Breaking: code that usesL1,L2, heads, routing,observeorlevel="auto"should pinanyjev==0.2.0. Docs and code that earlier entries cite are at tagv0.2.0.- New:
anyjev.Tacit, inference and serving for the Tacit models (Tacit-1.7B, 2B, 4B, 8B, 9B, collection).Tacit.from_pretrained(repo, engine=...)runs on transformers, on vLLM in the same process (engine="vllm"; Qwen3.5 checkpoints switch to the Triton gated-delta-rule kernel whennvccis missing), or against a runningvllm serve(engine="server", OpenAI/v1/completionswith token-id prompts; the client loads only the tokenizer, andbase_urlmay be the server root or its/v1URL). One decision is one prefill of the prompt the models were trained with; the prompt builder is the library's own, andDecider(level="raw")sends the identical prompt (tested).decide/decide_batchreturnanswer,index,probs,marginandroute. - New: capped escalation to reasoning. With
adaptive=True, a decision whose top-two margin is undertau(0.5) is answered again with thinking on. After the thought closes,Answer:is appended and the label distribution is read, so the escalated answer has probabilities and cannot fail to parse. At mostmax_cot_share(0.2) of the lastcot_window(1,000) decisions escalate (rounded up;cot_window=Nonecounts since loading). The bookkeeping is locked, so threads and clients share one cap. Escalations are reported (route="cot",first_pass,reasoning_tokens) and counted inTacit.stats. On vLLM the labels are read from the top 20 log-probabilities. - New:
python -m anyjev.serve, a standard-library HTTP gateway in front ofvllm serve:POST /v1/decide(one decision or{"items": [...]}),GET /v1/stats,GET /health; 400 on a malformed request, 502 when the upstream fails; binds 127.0.0.1 by default. - Results: Tacit accuracy with one forward per decision on JevBench (public, 231) and bev-decision
(test, 46,320),
bench/results_tacit/2026-10-05/one_forward.json, in both READMEs;tests/test_readme_numbers.pychecks the README tables against their JSON. - Removed:
L1(calibrate,TemperatureScaler, artifacts andCALIBRATORS),L2(fit_head,anyjev/heads.py, routing,adapt,observe,level="auto", artifact export and load),anyjev.pipeline, the shipped heads (anyjev-heads/),demo/, the benchmark code underbench/(the result JSON the docs cite is kept), and the docs that described them.LEVELSis("raw", "L0"). The hidden-state paths (HFBackend.hidden_states/hidden_states_to, the vLLM pooler path,anyjev.truncate) stay for the label-free early exit planned for 0.3.1. - Fix:
Taciton transformers older than 5 passes the dtype astorch_dtype, asHFBackenddoes; before 4.56,dtype=was dropped silently and the model loaded in float32. - Packaging: extras
vllm(vllm>=0.17.1, the version the Tacit checkpoints were checked on) andclient(the tokenizer only, forengine="server"and the gateway); thebenchextra is gone. CI lintsanyjev scripts space tests. - Docs:
docs/levels.mdrewritten for raw / L0 and Tacit's routes; the README banner and the how-it-works figure show raw and L0 only; the Roadmap is rewritten, and the Limitations move out of the README intodocs/limitations.md(anddocs/limitations.zh-CN.md).
- New:
- v0.2.02026-09-28 · 2026-09-28 08:33 UTC
查看更新说明
- New, opt-in: L0 can read as many option rotations as the decision needs instead of K, with the
rotations turning a canonical listing. Opt-in rather than default only because every table in
docs/was measured before it existed; the defaults flip in the release that regenerates them.Decider(adaptive_shifts=True)is now the default and the stopping rule compares the log-odds margin of the running marginal (adaptive_stat="logit") against a threshold with a stated meaning:Decider.calibrate_adaptive(question, states, target=0.01)reads every rotation of a batch of unlabelled states once and returns the cheapest threshold whose disagreement with the full-K answer is undertargetby a Clopper-Pearson upper bound (anyjev/calibrate/stopping.py). The reference is our own full-strength readout, never a label, so the guarantee costs only calibration compute. Before a question is calibrated the threshold isDEFAULT_LOG_MARGIN(8.5), the smallest value that certified 1% on four (model, task) cells at once. Measured on Qwen2.5-7B and Qwen3-8B over massive_route (K=18) and newsgroups (K=20), 900 states each: the uncalibrated default reads 5.1-9.7 rotations (1.9x-3.9x), per-question calibration reads 4.8-6.1 (2.9x-4.2x) with held-out disagreement 0.000-0.008, and accuracy is within 0.5 points of the full cycle either way. End to end at a certified 1% target on 300 states: 2.22x the decisions per second on a vLLM server and 2.3x-2.7x on the transformers backend (two runs; the adaptive rows are stable and the full-cycle reference varies, so the ratio inherits its variance —docs/rotation_budget.mdstates both), 7.2 requests per decision instead of 18, agreement 0.987, accuracy 0.703 against 0.697 (bench/results_layout/2026-09-27/,docs/rotation_budget.md, research log entries 23 and 24).Decider(adaptive_wave=n)asks for n rotations per backend call; the default is 2 because a round is a barrier the whole batch waits behind -- on vLLM, waves of 1 and 2 issue the same requests and differ by 1.7x in wall clock, while locally they tie.adaptive_shifts=Falsereads every rotation. Decider(canonical_order=True), also new, is what makes stopping early safe, so turn the two on together. The rotations now turn a listing of the options ordered by their text rather than the caller's listing. Reading every rotation already gave every option every position, but which options sit next to each other still followed the caller's order and a partial budget does not cancel the position bias either, so the decision could depend on how the list was typed. With it the prompts are a function of the option set: any two listings of the same options return identical probabilities, at any rotation budget -- a stronger guarantee than the full cycle used to give. The statistic had to change for the same reason the old margin never bound: a probability gap saturates at 1, which is whydocs/results_adaptive.mdfound margins of 0.05, 0.1 and 0.2 indistinguishable, and why on two of the four cells above no probability-gap threshold could certify a 1% rate at all.adaptive_stat="prob"restores the pre-0.2 rule,adaptive_marginpins a threshold by hand,canonical_order=Falserestores pre-0.2 prompts. Tests intests/test_stopping.py, including that a calibration set too small to certify a target returns no threshold and reads every rotation rather than pretending.- Every result JSON now records the readout it was produced with (
env.readout, frombench.run.readout_settings). A benchmark that inherits the library's defaults is fine; one that does not record them is not, because changing a default then moves every published row with nothing in the JSON to show it. This change is exactly that case, which is why the record is centralised inenvironment()rather than pinned per harness. - Fix:
Decider.load_artifactdispatched on the artifact's
- New, opt-in: L0 can read as many option rotations as the decision needs instead of K, with the
rotations turning a canonical listing. Opt-in rather than default only because every table in
- v0.1.02026-09-26 · 2026-09-26 20:55 UTC
查看更新说明
Version 3 of the method: a closed-form head at a fixed depth, routing, label-free adaptation, a packaged demo, and a tree that carries only the shipped code and the result JSON a doc cites (
docs/migration_v3.mdlists everything removed).- L2: closed-form per-question heads on the hidden state, at two thirds of the depth.
Decider.fit_head(question, states, labels)(orcalibrate(..., level="L2")) runs one forward of the labelled states and solves a shrunk-LDA or ridge head on the last-position hidden state; the block it reads, the head kind and the temperature are chosen by out-of-fold NLL.decide(..., level="L2")then sends one prompt per state through a forward that stops at that block (HFBackend.hidden_states_to, bit-exact against the plain forward in fp32,scripts/exit_parity.py) and returns calibrated probabilities withblocks_executedin the diagnostics;require="L2"is enforced like the other levels. Artifacts round-trip throughexport_artifacts/load_artifacts/load_artifact(refused on another model or question layout). On LocalLLaMA/typed-decisions with 300 labels per question: Qwen3-1.7B 0.730 at 64% depth, Qwen3-4B 0.786 at 67%, Qwen3-8B 0.771 at 67% (L1: 0.499 / 0.567 / 0.648; Jev published 0.727), pooled ECE 0.03-0.05, at 0.68x the batched time of one plain forward on the 8B; Qwen3-30B-A3B 0.799 at 83%, Qwen3-32B 0.798 at 81% (docs/results_exit.md, frombench/results_exit/2026-09-22/). Needs the transformers backend.docs/method_v3.md,docs/jev_mode.md,docs/levels.md,docs/research_log.md. - L2 follows its question across wordings and listing orders.
Decider.route(q)serves a question from its exact head, else from the head of the same kind and option texts under another wording, else (heads fit on random listing orders) from the head of the same option set in another order;Decider(adapt="routed")(default) re-estimates a routed head's feature mean and scale from the unlabelled states the question is asked on (30 by default, the current batch included), which on Qwen3-8B takes a reworded question from 0.65-0.70 (head as is) to 0.74-0.75 with 30 unlabelled states (0.74-0.76 with 300) against 0.77 for a labelled refit (bench/results_paraphrase/2026-09-22/Qwen__Qwen3-8B.paraphrase.b24.json; the 4B goes 0.63-0.68 to 0.74-0.75,Qwen__Qwen3-4B.paraphrase.b24.json; research log entry 13);fit_head(listing="auto")fits on random listing orders up to 8 options (flip under reversal 0.07 instead of 0.18,<model>.order.json) and on the canonical order above (random listings cost the 20-way bench heads 6-18 points in the artifact builds, entry 13);level="auto"picks L2 / L1 / L0 per question. Diagnostics:routed_from,reordered,adapted,adapt_n,listing. - Closed-form distillation:
bench.synth_stateswrites new cases per workflow from real exemplars (Qwen3-8B, thinking off),bench.distill_headslabels them with a teacher's shipped heads and solves student heads on gold plus teacher-labelled states (hard or soft targets); the 32B's heads lift the Qwen3-1.7B from 0.730 to 0.760 on typed-decisions (95% CI on the gain [+0.015, +0.049]), the 4B and 8B do not move (bench/results_distill/2026-09-22/Qwen__Qwen3-32B.distill_heads.fit.json, entry 14). - Shipped heads:
scripts/build_heads.pyfits and validates a model's heads for the 20 typed questions and the three bench tasks through the user path and writesanyjev-heads/<model>.json(with per-question validation, the agreement with the study caches, andenv). The head arrays are stored as base64 float32 (anyjev.heads.encode_array, exact, about ten times smaller than number lists): 1.8-4.4 MB per model, 13.6 MB for the five;LinearHead.from_dictandload_artifactsread the list format too, andscripts/compact_heads.pyconverts in place after a bit-exact round-trip check. - Demo:
python -m demo.jev_mode(demo/jev_mode.py; not in the wheel).--backend fakeruns in seconds on CPU with no downloa
- L2: closed-form per-question heads on the hidden state, at two thirds of the depth.
- v0.0.22026-09-21 · 2026-09-21 21:10 UTC
查看更新说明
-
README GIF:
scripts/find_flip_example.pyfinds real items where raw readout flips under option reversal and L0 does not;scripts/make_flip_gif.pyrenders them (assets/flip.gif, Qwen3-8B on BANKING77).space/holds the Hugging Face Space entry point. -
Decider.save_artifacts / load_artifacts: L1 artifacts as one JSON file per model, refused on model mismatch.
-
ROADMAP.md, CONTRIBUTING.md, CREDITS.md, GitHub Actions CI (ruff + pytest on 3.10 and 3.12).
-
Core:
Question(choice / score / noul),Decider,Decisionwith mandatory level. -
Readout: chat-template prompts, single-token label mapping with collision and multi-token errors.
-
L0: cyclic-shift permutation marginalization (log-space combine by default) and label-free prior correction: batch calibration by default (low variance in the bench), content-free contextual calibration opt-in (high variance: large wins on one noul task, losses on ordinal scores).
-
Readout: noul label tokens stay bound to their option when the phrasing order is swapped (a position-bound readout silently swapped Yes/No in the second phrasing).
-
L1: temperature scaling artifacts keyed by (model, question).
-
HFBackend accepts
revision. -
vLLM backend parity check (
scripts/vllm_parity.py): 15/15 argmax agreement with transformers on Qwen2.5-7B-Instruct; restricted log-softmax differs by up to 0.6 nats only on labels below 1e-7 probability. -
Backends: transformers (
HFBackend), vLLM OpenAI-compatible server (VLLMBackend, allowed_token_ids + logprobs), synthetic biased model (FakeBackend) for tests. -
Question.score accepts explicit ordered
levels; value is the expected level index. -
Bench:
bench.providers.nanojev_mazeruns AnyJev as the engine inside NanoJev's frozen maze exploration harness;bench.providers.nanojev_native_mazereruns their untuned-Qwen baseline for an apples-to-apples row. -
Bench:
bench.run_typedruns LocalLLaMA/typed-decisions (the set Laya and Jev report on) with overall / per-workflow / per-type metrics;bench.providers.layaruns Laya checkpoints on the same decisions. -
Bench:
bench.tableaggregates result JSONs into one table; runner saves after every task and merges per task across invocations. -
Bench: metrics (accuracy, macro-F1, Brier, NLL, ECE, flip rate, coverage-risk), tasks
newsgroups,injection,banking20, runnerpython -m bench.run.
pip install "anyjev[hf]" -
用户点评
登录用户的真实使用记录,可按版本和硬件筛选还没有人点评。第一个说出真实体验的人最有价值。
English · 简体中文 · ⚡ Serve it · 📊 Results · 🏆 Leaderboard · 🧭 Roadmap · 📖 Levels
[!TIP] 🆕 Tacit: AnyJev's self-distilled models, 1.7B to 9B, are on Hugging Face. One forward pass per decision. With
adaptive=True, a capped share of low-confidence decisions goes to the model's own reasoning. They run on transformers, in-process vLLM or a stockvllm serve.pip install "anyjev[hf]", thenTacit.from_pretrained("morriszjm/Tacit-9B"). Start here ↓
[!NOTE] 🏆 AnyJev Tacitus on the Decision Index 0.4.1. AnyJev Tacitus 31B, fine-tuned from Gemma-4-31B and read with AnyJev, has a Full score of 66.47, tied 3rd on the board on 2026-10-21. Details ↓
[!NOTE] 🏆 No training, on a public leaderboard. The training-free
Decider(L0, two rotations) on the unchanged Gemma-4-31B has a Full score of 60.22 on the Decision Index 0.3, 5th of 149 entries on 2026-10-12. Details ↓
⚡ Serve it
A Tacit model, in Python.
from anyjev import Tacit
tacit = Tacit.from_pretrained("morriszjm/Tacit-9B") # transformers, one GPU
d = tacit.decide(state="Customer: my package was due last Monday and it still has not arrived.",
question="What does the customer want?",
options=["track_order", "cancel_order", "refund", "change_address"])
d["answer"], d["probs"], d["route"] # an option, {option: probability}, "one_forward" or "cot"
kind is "choice" (default), "yes_no" or "score" (options are ordered levels, lowest
first, numbered from 1; first_level=0 numbers them from 0). decide_batch([...]) takes a list of such dicts.
Send the hardest decisions to reasoning, with a cap.
tacit = Tacit.from_pretrained("morriszjm/Tacit-9B", adaptive=True, tau=0.5, max_cot_share=0.2, cot_window=1000)
A decision whose top two options are less than tau apart in log-probability is answered again with
thinking on. After the reasoning, the answer is read as a label distribution, so it also has
probabilities and cannot fail to parse. At most max_cot_share of the last cot_window decisions
escalate, however hard the traffic gets. Every escalation is reported (route == "cot", with the
first pass kept), and tacit.stats counts them.
On vLLM. A stock server; the client needs only the tokenizer.
pip install "anyjev[client]"
vllm serve morriszjm/Tacit-9B --host 127.0.0.1 --port 8000
tacit = Tacit.from_pretrained("morriszjm/Tacit-9B", engine="server",
base_url="http://127.0.0.1:8000", adaptive=True)
engine="vllm" (pip install "anyjev[vllm]") runs vLLM in the same process instead.
An HTTP endpoint for many clients sharing one cap.
python -m anyjev.serve --model morriszjm/Tacit-9B --upstream http://127.0.0.1:8000 --adaptive --port 8100
curl -s 127.0.0.1:8100/v1/decide -H 'Content-Type: application/json' \
-d '{"state": "Customer: my package has not arrived.", "question": "What does the customer want?", "options": ["track_order", "refund"]}'
POST /v1/decide takes one decision or {"items": [...]}; GET /v1/stats reports the escalation
share. The gateway listens on 127.0.0.1 and has no authentication of its own.
| argument | default | meaning |
|---|---|---|
adaptive | False | send low-confidence decisions to the model's own reasoning |
tau | 0.5 | low confidence: the log-probability gap between the top two options is below tau |
max_cot_share | 0.2 | at most this share of the last cot_window decisions escalates; None removes the cap |
cot_window | 1000 | how many recent decisions the cap counts; None counts every decision since loading |
cot_max_tokens | 8192 | reasoning budget of one decision |
engine | "transformers" | "vllm" runs vLLM in this process; "server" uses a running vllm serve at base_url |
Any other model, training-free. The Decider reads the same typed decisions from any open
causal LM, with no training and no labels.
from anyjev import Decider, Question
from anyjev.backends.hf import HFBackend # or VLLMBackend / SGLangBackend(url, model), LlamaCppBackend(gguf)
d = Decider(HFBackend("Qwen/Qwen3-8B")) # level="L0" by default
route = Question.choice("Which team should handle this?",
["billing", "technical", "sales", "other"], name="route")
r = d.decide("My card was charged twice for one order.", [route])["route"]
r.distribution, r.level # {option: probability}, "L0"
L0 reads a K-option choice once per rotation of the options. With the rotation budget, it reads only as many rotations as the decision needs:
d = Decider(backend, adaptive_shifts=True, canonical_order=True)
d.calibrate_adaptive(route, unlabelled_tickets, target=0.01) # a few hundred states, no labels
The stopping threshold is calibrated against our own full-cycle answer, so it needs no labels. At a certified 1% disagreement it read 7.2 rotations instead of 18. That was 2.2× the decisions per second on vLLM and 2.3×–2.7× on transformers, with accuracy unchanged (docs/rotation_budget.md).
✨ What it is
Give the model a state and a typed question (a choice, a yes/no or a score). You get back a decision with a probability over the options, read from the model's next-token distribution. Nothing is parsed. There are two ways in:
- AnyJev Training-Free (
Decider) works on any open LLM, with no training. Raw label logits change their answer when the options are reordered and carry the model's preference for some labels. L0 removes both without a single label. - AnyJev Self-Distilled (
Tacit) uses the Tacit checkpoints. They are trained by self-distillation: the model learns to give, in one forward pass, the answers it reaches when it reasons. No human labels and no other model are involved. One prefill per decision; withadaptive=True, a capped share of decisions goes to reasoning.
| ⚪ raw logits | 🔵 L0zero labels | |
|---|---|---|
| Labels required | none | none |
| Answer flips when options are reversed | 0.230 | 0.073 |
| Accuracy | 0.747 | 0.803 |
| Calibration error (ECE) | 0.240 | 0.184 |
| Auto-decidable at ≤5% error | 7.7% | 46.3% |
Qwen3-8B, BANKING77 20-way, 300 test items · bench/results_v01/2026-09-22/Qwen__Qwen3-8B.json
The last row matters most. Accuracy moves six points, but the share of decisions confident enough to automate at ≤5% error goes from 7.7% to 46.3%, with no labels at all.
📊 Tacit results
| model | base | JevBench public (231) | adaptive | bev-decision test (46,320) | adaptive |
|---|---|---|---|---|---|
| Tacit-9B | Qwen3.5-9B | 0.823 | 0.887 15.2% | 0.727 | 0.755 18.1% |
| Tacit-8B | Qwen3-8B | 0.736 | — | 0.663 | — |
| Tacit-4B | Qwen3-4B | 0.723 | 0.758 14.3% | 0.663 | 0.704 17.8% |
| Tacit-2B | Qwen3.5-2B | 0.671 | — | 0.626 | — |
| Tacit-1.7B | Qwen3-1.7B | 0.619 | — | 0.598 | — |
Accuracy on every item of both sets (JevBench public
set; bev-decision test split), in the order they
are stored. First column: one forward pass per decision (adaptive=False). Adaptive: adaptive=True at
the defaults (tau=0.5, at most 20% of every 1,000 decisions), with the share of decisions sent to
reasoning in small print. Served by vllm serve (vLLM 0.17.1), run with scripts/eval_tacit.py · bench/results_tacit/2026-10-06/
On average, escalation adds 567 (JevBench) and 458 (bev-decision) generated tokens per decision for Tacit-9B, and 305 and 187 for Tacit-4B. Results with escalation for Tacit-8B, Tacit-2B and Tacit-1.7B come next.
🏆 AnyJev Tacitus on the Decision Index
AnyJev Tacitus 31B is a decision model fine-tuned from
google/gemma-4-31B-it, with an inference technique designed together with
the training. It reads every decision from one prefill through AnyJev's readout, with no generated tokens. On the
Decision Index 0.4.1 board it is tied 3rd by Full score (2026-10-21);
from edition 0.4 the Full score counts the private parts only.
| Full score | same skills, private 60% | new domains, private 40% | public not counted | latency median / mean / p95 |
|---|---|---|---|---|
| 66.47 | 62.48 | 56.93 | 65.52 | 95 / 265 / 1,000 ms |
The board's maintainers ran the two private parts and measured the latency (single process, one RTX PRO 6000).
Served by vLLM 0.29.0 with FP8 at load and the model's vLLM plugin, anyjev 0.3.0. Engine, plugin and run settings:
MorrisZJ/anyjev-tacitus; results: decision-index-results ·
bench/results_decision_index/2026-10-21/anyjev-tacitus-31b.json
🏆 Training-free on the Decision Index
The Decider at L0 on the unchanged google/gemma-4-31B-it:
no training, no labels, two rotations per decision. On the Decision Index 0.3 board it is
5th of 149 entries by Full score (2026-10-12).
| Full score | public 20% | same skills, private 50% | new domains, private 30% | latency median / mean / p95 |
|---|---|---|---|---|
| 60.22 | 59.79 | 59.13 | 52.98 | 98 / 260 / 1,080 ms |
The board's maintainers ran the two private parts and measured the latency (single process, one RTX PRO 6000).
Served by vllm serve --quantization fp8 (vLLM 0.29.0) with anyjev 0.3.0. Engine and run settings:
examples/decision_index (submitted as
anyjev-l0-gemma); model card:
AnyJev-L0-Gemma-4-31B ·
bench/results_decision_index/2026-10-12/anyjev-l0-gemma-4-31b.json
🧠 How it works
| needs | does | does not | |
|---|---|---|---|
raw | nothing | one prompt, softmax restricted to the option labels | correct order or label bias |
L0 | nothing | averages position bias out over the K rotations, divides out the label prior | calibrate against labels |
Tacit one_forward | a Tacit checkpoint | one prompt, read like raw from a model trained to answer in one pass | correct order bias |
Tacit cot | adaptive=True | reasons first, then reads the label distribution after the thought | run beyond its cap |
Every Decision carries its level, and require="L0" makes downstream code refuse a weaker one.
Every Tacit decision carries its route.
The contract in full →
Every number in this README is read from committed JSON. Not affiliated with TypeSafe AI or Jev.
🧭 Roadmap
-
choice,noulandscorefrom one prefill; L0 with zero labels - The rotation budget: L0 at about 7 of 18 rotations, with a stopping threshold certified without labels
- Tacit-1.7B, 2B, 4B, 8B and 9B on Hugging Face;
Tacitin the library on transformers, vLLM andvllm serve, with capped escalation to reasoning and an HTTP gateway - The evaluation harness (
scripts/eval_tacit.py); results with escalation for Tacit-9B and Tacit-4B - The training-free path on the public Decision Index 0.3 board (L0 on Gemma-4-31B)
- AnyJev Tacitus 31B on the Decision Index 0.4.1 board, tied 3rd (details)
- 🚧 Results with escalation for Tacit-8B, Tacit-2B and Tacit-1.7B
- 🚧 Label-free early exit: read a decision from part of the model's depth, choosing the depth by agreement with the full model
- Agent-loop evaluation: the same decisions inside a real agent
- SGLang backend (
anyjev.backends.sglang), contributed by @shentonyan - llama.cpp backend for GGUF models (
anyjev.backends.llamacpp), contributed by @Tusm11 - More log-prob backends (MLX, Ollama), span readout beyond 26 options
Dated plan and help-wanted files: ROADMAP.md. Known limitations: docs/limitations.md.
🤝 Contributing and citation
Backends are one file each, and several are help wanted (ROADMAP.md, CONTRIBUTING.md). Changes: CHANGELOG.md. Credits: CREDITS.md.
Technical Report:
@misc{zhang2026anyjevtechnicalreport,
title={AnyJev Technical Report},
author={Jiamu Zhang and Tianze Yang and Yucheng Shi and Evan Chen and Zixiang Nie and Kelly Wan and Liangjie Hong and Ninghao Liu and Liang Wu},
year={2026},
eprint={2610.00831},
archivePrefix={arXiv},
primaryClass={cs.LG},
url={https://arxiv.org/abs/2610.00831},
}
Apache-2.0, see LICENSE. The Tacit models carry their base models' Apache-2.0 license. Datasets keep their own licenses, see THIRD_PARTY.md.