Avrik-Pro-12B

Built to perform. Calibrated to decide.

Avrik means "performance and achievement". Avrik-Pro-12B is the Pro tier and the default model of the Avrik family: a 12B decision model that answers in about 90 ms on one GPU, 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 Pro (default)
Base Gemma 4 12B-it (google/gemma-4-12B-it), frozen
This repo bf16 safetensors, 23 GiB, GPU via vLLM
Question types yes/no, choice, score, multi-label
Context 70,000
Dev set (bf16) 292/320 = 0.913, 95% Wilson [0.876, 0.939]
Latency 90.4 ms p50 per decision at 702 tokens on an H100 (bf16 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 12B-it, frozen (not fine-tuned), with per-type temperatures choice 2.52 and yes/no 5.0.

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-Pro-12B --format bf16          # -> ~/.cache/avrik/Avrik-Pro-12B-bf16

HF_HUB_OFFLINE=1 VLLM_NO_USAGE_STATS=1 DO_NOT_TRACK=1 VLLM_BATCH_INVARIANT=1 \
  vllm serve ~/.cache/avrik/Avrik-Pro-12B-bf16 --served-model-name avrik \
  --dtype bfloat16 --max-model-len 70000 --logprobs-mode raw_logprobs \
  --host 127.0.0.1 --port 8000 &

avrik ask Avrik-Pro-12B --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-Pro-12B --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-Pro-12B-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-Pro-12B",
    "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-Pro-12B@cfd9cc0c27e96d1e"
CALIBRATION = "cal-12b-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 Q8_0 GGUF on a 6-thread laptop CPU; the bf16 build's values differ slightly.

avrik ask Avrik-Pro-12B --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-Pro-12B",
 "answers": {
  "q1": {
   "type": "noul",
   "noul": 0.9766435620248699,
   "top": 0.9766435620248699,
   "margin": 0.9532871240497397,
   "abstain": false,
   "avrik_confidence": 0.9532871240497398
  },
  "q2": {
   "type": "choice",
   "choice": "approve",
   "probabilities": {
    "approve": 0.9989560714456117,
    "deny": 0.0007050294868159737,
    "escalate": 0.00033889906757236717
   },
   "confidence": 0.9984341071684174,
   "top": 0.9989560714456117,
   "margin": 0.9982510419587958,
   "abstain": false,
   "avrik_confidence": 0.9984341071684174
  },
  "q3": {
   "type": "score",
   "score": 1.9808000557008545,
   "legend": {
    "0": "low",
    "1": "medium",
    "2": "high"
   },
   "probabilities": {
    "0": 0.00309155478292605,
    "1": 0.013016834733293398,
    "2": 0.9838916104837806
   },
   "confidence": 0.9712000835512817,
   "top": 0.9838916104837806,
   "margin": 0.9708747757504872,
   "abstain": false,
   "avrik_confidence": 0.9758374157256707
  }
 },
 "audit": {
  "model_hash": "avrik-ai/Avrik-Pro-12B-GGUF@6fbf37d64038ea71",
  "adapter_hash": null,
  "calibration_version": "cal-12b-q8-frozen-20261011-1",
  "prompt_template_sha256": [
   "3269884bf2b10959761578efcec48f09ec59ac185c735f0f759a9088440e2ce0",
   "3269884bf2b10959761578efcec48f09ec59ac185c735f0f759a9088440e2ce0",
   "3269884bf2b10959761578efcec48f09ec59ac185c735f0f759a9088440e2ce0"
  ],
  "allowed_token_set_hash": [
   "1756cfcb21d8677044b4032888d2d5d77342aef34930c796ae9b117814bfbcec",
   "75fdd8658361fd816b339b38b562d2c72e7d3d3db1fef94a0b4e4da837118cec",
   "75fdd8658361fd816b339b38b562d2c72e7d3d3db1fef94a0b4e4da837118cec"
  ],
  "input_tokens": [
   114,
   115,
   119
  ],
  "backend": "llamacpp-cpu",
  "precision": "q8_0"
 }
}

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 15 [0.796, 1.000]
order_invariance consistency 10 8 [0.490, 0.943]
paraphrase_invariance consistency 10 10 [0.722, 1.000]
ambiguous_abstain core 10 10 [0.722, 1.000]
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 12 [0.548, 0.930]
probability_laws core 15 14 [0.702, 0.988]
routing core 10 10 [0.722, 1.000]
rule_precedence core 15 15 [0.796, 1.000]
safety_judge core 15 15 [0.796, 1.000]
temporal_numeric core 24 20 [0.641, 0.933]
trap_adversarial core 10 8 [0.490, 0.943]
injection domain_governance 15 15 [0.796, 1.000]
intent_alignment domain_governance 15 14 [0.702, 0.988]
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 7 [0.231, 0.668]
long_records long_context 18 18 [0.824, 1.000]
needle long_context 12 12 [0.757, 1.000]
score_quality score_quality 10 4 [0.168, 0.687]
overall 320 292 [0.876, 0.939]

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 67/72 [0.848, 0.970]
hard 84/111 [0.669, 0.827]
overall 199/231 [0.811, 0.900]

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-12b-bf16-frozen-20261011-1. The calibration pool is held out from dev; dev is shown for comparison only. The pool's yes/no items come from two hard families, which is why the yes/no temperature sits at the top of the fit range (5.0); it is refitted when the pool widens.

