typical-ai
Typed, direct decisions from a pretrained language model. State + question + a label set you define at call time go in; a probability distribution over exactly those labels, plus an explicit abstain, comes out. One forward pass, nothing generated, nothing to parse.
A self-contained decision head for OzLabs/typical-small-preview, OzLabs/typical-small, and
OzLabs/typical-medium. No training-repo dependencies (no bench/train/data/
metrics) -- just torch, transformers, huggingface_hub, safetensors, numpy.
Install
pip install typical-ai
The import name is typical_ai, not typical: PyPI's typical is an unrelated, established
package, so taking that import name would break anyone who has both installed.
from typical_ai import Typical
m = Typical.from_pretrained("OzLabs/typical-small") # or OzLabs/typical-medium
m.choice(state, "What does the customer want?", ["refund", "replacement", "repair"])
m.noul(state, "Is the order still under warranty?")
m.score(state, "How urgent is this ticket?", ["0", "1", "2", "3"])
Models and their cards, including the measured trade-offs of each release, are at https://huggingface.co/OzLabs. Source and the full experimental record: https://github.com/GuyNachshon/typical.
(Or just copy the typical/ directory next to your code -- it's a plain Python package,
no build step.)
Usage
from typical_ai import Typical
m = Typical.from_pretrained("OzLabs/typical-small", device="auto") # or "typical-small-preview" / "typical-medium"
# K-way choice over a fixed label set -> {label: p, ...} + p_null
m.choice(state, "What does the customer want?", ["refund", "replacement", "repair"])
# Yes/no -> P(yes)
m.noul(state, "Is the order still under warranty?")
# Ordinal levels -> {level: p, ...} + p_null + expected (E[index] under the candidates)
m.score(state, "How urgent is this ticket?", ["0", "1", "2", "3"])
# Full JevBench-style decide() -- mirrors pcdm_jev.decider.PCDMDecider.decide exactly,
# including the runtime block (latency, p_null, truncation flags).
probs, runtime = m.decide(
state,
{"type": "choice", "instructions": "What does the customer want?",
"criteria": {"refund": "money back", "replacement": "a new item shipped"}},
["refund", "replacement"],
)
state is either a string or a JSON-serialisable dict (dicts are dumped with
json.dumps before tokenising, same as the original decider).
See example.py for a runnable end-to-end script.
What's inside
typical/ is a trimmed, numerically-identical port of this repo's native-readout serving
path (pcdm_jev.decider.PCDMDecider(mode="native")):
typical/backbone.py-- frozen Qwen3 trunk truncated attap_layer, LoRA on its toplora_layersblocks (pcdm/encode.py'sBackbone, minus the training-only FeatureCache/EmbedEncoder/forward() machinery the serving path never touches).typical/native.py--NativeHead(factored null, the per-row Bernoulli "noul" route, theletters/tags/letters_nonull/query_onlyrenderers) andnative_kv_decide(encode the state once into a KV cache, score every query's suffix against it).typical/core.py--Typical.from_pretrained(downloadsbest.pt, readscheckpoint["args"]for backbone id /tap_layer/lora_r/lora_layers/nc_head/nc_render/null/noul_head/score_headto rebuild the exact backbone+head shape, then loads the LoRA + tower weights) plus thechoice/noul/score/decideAPI andquery_text/to_labels(verbatim frompcdm_jev/decider.py).
Not ported: nc_head values n2/n2n3 (Qwen3-Embedding candidate vectors) -- neither
shipped checkpoint trains with them; native_kv_decide raises NotImplementedError if a
future checkpoint needs that path. z-score calibration (--zscore) needs no special
handling -- its buffers live in the checkpoint's tower state_dict like any other weight.
Verification
inference/test_parity.py (gated behind RUN_SLOW=1, downloads the real 1.7B checkpoint)
runs 6 items through both the original PCDMDecider(mode="native") and Typical on the
same device and checkpoint, and asserts identical probabilities (max abs diff was 0.0
against guychuk/pcdm-runs/typical-small/best.pt on both CPU and MPS), plus the noul
reversed-label control (["no","yes"] vs ["yes","no"] give the same P(yes) through the
Bernoulli head) and a check that typical-small-preview's noul_head="choice" checkpoint
still answers noul() correctly through the plain K-way path.
RUN_SLOW=1 python inference/test_parity.py
Metadata
Release files for typical-ai 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| typical_ai-0.1.1.tar.gz | 18.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| typical_ai-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 37.9 kB
Release files / typical_ai-0.1.1.tar.gz
| Download URL | typical_ai-0.1.1.tar.gz |
|---|---|
| Size | 18.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e3051798d9c39035bb54c252419dd906b06696e21548a177224859067f96bf5a
|
|
BLAKE2b-256 checksum How to use checksums |
228e92adf5c780a169fa7ba94ffa4ed44db3ee4e0035a6e59e655745c528c423
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.7.9
|
Release files / typical_ai-0.1.1-py3-none-any.whl
| Download URL | typical_ai-0.1.1-py3-none-any.whl |
|---|---|
| Size | 19.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
134f2bf015835c8dc1a2c75d62fa98596d4feafa2e20f5f44f2e89ba4e9c31e6
|
|
BLAKE2b-256 checksum How to use checksums |
2f7c1ec58fc9907f24a14a1d3e78e40e4d93c8cc98dda0f11947fe321c1d2e15
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.7.9
|