# Introducing Decide, a System One model in the browser

**Decide** reads a piece of text and picks one of your labels, inside the user's browser, in about 8 ms in Chrome. It needs no server and no API key, and its confidence means what it says: answers at 0.9 are right about 90% of the time. When it isn't sure, it asks an LLM and learns from the reply. Watching real Llama 3.1 8B answers, the share of messages it sent fell from 30% to 19%. [Try it in your browser](https://debuff.jp/decide/playground/).

## A small, local Jev

TypeSafe's [Jev](https://typesafe.ai/) made the term ["System One model"](https://docs.typesafe.ai/concepts/system-one) stick: a model that doesn't write, it reads a text once and returns a typed decision with a calibrated confidence. Jev runs behind an API. Decide is the same kind of model, small enough to run on the user's device, so each decision is free, private and a few milliseconds. It's less accurate than a large hosted model, which is why the confidence matters: your code can act alone when Decide is sure and ask for help when it isn't.

Coding against Jev already? [`decidekit/typesafe`](/decide/docs/guide-typesafe) has the same `systemOne({ state, questions })` shape for Choice questions, and the guide lists what differs.

## Try it

Decide ships in the `decidekit` library:

```bash
npm install decidekit
```

```ts
import { createDecider } from "decidekit";

const d = await createDecider();
const { choice, confidence } = await d.decide("my card still hasn't arrived", ["card_arrival", "lost_card", "refund"]);
// choice: "card_arrival", typed as your labels
```

| | |
|---|---|
| BANKING77, 77 labels, all training data | 90.7% |
| CLINC150, 150 labels, all training data | 94.4% |
| BANKING77 with 5 examples per label | 82.3% |
| Calibration error, trained heads with 10+ examples per label | 0.008 to 0.029 |
| A decision in Chrome (worker, median) | 7.7 ms |

Measured on a Ryzen 7 260 laptop with the default model (bge-small-en-v1.5, 34 MB, downloaded once). The [README](https://github.com/debuffjp/decidekit#numbers) has the full table and the scripts that produced it.

## Your labels are the type

`choice` has the literal type of the labels you pass, so the compiler checks every branch:

```ts
const labels = ["refund", "bug_report", "praise"] as const;
const { choice } = await d.decide(text, labels);
switch (choice) {
  case "refund": return openRefund();
  case "bug_report": return fileBug();
  case "praise": return thank();
}
```

Rename a label and TypeScript shows you every place that handled the old one. Trained heads carry their labels too: `decidekit train examples.csv --types` writes a `.ts` file with the labels as a union, so a head trained by someone else still types your code.

## Three ways to start

1. **From label names.** Pass `["refund", "bug_report", "praise"]` and it decides zero-shot. Add a one-line description per label and it gets 7 to 10 points better; `describeLabels()` asks an LLM to write them once.
2. **From examples, in the page.** `train()` fits a small head on the user's own data in a Web Worker. BANKING77's 10,003 examples trained without a page stall longer than 18 ms.
3. **From an LLM, as it goes.** `withFallback()` answers what it's sure of and sends the rest to your `ask` function. Each answer becomes a training example, so the share it sends keeps falling.

## Learning from an LLM that's sometimes wrong

LLM answers are not ground truth. Llama 3.1 8B agreed with BANKING77's labels on 89% of our demo messages. Wrong answers barely moved the head's accuracy, but they ruined its confidence, so it kept asking. Decide now fits its confidence on the answers zero-shot was already sure of, and learns the LLM's "none of these" answers so it can turn away off-topic text itself. The method and the numbers are in the research post, [When the LLM is wrong](/research/learning-from-a-noisy-llm).

[The two lanes demo](https://debuff.jp/decide/lanes/) replays those real Llama answers, so you can watch the share fall.

## What it doesn't do

- **Tone.** It reads what a text is about better than how it feels: 61% on tweet sentiment, 49% on emotion with 32 examples per label.
- **Long documents.** It reads about a paragraph. Split longer text.
- **Languages other than English** with the default model. `multilingual-e5-small` reaches 76% on Japanese and Chinese intents against 55% and 40%, with calibrated confidence, at about 118 MB.

It's 0.1 and MIT licensed. Tell us what it gets right and wrong on your data in [Discussions](https://github.com/debuffjp/decidekit/discussions) or the [debuff Discord](https://discord.gg/jshbDHSpCY).

```bash
npm install decidekit
```