Jiamu Zhang1 Tianze Yang1 Yucheng Shi2 Evan Chen1
Zixiang Nie1 Kelly Wan1 Liangjie Hong1 Ninghao Liu3 Liang Wu1
1 Nokia, Sunnyvale, CA, USA 2 Tencent Hunyuan 3 The Hong Kong Polytechnic University
Qwen3-8B on a real BANKING77 item. Every number is a model output.
⚡ 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). 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 anyjev.backends.vllm.VLLMBackend(url, model)
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 | 🔵 L0 zero 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) | bev-decision test (46,320) |
|---|---|---|---|
| Tacit-9B | Qwen3.5-9B | 0.823 | 0.725 |
| Tacit-8B | Qwen3-8B | 0.749 | 0.662 |
| Tacit-4B | Qwen3-4B | 0.723 | 0.663 |
| Tacit-2B | Qwen3.5-2B | 0.671 | 0.626 |
| Tacit-1.7B | Qwen3-1.7B | 0.623 | 0.598 |
Accuracy with one forward pass per decision (adaptive=False), the options in the benchmark's
order, on every item of both test sets (JevBench public
set; bev-decision test split) ·
bench/results_tacit/2026-10-05/one_forward.json
Results with escalation (adaptive=True) will be published together with the evaluation harness.
🧠 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 - 🚧 Results with escalation on JevBench and bev-decision, released with the evaluation harness
- 🚧 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
- More log-prob backends (SGLang, llama.cpp, 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},
}
Software:
@software{anyjev2026,
title = {AnyJev: Turn any LLM into a Jev-style decision model},
author = {Zhang, Jiamu and Yang, Tianze and Shi, Yucheng and Wu, Liang},
year = {2026},
url = {https://github.com/nokia-applied-research/AnyJev}
}
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.
Metadata
Release files for anyjev 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| anyjev-0.3.0.tar.gz | 75.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| anyjev-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 136.5 kB
Release files / anyjev-0.3.0.tar.gz
| Download URL | anyjev-0.3.0.tar.gz |
|---|---|
| Size | 75.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8a8c004c88803fbb407546e4e7c059dc0fb19e08b95d2c4ea3b1089a6fd00b76
|
|
BLAKE2b-256 checksum How to use checksums |
10fbbcd57670036f0faf249eec3d01d6db249cfa128092f88cb3d3254c8faa6c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency logRelease files / anyjev-0.3.0-py3-none-any.whl
| Download URL | anyjev-0.3.0-py3-none-any.whl |
|---|---|
| Size | 61.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
24217f23eecb3859353d625b89e0047d02c70c8ce993f956e118d7e39b9dcf3f
|
|
BLAKE2b-256 checksum How to use checksums |
8a6980b0efe02d63f9ee96ed312919b7faf801a7b6c8bf7b6622ebbb8c57685d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency log