Files
zzgandClaude Sonnet 5 15704f4ada Switch backend from laya to von
Measured against the same two benchmarks used for every prior backend
swap this project has made:

- Urgency noul: von 0.9995 (vs. laya's 0.77, kev's inverted 0.17) --
  essentially matches Jev's own claimed ~0.999, and correctly separates
  calm (0.059) from urgent.
- costslayer's L1 task-scope Choice classification (external stress test,
  costslayer itself unchanged): von scored 0.737 average, actually
  *behind* laya's 0.77-0.80, with a real 25% under-classification rate.

No backend wins both axes. Swapping anyway because Noul was this
project's clearest weak spot (kev inverted it, laya was only middling),
and because von ships its own /v1/systemone HTTP server -- removes the
need for a custom wrapper (serve_laya.py deleted; laya had no server of
its own). README's Known Limitations section now documents the Choice
weakness plainly rather than only reporting the win.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-19 19:40:45 -07:00

5.1 KiB

sysone

A local, self-hosted typed-decision classifier. Instead of generating text, it takes a state (some text or data) and a set of typed questions, and returns calibrated probabilities:

  • Noul — a yes/no question, answered as P(true).
  • Choice — pick one of several labeled options, answered as a probability per option.
  • Score — place the input on an ordered scale, answered as a continuous position on that scale plus a probability per level.

No chat model, no text generation, no hallucination risk — the model can only ever return a number or a label from a set you defined. Runs entirely on this machine: no API key, no external service, no per-call cost.

Architecture

sysone/ (this repo, stdlib-only, no dependencies)
    types.py    Choice / Score / Noul question specs + result types
    client.py   Classifier.invoke(state, questions) -> ClassifierResponse

        │  HTTP POST /v1/systemone
        ▼

von serve (external process, ~/work/von/.venv; not part of this repo)
    von-sdk's own built-in HTTP server -- speaks /v1/systemone natively,
    no wrapper needed.
    → localhost:8011

von-1.0.0 (395M-param ModernBERT encoder, Apache 2.0, runs on MPS)

Setup

If the model server is already running, skip to Usage. Check:

curl -s localhost:8011/v1/systemone -o /dev/null -w '%{http_code}\n' \
  -H 'content-type: application/json' \
  -d '{"state":"x","model":"von","questions":{"q":{"type":"noul","instructions":"x"}}}'

From scratch:

mkdir -p ~/work/von && cd ~/work/von
uv venv --python 3.12   # von-sdk requires Python >=3.12
uv pip install von-sdk

Run the server:

~/work/von/.venv/bin/von serve --port 8011 --backend modernbert --device mps

First run downloads the von-1.0.0 checkpoint from Hugging Face (~1.5GB) and serves on MPS (Apple Silicon GPU). Leave it running in its own terminal, or background it. It's a plain background process, not a managed service — if the machine restarts, re-run the command above. First startup after a restart takes a few seconds to load the model; each request after that is 20-50ms.

Usage

from sysone import Classifier, Choice, Noul, Score

classifier = Classifier()  # defaults to http://localhost:8011

response = classifier.invoke(
    state="Our production database is down and customers can't check out.",
    questions={
        "urgent": Noul(instructions="Does this need attention right now?"),
        "team": Choice(instructions="Which team should handle this?",
                        options=["billing", "technical", "sales"]),
        "severity": Score(instructions="How severe is this?",
                           levels=["minor", "moderate", "major", "critical"]),
    },
)

response.nouls["urgent"].noul          # -> probability, e.g. 0.94
response.choices["team"].best          # -> "technical"
response.choices["team"].probs         # -> {"billing": 0.03, "technical": 0.92, "sales": 0.05}
response.scores["severity"].score      # -> continuous index into `levels`, e.g. 2.6

Run the example and smoke test:

python3 examples/support_ticket.py   # a worked example
python3 smoke_test.py                # noul/choice/score sanity checks

Wire format (/v1/systemone)

Type Request criteria Response fields
noul none noul: P(yes)
choice {option: description} choice, probabilities (by option key), confidence
score [level_0, level_1, ...] (low → high) score (0-indexed position into levels), legend, probabilities (by index), confidence

Known limitations

  • Noul and Choice are not equally strong. This client's own testing found yes/no (Noul) judgments to be sharp and well-directed even on pragmatic, non-factual questions (e.g. urgency). Multi-way Choice judgments on fine-grained, domain-specific categories (tested: classifying software tasks by scope) were noticeably weaker, with a real tendency to under-predict how much a task actually requires. If your use case leans heavily on Choice with many closely-related options, verify against your own labeled examples before trusting it.
  • Raw confidence isn't necessarily calibrated for your task. The confidence field this client returns is the model's raw output for whatever domain it was trained on. Fitting your own temperature scalar on a held-out set is worth doing before using confidence for anything threshold-based (e.g. "auto-act above 0.85, else escalate").
  • High-cardinality choice questions are untested here. All examples in this repo use ≤5 options; large option sets are unverified.
  • English-only. Not exercised with non-English input.

Possible next steps

  • Fine-tune or otherwise adapt the Choice head for domain-specific multi-category tasks if that's your primary use case.
  • Fit per-question-type temperature scaling on a held-out set before relying on confidence for threshold-based decisions.
  • A LangChain-style wrapper and middleware (model routing, tool-call guardrails) built on top of this classifier are both natural extensions, not implemented here — this repo is the core classifier only.