Set Type, stage n Accuracy 95% Wilson ECE Brier
calibration pool choice, before 126 0.8889 [0.8221, 0.9327] 0.0935 0.1824
calibration pool choice, after 126 0.8889 [0.8221, 0.9327] 0.0471 0.1582
calibration pool noul, before 84 0.7024 [0.5975, 0.7896] 0.2828 0.5612
calibration pool noul, after 84 0.7024 [0.5975, 0.7896] 0.1601 0.3858
dev choice, before 150 0.9800 [0.9429, 0.9932] 0.0131 0.0267
dev choice, after 150 0.9800 [0.9429, 0.9932] 0.0225 0.0299
dev noul, before 160 0.8938 [0.8364, 0.9326] 0.1027 0.1985
dev noul, after 160 0.8938 [0.8364, 0.9326] 0.0623 0.1470
dev score, before 10 0.4000 [0.1682, 0.6873] 0.5999 1.1996
dev score, after 10 0.4000 [0.1682, 0.6873] 0.5714 1.1294

Latency

p50 90.4 ms and p95 94.6 ms per decision at 702 input tokens, one question, on an H100 80GB with vLLM 0.30 and batch-invariant kernels (VLLM_BATCH_INVARIANT=1). Several questions on one state are batched: 32 questions on a 1,500-token state took 17.6 ms per decision.

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: score_quality (4/10); long_policy_buried (7/16); order_invariance (8/10).
  • 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-Pro-12B@cfd9cc0c27e96d1e
Base google/gemma-4-12B-it at revision 707f0a3b8a3c7ad586ed01e27eafbad8a27dd0f7
Recipe frozen base with fitted per-type temperatures; no fine-tuning
Adapter hash none
Calibration cal-12b-bf16-frozen-20261011-1
Prompt template SHA-256 8d1575803fdb25b66865405afa0d2e6bb3df4eff08003e858769225b3bcc0b70
Release gate frozen (no-sealed): fine-tuned builds replace this one only if they beat 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-Pro-12B --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 the avrik package); releases that ship code (code files, auto_map and symlinks are refused, and tokenizers load with trust_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 serve listens on 127.0.0.1 only. Only avrik pull uses the network.
  • Reporting a vulnerability: email Avrik AI at avriktech.ai@gmail.com.

Credits

  • Gemma 4 by Google (Apache-2.0). Avrik-Pro-12B is built on google/gemma-4-12B-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 (LICENSE in this repo). The weights are Google's Gemma 4 12B-it, not fine-tuned, redistributed under Apache-2.0; the calibration and readout config are Apache-2.0 too.
  • Attribution: keep NOTICE with any redistribution. It credits Avrik AI and Gemma 4 by Google.
  • Acceptable use: USE_POLICY.md asks 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-Pro-12B, release v1.0.0}
}

Avrik AI · www.avrik.ai · avriktech.ai@gmail.com · huggingface.co/avrik-ai

Downloads last month
35
Safetensors
Model size
12B params
Tensor type
BF16
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for avrik-ai/Avrik-Pro-12B

Finetuned
(307)
this model
Quantizations
2 models