Schemer, on-device text to structured JSON
Schemer is a schema-native extraction model: it takes free text and a developer-supplied schema, and returns a JSON object that matches the schema. The schema is the model's input, not a prompt suggestion, and every field is decoded by a head built for its type. It does not generate text.
- 211M parameters: 218 MB int8 (verified lossless) or 111 MB int4
- 13 languages, 0.041 per-language accuracy spread
- Documents up to ~1,100 tokens (roughly 3 pages); short inputs run a fast 256-token path
- Offline, ~200 MB RAM; 8.7 ms per encoder pass on an Apple Neural Engine
Three guarantees no generative extractor offers:
- Typed by construction. Labels are always one of your declared choices, numbers arrive clamped to your range, datetimes are ISO 8601, and relative expressions ("tomorrow at 3pm", "i morgen kl 15", misspellings included) resolve against device time.
- Absence detection. Fields the text does not state come back null. Schemer scores 0.94 on this; every LLM and span extractor we benched, at any size, scores 0.37 to 0.43.
- Verbatim with offsets. Extracted strings are substrings of the input; the SDK surfaces character offsets, so hallucination auditing is a substring check.
Private pre-release. Weights are staged here ahead of the
0.0.1SDK release.
Try it
- iOS / macOS: Swift SDK coming soon (lands with
0.0.1). The int4 Core ML encoders incoreml/are ANE-validated (8.1 ms/forward at the 256-token shape) and eval-confirmed on-device. - Android / web: ONNX graphs are staged in
onnx/(int4 web encoder + fp32 support graphs, quality measured through the actual graphs); the JS harness port lands with0.0.1. - The deterministic harness (relative dates, duration units, format gates,
string trims, anchor injection) ships as data in
harness/*.json; every SDK port must pass the bundled conformance fixtures bit-for-bit.
Files
| File | Format | Size | Use |
|---|---|---|---|
model-int8.pt |
int8 per-row | 218 MB | start here; full quality (0.763 OOD) |
model-int4-awq.pt |
int4 AWQ | 111 MB | when download or RAM is tight (0.757 OOD) |
model-fp32.pt |
fp32 | 850 MB | converting to other formats; not for deployment |
onnx/encoder_web4e4.onnx |
int4 ONNX | 111 MB | run in the browser or on Android |
onnx/*.onnx |
fp32 ONNX | 80 MB | decoding graphs; always ship with the encoder |
coreml/*.mlpackage.zip |
int4 Core ML | 84 MB each | run on iOS / macOS; 256 + 1216 token shapes, ANE-resident |
tokenizer/, keep_ids.json |
11 MB | required by every runtime | |
harness/*.json |
<1 MB | post-processing rules every SDK port must implement | |
manifest.json |
verify downloads; measured quality per artifact |
Use
The schema is plain JSON (paste an OpenAI/Gemini responseSchema and it
works). One call per document:
{
"title": {"type": "string", "describe": "the task title", "max_chars": 60},
"guest": {"type": "string", "describe": "person the meeting is with", "nullable": true},
"start": {"type": "datetime","describe": "start time", "nullable": true},
"duration_min": {"type": "number", "describe": "duration in minutes", "min": 0, "max": 480, "nullable": true},
"is_recurring": {"type": "boolean", "describe": "is this a recurring task"}
}
Input "Meeting with Sarah tomorow at 3pm for an hour to review the Q3 deck. Recurring weekly." returns (with device time 2026-07-05):
{"title": "review the Q3 deck", "guest": "Sarah",
"start": "2026-07-06T15:00", "duration_min": 60, "is_recurring": true}
Note the typo tolerance, the relative-date resolution, the unit conversion
("an hour" to 60), and the factoring: the title is the purpose of the
meeting, the person lands in guest, and the temporal clutter lands in
the temporal fields.
Model
- Encoder: pruned mmBERT-base (22 layers, 103k-token vocabulary kept of
256k), jointly encoding
[schema summary ||| document]. Two compiled input shapes: 256 tokens (records) and 1216 tokens (documents). The 1216-token shape is the input limit: schema summary + document together; longer inputs are truncated, so budget roughly 1,100 tokens of document. - Reader: one shared cross-attention reader over encoder states.
- Heads: thin per-type decoders: label entailment, 3-way boolean (absent/false/true), BIO span tagging for strings and arrays with trained presence gates, datetime and number component decoders.
- Harness: deterministic post-processing (locale number parsing, ISO composition, 13-language relative-date lexicons, format gates). Shipped as data plus a reference implementation; ports are conformance-tested.
Evaluation
2,600 out-of-distribution records, 25 schemas the model never saw, 13 languages, scored by an order-insensitive, absence-aware scorer. Every competitor ran through the same scorer in its documented best configuration; sizes are measured bytes of the artifact benched.
| Model | Overall | Absence (boolean) | Params | On disk |
|---|---|---|---|---|
| Claude Haiku 4.5 (API) | 0.842 | 0.431 | n/a | API only |
| Qwen 3.5 9B | 0.822 | 0.432 | 9.1B | 9.1 GB |
| Ministral 3 8B | 0.818 | 0.430 | 8.0B | 17.8 GB |
| Gemma 4 E2B (official int4 QAT) | 0.808 | 0.429 | 5.1B | 8.3 GB |
| Schemer | 0.763 | 0.939 | 211M | 218 MB int8 |
| NuExtract-2.0-2B | 0.761 | 0.406 | 2.2B | 4.4 GB |
| Schemer (int4) | 0.757 | 0.933 | 211M | 111 MB int4 |
| GLiNER2-multi | 0.682 | 0.393 | 307M | 309 MB int8* |
| Qwen 3.5 0.8B | 0.680 | 0.371 | 0.87B | 1.75 GB |
| FunctionGemma 270M (tool calling) | 0.337 | 0.161 | 0.27B | 0.54 GB |
*GLiNER int8 sizes verified by us with the same quantize-and-rebench methodology as our own int8 claim (accuracy held within 0.004 of fp32).
Per field type
Bold marks the best score in each row. Schemer's architecture shows plainly: it owns the typed/absence rows and trails a 10x-larger extraction LLM on free-text rows.
| Type | Schemer | Schemer (int4) | NuExtract-2.0-2B (2.2B) | Qwen 3.5 0.8B |
|---|---|---|---|---|
| boolean | 0.939 | 0.933 | 0.406 | 0.371 |
| datetime | 0.864 | 0.853 | 0.727 | 0.584 |
| array | 0.812 | 0.808 | 0.873 | 0.772 |
| number | 0.737 | 0.739 | 0.751 | 0.742 |
| label | 0.684 | 0.671 | 0.778 | 0.697 |
| string | 0.661 | 0.655 | 0.886 | 0.783 |
Per language
| Language | Schemer | Qwen 3.5 0.8B | GLiNER2-multi |
|---|---|---|---|
| French | 0.779 | 0.692 | 0.739 |
| Spanish | 0.778 | 0.696 | 0.735 |
| Italian | 0.775 | 0.692 | 0.733 |
| Portuguese | 0.775 | 0.704 | 0.726 |
| German | 0.769 | 0.678 | 0.703 |
| Norwegian | 0.769 | 0.643 | 0.708 |
| English | 0.768 | 0.744 | 0.766 |
| Danish | 0.767 | 0.661 | 0.709 |
| Swedish | 0.766 | 0.650 | 0.733 |
| Dutch | 0.756 | 0.655 | 0.749 |
| Chinese | 0.742 | 0.693 | 0.435 |
| Polish | 0.740 | 0.652 | 0.711 |
| Japanese | 0.737 | 0.685 | 0.425 |
| overall | 0.763 | 0.680 | 0.682 |
Schemer scores 0.763 overall to NuExtract-2.0-2B's 0.761 at a tenth of the parameters, leads every model under 1B parameters, wins all 13 languages against both the strongest sub-1B LLM and the closest task-specific extractor, and is the only model at any size with reliable absence detection. Long documents: 0.724 at ~1,100 tokens; 0.687 when the document contains same-type distractor records.
Limitations
- Nested schemas (arrays of objects) are not supported yet.
- Extractive strings only: Schemer will not compose or rewrite text; abstractive titles from messy prose trail 2B+ LLMs (0.661 vs ~0.9). It does factor titles extractively (purpose clause, people and times split into their fields), but the title is always a substring of the input.
- Judgment labels requiring world knowledge (severity triage) trail the 2B+ class (0.684 vs ~0.85).
- Not a NER model: it fills your fields; it does not enumerate every entity mention (CrossNER span-F1 0.24 vs GLiNER2's 0.59).
- English is the weakest of the 13 languages relative to competitors.
License
Desert Ant Labs Source-Available License, Version 1.0. Free below 100,000 monthly active devices per platform, for each model; above that a commercial license is required (licensing@desertant.ai). You may embed the model in your application; you may not use it, its outputs, or its logs to train a competing on-device model. Credit Desert Ant Labs in your app: https://license.desertant.ai/attribution.
Third-party upstream components retain their original licenses; see
THIRD_PARTY_NOTICES.md.
Citation
@software{valid_2026,
title = {Schemer: on-device text to structured JSON},
author = {Desert Ant Labs},
year = {2026},
url = {https://huggingface.co/desert-ant-labs/schemer},
}
© 2026 Desert Ant Labs · https://desertant.ai