Belay · learned classifier · demo

A classifier that learns from the cloud, in your browser

Support messages arrive one by one. A small embedding model in this tab answers each one when it is confident enough; otherwise the cloud model answers, and the local classifier learns from that answer. Watch the share it handles on its own grow while its accuracy holds.

The embedding model downloads once and is cached by your browser.

Over time

Each point covers the 50 messages before it.

Messages

The newest first. When the device answered wrong, teach it the right label: a correction counts three times as much as a cloud answer.

Try your own

Classified on this device only: nothing you type here is sent anywhere. Pick the right team to teach it.

How it works

Each message is embedded with bge-small-en-v1.5 through transformers.js. A small classifier on the embeddings (nearest neighbors first, a softmax layer once it has enough examples) predicts the team. Its score becomes a confidence by Platt scaling, fitted on how it did on messages it had not seen yet, so the threshold keeps meaning "accept when at least this likely right". Below the threshold the message goes to the cloud, and the cloud's answer becomes a training example. Explore also sends a share of confident messages to the cloud, to keep checking the local answers: any of them (uniform), or mostly those it is least sure of (informative). A message unlike anything it has stored goes to the cloud however confident the vote is (the distance gate). What it learned can be exported as a file (embeddings, no text) and imported in another browser.

The cloud here is simulated with the dataset's labels (1,500 messages from the Bitext customer support dataset, CDLA-Sharing-1.0), and each call is priced at $0.0020, what Claude Opus 5.5 cost per message in the ticket-triage calibration. Only embeddings are stored, never the text.

import { task, fetchAdapter } from '@swissspidy/belay-core';
import { learnedClassifier, transformersEmbedder, indexedDbStore } from '@swissspidy/belay-learn';

const triage = task({
  name: 'ticket-triage',
  schema: { type: 'categorical', options: ['account', 'billing', 'order', 'shipping', 'feedback'] },
  local: learnedClassifier({ embedder: transformersEmbedder(), store: indexedDbStore() }),
  cloud: fetchAdapter({ url: '/api/belay' }),
  threshold: 0.9,
  explore: 0.05,
});

The guide walks through adding it to an app: loading the model, shipping a seed of labeled examples, collecting corrections, tuning and monitoring. On ticket triage, starting from nothing, it answered 86% of 1,500 messages on the device at 99.7% accuracy (all results).

Training a small student on an LLM's answers and deferring when it is unsure is known in research as neural caching or online cascade learning (Cache & Distil, OCaTS, Nie et al.). This brings it into the browser, on the user's device.