Avrik-Lite-4B
Built to perform. Calibrated to decide.
Avrik means "performance and achievement". Avrik-Lite-4B is the Edge tier of the Avrik family: a 4B-effective-parameter decision model that answers on an ordinary CPU in seconds, with calibrated probabilities. This repo holds the bf16 weights for GPUs.
www.avrik.ai · All Avrik models · Python: pip install avrik / pip install avrik-sdk
| Tier | Edge (Lite) |
| Base | Gemma 4 E4B-it (google/gemma-4-E4B-it), frozen |
| This repo | bf16 safetensors, 15 GiB, GPU via vLLM |
| Question types | yes/no, choice, score, multi-label |
| Context | 70,000 |
| Dev set (bf16) | 277/320 = 0.866, 95% Wilson [0.824, 0.899] |
| Latency | GPU latency not measured for this build |
| Licence | Apache-2.0 |
The Avrik family
| Model | Tier | Base | Runs on | Repos |
|---|---|---|---|---|
| Avrik-Lite-4B | Edge | Gemma 4 E4B-it | CPU (GGUF Q4_K_M) or GPU | bf16 · GGUF |
| Avrik-Pro-12B | Pro | Gemma 4 12B-it | One GPU (bf16), or a CPU or 16 GB card (GGUF Q8_0) | bf16 · GGUF |
| Avrik-Max-31B | Max | Gemma 4 31B-it | One 80 GB GPU (FP8) | config (weights stay with Google, verified by hash) |
All three answer the same API with the same question types; pick by accuracy, latency and hardware. Every model ships its own calibration for each build.
What it does
Avrik models are decision models. You send a state (a ticket, a transaction, a policy and a case, a document) and one or more typed questions, and you get back a calibrated probability distribution over each question's options. There is no generated text, no parsing and no sampling: one forward pass per question, and the answer is read directly from the model's output probabilities.
Use them where a system has to decide many times a second and needs to know how sure it is: routing, approvals, policy checks, moderation, triage, guardrails, eligibility, and "should a human look at this?".
| Question type | You send | You get |
|---|---|---|
noul (yes/no) | a yes/no question | noul: P(yes), from 0 to 1 |
choice | a question and 2 or more named options | choice (the top option) and probabilities over all of them |
score | a question and ordered levels (for example low, medium, high) | score: the expected level, plus probabilities per level |
multi_label | a question and labels | P(yes) per label, read independently, and the labels above a threshold |
Every answer also carries top, margin (top minus second), confidence and an abstain
flag. With abstain_option: true the model may answer "Insufficient information to
decide", and unknown_probability reports that mass.
Calibrated means that when the model says 0.8, it is right about 80% of the time on held-out data; the calibration section below shows how close each build gets. Act on the probabilities with your own thresholds: approve above 0.95, send to a human between 0.2 and 0.95, and so on.
Auditable. Every response records the model hash, adapter hash, calibration version, prompt-template SHA-256, allowed-token-set hash, input token count, backend and weight precision. The same request on the same backend and precision returns the same numbers.
Architecture
state + typed questions (HTTP POST /v1/systemone, or `avrik ask`)
│
▼
┌──────────────────────────┐
│ 1. Prompt renderer │ one fixed template per build (its SHA-256 is in every
│ │ response); options are rendered as letters A, B, C, …
└────────────┬─────────────┘
▼
┌──────────────────────────┐
│ 2. Gemma 4 decoder │ one forward pass per question; questions on the same
│ (this model) │ state are batched; nothing is generated
└────────────┬─────────────┘
▼
┌──────────────────────────┐
│ 3. Letter readout │ reads the probability of every tokenizer form of each
│ │ option letter (never top-k); refuses the answer if the
│ │ letters hold less than 98% of the probability mass
└────────────┬─────────────┘
▼
┌──────────────────────────┐
│ 4. Calibration │ per-type temperatures (yes/no, choice, score), fitted
│ │ for this exact build and bound to its hash
└────────────┬─────────────┘
▼
distribution + top, margin, confidence, abstain + 8 audit fields
The run-time stack is open source (Apache-2.0) on PyPI:
| Package | Install | Role |
|---|---|---|
avrik | pip install avrik (avrik[cpu] for llama.cpp) | CLI: pull (verified download), ask, serve, info |
avrik-server | installed with avrik | Prompt renderer, readout, calibration, the /v1/systemone HTTP API, and the llama.cpp (CPU) and vLLM (GPU) backends |
avrik-sdk | pip install avrik-sdk | Typed Python client (sync and async); depends only on httpx and pydantic |
This build: Gemma 4 E4B-it, frozen (not fine-tuned), with per-type temperatures choice 2.48 and yes/no 3.09.
The readout is what makes the numbers trustworthy, so run the model through
avrik-server rather than calling generate(): plain text generation from these weights
returns a chat answer, not calibrated probabilities. readout.json in this repo names the
prompt profile, the allowed letter set, the mass bound and the calibration file that
avrik-server loads.
Quick start
On a GPU with vLLM (Linux, CUDA). avrik pull downloads this repo and verifies every
file; vLLM serves the weights on loopback; avrik serve puts the decision API in front.
pip install avrik "vllm==0.30.0"
avrik pull Avrik-Lite-4B --format bf16 # -> ~/.cache/avrik/Avrik-Lite-4B-bf16
HF_HUB_OFFLINE=1 VLLM_NO_USAGE_STATS=1 DO_NOT_TRACK=1 VLLM_BATCH_INVARIANT=1 \
vllm serve ~/.cache/avrik/Avrik-Lite-4B-bf16 --served-model-name avrik \
--dtype bfloat16 --max-model-len 70000 --logprobs-mode raw_logprobs \
--attention-backend TRITON_ATTN \
--host 127.0.0.1 --port 8000 &
avrik ask Avrik-Lite-4B --format bf16 --vllm-url http://127.0.0.1:8000 \
--state "Customer bought headphones 12 days ago, unopened, receipt attached. \
Policy: unopened items within 30 days get a full refund." \
--noul "Should the refund be approved?" --choice "Which action?=approve,deny,escalate"
avrik serve Avrik-Lite-4B --format bf16 --vllm-url http://127.0.0.1:8000 # API on :8080
--logprobs-mode raw_logprobs is required: the readout needs the model's raw
probabilities. VLLM_BATCH_INVARIANT=1 makes answers independent of batch size (about 45%
slower at one question; drop it if you don't need bit-for-bit replay). No GPU? Use
Avrik-Lite-4B-GGUF on a CPU.
Connect and test
avrik serve exposes the API on http://127.0.0.1:8080 (loopback only):
| Route | Purpose |
|---|---|
POST /v1/systemone | Decide: state + questions in, calibrated answers out |
GET /health | Readiness and the loaded build's hashes |
GET /v1/models | The served model |
GET /openapi.json | The OpenAPI 3.1 schema |
curl
curl -s http://127.0.0.1:8080/health
curl -s http://127.0.0.1:8080/v1/systemone \
-H "Content-Type: application/json" \
-d '{
"model": "Avrik-Lite-4B",
"state": "Customer bought headphones 12 days ago, unopened, receipt attached. Policy: unopened items within 30 days get a full refund.",
"questions": {
"refund": {"type": "noul", "instructions": "Should the refund be approved?"},
"action": {"type": "choice", "instructions": "Which action?",
"criteria": {"approve": "approve", "deny": "deny", "escalate": "escalate"}},
"fit": {"type": "score", "instructions": "How confident is the policy match?",
"criteria": ["low", "medium", "high"]}
}
}'
Python SDK
pip install avrik-sdk
from avrik_sdk import Client, choice, noul, score
STATE = (
"Customer bought headphones 12 days ago, unopened, receipt attached. "
"Policy: unopened items within 30 days get a full refund."
)
with Client("http://127.0.0.1:8080") as client:
print(client.health().ok, [m.name for m in client.models()])
d = client.decide(
STATE,
{
"refund": noul("Should the refund be approved?"),
"action": choice("Which action?", ["approve", "deny", "escalate"]),
"fit": score("How confident is the policy match?", ["low", "medium", "high"]),
},
)
print(d["refund"].noul) # P(yes)
print(d["action"].choice, d["action"].probabilities)
print(d["fit"].score, d["fit"].legend) # expected level, 0..2
print(d.audit.model_hash, d.audit.calibration_version)
AsyncClient has the same methods. Errors raise AvrikError (with status, code,
message); 429 and 503 raise RateLimited with retry_after. The client never retries
unless you set max_retries.
A smoke test to keep
Save as test_avrik.py and run pytest -q while avrik serve is up. It checks that the
server is the build this card describes and that the answers are well formed.
from avrik_sdk import Client, choice, noul
MODEL_HASH = "avrik-ai/Avrik-Lite-4B@8004525daedc7abd"
CALIBRATION = "cal-lite-bf16-frozen-20261011-1"
STATE = (
"Customer bought headphones 12 days ago, unopened, receipt attached. "
"Policy: unopened items within 30 days get a full refund."
)
def test_decision_is_calibrated_and_attributable() -> None:
with Client("http://127.0.0.1:8080") as client:
assert client.health().ok
d = client.decide(STATE, {
"refund": noul("Should the refund be approved?"),
"action": choice("Which action?", ["approve", "deny", "escalate"]),
})
assert d.audit.model_hash == MODEL_HASH
assert d.audit.calibration_version == CALIBRATION
assert abs(sum(d["action"].probabilities.values()) - 1.0) < 1e-6
assert 0.0 <= d["refund"].noul <= 1.0
assert d["action"].choice == "approve" and d["refund"].noul > 0.5
Example output (measured)
From this tier's Q4_K_M GGUF on a 6-thread laptop CPU; the bf16 build's values differ slightly.
avrik ask Avrik-Lite-4B --state "Customer bought headphones 12 days ago, unopened, receipt attached. Policy: unopened items within 30 days get a full refund." \
--noul "Should the refund be approved?" \
--choice "Which action?=approve,deny,escalate" \
--score "How confident is the policy match?=low,medium,high" --json
{
"model": "Avrik-Lite-4B",
"answers": {
"q1": {
"type": "noul",
"noul": 0.9888623990436327,
"top": 0.9888623990436327,
"margin": 0.9777247980872654,
"abstain": false,
"avrik_confidence": 0.9777247980872654
},
"q2": {
"type": "choice",
"choice": "approve",
"probabilities": {
"approve": 0.9802886662123544,
"deny": 0.013453495424946386,
"escalate": 0.006257838362699155
},
"confidence": 0.9704329993185317,
"top": 0.9802886662123544,
"margin": 0.9668351707874081,
"abstain": false,
"avrik_confidence": 0.9704329993185317
},
"q3": {
"type": "score",
"score": 1.9108830388010996,
"legend": {
"0": "low",
"1": "medium",
"2": "high"
},
"probabilities": {
"0": 0.026152013564589877,
"1": 0.03681293406972051,
"2": 0.9370350523656895
},
"confidence": 0.8663245582016496,
"top": 0.9370350523656895,
"margin": 0.900222118295969,
"abstain": false,
"avrik_confidence": 0.9055525785485341
}
},
"audit": {
"model_hash": "avrik-ai/Avrik-Lite-4B-GGUF@c6f10bb369fe162a",
"adapter_hash": null,
"calibration_version": "cal-lite-q4-frozen-20261011-2",
"prompt_template_sha256": [
"a0eb0c15ba82644a1c8cc1fa5193e9f80e64c4b63a88fe38a65588e11ab16ff3",
"a0eb0c15ba82644a1c8cc1fa5193e9f80e64c4b63a88fe38a65588e11ab16ff3",
"a0eb0c15ba82644a1c8cc1fa5193e9f80e64c4b63a88fe38a65588e11ab16ff3"
],
"allowed_token_set_hash": [
"5fc292798298c3fc304dc50d234baa27140368a75b2f09cda2be877f8f10ca6a",
"306a666af00697fd8014ec8958ebbfacbde7a18f00eafefa52bdbaff5ee8e488",
"306a666af00697fd8014ec8958ebbfacbde7a18f00eafefa52bdbaff5ee8e488"
],
"input_tokens": [
110,
111,
115
],
"backend": "llamacpp-cpu",
"precision": "q4_k_m"
}
}
Results
All accuracies carry 95% Wilson intervals; a bare point estimate hides how few items sit behind it. Numbers were measured by Avrik AI.
Held-out human-authored evaluation
Pending. Avrik's sealed evaluation set is written by people, kept encrypted and never used for training or tuning. Its per-family results with 95% intervals will be added to this card in a later revision; this release is the frozen, calibrated base, so it does not depend on them.
Avrik dev set
Avrik's own development set: 320 text items in 24 families (decision rules, long-context lookups, probability and temporal reasoning, judgement, consistency pairs). 100 labels are computed by code; 220 were drafted by a model and are not human-verified, so read the families without computed labels as indicative. The set is used to choose prompts and check calibration, never to fit them.
| Family | Group | n | Correct | 95% Wilson |
|---|---|---|---|---|
| near_tie_stability | consistency | 10 | 10 | [0.722, 1.000] |
| negation_pairs | consistency | 15 | 14 | [0.702, 0.988] |
| order_invariance | consistency | 10 | 7 | [0.397, 0.892] |
| paraphrase_invariance | consistency | 10 | 9 | [0.596, 0.982] |
| ambiguous_abstain | core | 10 | 9 | [0.596, 0.982] |
| extraction | core | 10 | 10 | [0.722, 1.000] |
| judge | core | 15 | 15 | [0.796, 1.000] |
| long_policy | core | 10 | 10 | [0.722, 1.000] |
| multi_hop | core | 10 | 10 | [0.722, 1.000] |
| paraphrase_edit | core | 15 | 15 | [0.796, 1.000] |
| probability_laws | core | 15 | 10 | [0.417, 0.848] |
| routing | core | 10 | 10 | [0.722, 1.000] |
| rule_precedence | core | 15 | 9 | [0.357, 0.802] |
| safety_judge | core | 15 | 15 | [0.796, 1.000] |
| temporal_numeric | core | 24 | 20 | [0.641, 0.933] |
| trap_adversarial | core | 10 | 4 | [0.168, 0.687] |
| injection | domain_governance | 15 | 13 | [0.621, 0.963] |
| intent_alignment | domain_governance | 15 | 12 | [0.548, 0.930] |
| pii | domain_governance | 15 | 15 | [0.796, 1.000] |
| tool_call_authorization | domain_governance | 15 | 15 | [0.796, 1.000] |
| long_policy_buried | long_context | 16 | 11 | [0.444, 0.858] |
| long_records | long_context | 18 | 17 | [0.742, 0.990] |
| needle | long_context | 12 | 12 | [0.757, 1.000] |
| score_quality | score_quality | 10 | 5 | [0.237, 0.763] |
| overall | 320 | 277 | [0.824, 0.899] |
JevBench public tasks (self-run)
The 231 public tasks of JevBench v1.4.2 (MIT harness at commit b6b8fff7), run by Avrik AI against this release's server. This is not an official JevBench measurement, and these public tasks are not on the scale of the current leaderboard (v1.6.1), which draws from a private set. Accuracy is the top answer, so it is the same before and after calibration.
| Tier | Correct | 95% Wilson |
|---|---|---|
| easy | 48/48 | [0.926, 1.000] |
| standard | 68/72 | [0.866, 0.978] |
| hard | 66/111 | [0.502, 0.681] |
| overall | 182/231 | [0.731, 0.836] |
Calibration
Expected calibration error (ECE, 10 bins, top option) and Brier score per question type,
before (raw, T = 1) and after this build's calibration cal-lite-bf16-frozen-20261011-1.
The calibration pool is held out from dev; dev is shown for comparison only.
| Set | Type, stage | n | Accuracy | 95% Wilson | ECE | Brier |
|---|---|---|---|---|---|---|
| calibration pool | choice, before | 126 | 0.8333 | [0.7586, 0.8883] | 0.1376 | 0.2915 |
| calibration pool | choice, after | 126 | 0.8333 | [0.7586, 0.8883] | 0.0747 | 0.2757 |
| calibration pool | noul, before | 84 | 0.6667 | [0.5605, 0.7582] | 0.2895 | 0.5923 |
| calibration pool | noul, after | 84 | 0.6667 | [0.5605, 0.7582] | 0.1557 | 0.4360 |
| dev | choice, before | 150 | 0.8533 | [0.7879, 0.9011] | 0.1275 | 0.2754 |
| dev | choice, after | 150 | 0.8533 | [0.7879, 0.9011] | 0.1172 | 0.2538 |
| dev | noul, before | 160 | 0.9062 | [0.8511, 0.9424] | 0.0761 | 0.1601 |
| dev | noul, after | 160 | 0.9062 | [0.8511, 0.9424] | 0.0407 | 0.1444 |
| dev | score, before | 10 | 0.5000 | [0.2366, 0.7634] | 0.3519 | 0.7983 |
| dev | score, after | 10 | 0.5000 | [0.2366, 0.7634] | 0.2428 | 0.6572 |
Latency
Not measured for the bf16 build on a GPU in this release. For reference, Avrik-Pro-12B answers in 90 ms (p50) at 700 tokens on an H100. On a CPU, use the GGUF build: 5.0 s (p50) at 256 tokens on a 6-thread laptop CPU.
Intended use and limits
- For: automated decisions with a human-set threshold, triage and routing, policy and eligibility checks, classification with calibrated confidence, and as a fast first stage in front of people or larger models.
- Not for: explanations or free text (it generates none), or acting alone on decisions with legal, medical, financial or safety consequences without human review.
- Language: evaluated in English only.
- Input: text or JSON state. Images are not supported in this release.
- Context: up to 70,000 tokens per request through
avrik-server; the calibration was fitted within that length. - Weakest areas on our dev set: trap_adversarial (4/10); score_quality (5/10); rule_precedence (9/15).
- The model judges only what is in the state. Instructions planted in the state (prompt injection) can sway it; keep untrusted text clearly delimited.
Provenance and verification
| Field | Value |
|---|---|
| Model hash | avrik-ai/Avrik-Lite-4B@8004525daedc7abd |
| Base | google/gemma-4-E4B-it at revision ee0ef6023621cff504d758262d4e04895a5af4a2 |
| Recipe | frozen base with fitted per-type temperatures; no fine-tuning |
| Adapter hash | none |
| Calibration | cal-lite-bf16-frozen-20261011-1 |
| Prompt template SHA-256 | faef1dd3a7300a8a3cbb5204a78a57c28d2b70ca8965f715920cb4a56a0f9aa7 |
| Release gate | frozen (no-sealed): a fine-tuned Lite is in evaluation and replaces this build only if it beats it on the sealed human-authored set |
| Release | v1.0.0 |
Every file in this repo is listed with its SHA-256 in MANIFEST.sha256. avrik pull
checks every file before anything loads, and avrik ask and avrik serve check again at
every start. To check by hand: sha256sum -c MANIFEST.sha256. avrik info Avrik-Lite-4B --format bf16
prints provenance.json.
Security and data handling
- Protected against: tampered or swapped downloads (every file is checked against
MANIFEST.sha256, and the manifest's own digest is pinned inside theavrikpackage); releases that ship code (code files,auto_mapand symlinks are refused, and tokenizers load withtrust_remote_code=False). - Not protected against: adversarial content inside the state you send, or wrong answers. Treat outputs as calibrated probabilities to act on with your own thresholds, not as guarantees.
- Data handling: inference makes no network calls, sends no telemetry and stores
nothing.
avrik servelistens on 127.0.0.1 only. Onlyavrik pulluses the network. - Reporting a vulnerability: email Avrik AI at avriktech.ai@gmail.com.
Credits
- Gemma 4 by Google (Apache-2.0). Avrik-Lite-4B is built on
google/gemma-4-E4B-it. Thanks to Google DeepMind for releasing Gemma 4 under Apache-2.0. - Inference runs on llama.cpp (MIT) and vLLM (Apache-2.0).
- JevBench public tasks from the MIT-licensed JevBench harness.
Licence and terms of use
- Licence: Apache License 2.0 (
LICENSEin this repo). The weights are Google's Gemma 4 E4B-it, not fine-tuned, redistributed under Apache-2.0; the calibration and readout config are Apache-2.0 too. - Attribution: keep
NOTICEwith any redistribution. It credits Avrik AI and Gemma 4 by Google. - Acceptable use:
USE_POLICY.mdasks you to keep a person accountable for decisions with legal, financial, medical, employment or safety consequences, to test your own thresholds, and not to use the model for unlawful discrimination, surveillance without a lawful basis, or other illegal purposes. It does not restrict the rights the licence grants. - No warranty: provided "AS IS", without warranties or conditions of any kind (Apache-2.0, sections 7 and 8). Avrik AI is not liable for decisions made with it. The figures on this card describe the evaluations reported here, not results on your data.
Citation
@misc{avrik2026,
title = {Avrik: calibrated decision models},
author = {{Avrik AI}},
year = {2026},
howpublished = {\url{https://www.avrik.ai}},
note = {Avrik-Lite-4B, release v1.0.0}
}
Avrik AI · www.avrik.ai · avriktech.ai@gmail.com · huggingface.co/avrik-ai