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)

v0.3.0发布于 2026-10-07 00:48 UTC1,600star +7 / 7 天180fork同步于 2026-11-10 17:49 UTC

怎么上手

由 README 提炼,执行前请确认
pip install "anyjev[hf]"
from anyjev import Tacit
tacit = Tacit.from_pretrained("morriszjm/Tacit-9B")
硬件要求按 README 说明

README 未给出显存要求;Tacit 模型示例注明单 GPU 运行,支持 transformers、进程内 vLLM 或 vllm serve 部署。

下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

把任意开源 LLM 变成带概率的类型化决策模型,无需训练即可输出可自动化的决策

把任意 LLM 改造成 Jev 风格决策模型,输出带类型的决策和真实概率,无需训练即可使用,适合需要可靠置信度的决策场景。

核心能力

  • 用 L0 读出消除选项顺序翻转和标签偏好偏差
  • 返回选项概率分布,无需解析模型文本输出
  • Tacit 自蒸馏模型单次前向即出决策,可选自适应升级推理
  • 按旋转预算自适应停止,无标签校准阈值
  • 提供 vLLM 服务端与 HTTP 决策网关,支持批量与统计

容易踩的坑

Tacit 需从 Hugging Face 额外下载权重;用 vLLM 服务端模式需先自行启动 vllm serve 并装 anyjev[client];HTTP 网关默认监听 127.0.0.1 且无自带鉴权。

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

4 个版本v0.3.0
  1. v0.3.0最新正式版2026-10-07 · 2026-10-07 00:48 UTC

    AnyJev now has two directions: training-free (Decider, levels raw and L0, 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 uses L1, L2, heads, routing, observe or level="auto" should pin anyjev==0.2.0. Docs and code that earlier entries cite are at tag v0.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 when nvcc is missing), or against a running vllm serve (engine="server", OpenAI /v1/completions with token-id prompts; the client loads only the tokenizer, and base_url may be the server root or its /v1 URL). One decision is one prefill of the prompt the models were trained with; the prompt builder is the library's own, and Decider(level="raw") sends the identical prompt (tested). decide / decide_batch return answer, index, probs, margin and route.
    • New: capped escalation to reasoning. With adaptive=True, a decision whose top-two margin is under tau (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 most max_cot_share (0.2) of the last cot_window (1,000) decisions escalate (rounded up; cot_window=None counts since loading). The bookkeeping is locked, so threads and clients share one cap. Escalations are reported (route="cot", first_pass, reasoning_tokens) and counted in Tacit.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 of vllm 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.py checks the README tables against their JSON.
    • Removed: L1 (calibrate, TemperatureScaler, artifacts and CALIBRATORS), 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 under bench/ (the result JSON the docs cite is kept), and the docs that described them. LEVELS is ("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: Tacit on transformers older than 5 passes the dtype as torch_dtype, as HFBackend does; 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) and client (the tokenizer only, for engine="server" and the gateway); the bench extra is gone. CI lints anyjev scripts space tests.
    • Docs: docs/levels.md rewritten 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 into docs/limitations.md (and docs/limitations.zh-CN.md).
  2. 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 under target by 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 is DEFAULT_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.md states 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=False reads 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 why docs/results_adaptive.md found 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_margin pins a threshold by hand, canonical_order=False restores pre-0.2 prompts. Tests in tests/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, from bench.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 in environment() rather than pinned per harness.
    • Fix: Decider.load_artifact dispatched on the artifact's
  3. 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.md lists everything removed).

    • L2: closed-form per-question heads on the hidden state, at two thirds of the depth. Decider.fit_head(question, states, labels) (or calibrate(..., 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 with blocks_executed in the diagnostics; require="L2" is enforced like the other levels. Artifacts round-trip through export_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, from bench/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_states writes new cases per workflow from real exemplars (Qwen3-8B, thinking off), bench.distill_heads labels 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.py fits and validates a model's heads for the 20 typed questions and the three bench tasks through the user path and writes anyjev-heads/<model>.json (with per-question validation, the agreement with the study caches, and env). 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_dict and load_artifacts read the list format too, and scripts/compact_heads.py converts in place after a bit-exact round-trip check.
    • Demo: python -m demo.jev_mode (demo/jev_mode.py; not in the wheel). --backend fake runs in seconds on CPU with no downloa
  4. v0.0.22026-09-21 · 2026-09-21 21:10 UTC
    查看更新说明
    • README GIF: scripts/find_flip_example.py finds real items where raw readout flips under option reversal and L0 does not; scripts/make_flip_gif.py renders 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, Decision with 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_maze runs AnyJev as the engine inside NanoJev's frozen maze exploration harness; bench.providers.nanojev_native_maze reruns their untuned-Qwen baseline for an apples-to-apples row.

    • Bench: bench.run_typed runs LocalLLaMA/typed-decisions (the set Laya and Jev report on) with overall / per-workflow / per-type metrics; bench.providers.laya runs Laya checkpoints on the same decisions.

    • Bench: bench.table aggregates 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, runner python -m bench.run.

    pip install "anyjev[hf]"

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    PyPI Python CI License Technical Report Models Tacitus Decision Index Decision Index 0.4.1

    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 stock vllm serve. pip install "anyjev[hf]", then Tacit.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.

    argumentdefaultmeaning
    adaptiveFalsesend low-confidence decisions to the model's own reasoning
    tau0.5low confidence: the log-probability gap between the top two options is below tau
    max_cot_share0.2at most this share of the last cot_window decisions escalates; None removes the cap
    cot_window1000how many recent decisions the cap counts; None counts every decision since loading
    cot_max_tokens8192reasoning 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; with adaptive=True, a capped share of decisions goes to reasoning.
    ⚪ raw logits🔵 L0zero labels
    Labels requirednonenone
    Answer flips when options are reversed0.2300.073
    Accuracy0.7470.803
    Calibration error (ECE)0.2400.184
    Auto-decidable at ≤5% error7.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

    modelbaseJevBench public (231)adaptivebev-decision test (46,320)adaptive
    Tacit-9BQwen3.5-9B0.8230.887 15.2%0.7270.755 18.1%
    Tacit-8BQwen3-8B0.736—0.663—
    Tacit-4BQwen3-4B0.7230.758 14.3%0.6630.704 17.8%
    Tacit-2BQwen3.5-2B0.671—0.626—
    Tacit-1.7BQwen3-1.7B0.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 scoresame skills, private 60%new domains, private 40%public not countedlatency median / mean / p95
    66.4762.4856.9365.5295 / 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 scorepublic 20%same skills, private 50%new domains, private 30%latency median / mean / p95
    60.2259.7959.1352.9898 / 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

    needsdoesdoes not
    rawnothingone prompt, softmax restricted to the option labelscorrect order or label bias
    L0nothingaverages position bias out over the K rotations, divides out the label priorcalibrate against labels
    Tacit one_forwarda Tacit checkpointone prompt, read like raw from a model trained to answer in one passcorrect order bias
    Tacit cotadaptive=Truereasons first, then reads the label distribution after the thoughtrun 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, noul and score from 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; Tacit in the library on transformers, vLLM and vllm 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.