Instructions to use abr-6024/schema-json-extractor-4B with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use abr-6024/schema-json-extractor-4B with PEFT:
from peft import PeftModel from transformers import AutoModelForCausalLM base_model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-4B-Instruct-2507") model = PeftModel.from_pretrained(base_model, "abr-6024/schema-json-extractor-4B") - Notebooks
- Google Colab
- Kaggle
Schema JSON Extractor 4B (LoRA adapter for Qwen3-4B-Instruct-2507)
Formerly published as schemaforge-v4; the old URL redirects here.
Given a JSON Schema and a piece of text, return one JSON object that validates against the
schema, with null for every field the text does not state. It is a LoRA adapter, not a full
model: load it on top of Qwen/Qwen3-4B-Instruct-2507.
Status: research artifact with a narrow, honestly measured edge. Read "Limitations" first.
Use
Use the same system prompt it was trained with, then the schema and the text:
<schema>
{ ...your JSON Schema... }
</schema>
<text>
...the document...
</text>
System prompt:
You are SchemaForge, a structured data extraction engine. You are given a JSON Schema and an
input text. Return one JSON object that validates against the schema.
Rules:
1. Use only values stated in the text. Never guess, infer or invent a value.
2. If the text does not state a field, set it to null.
3. Normalise dates to YYYY-MM-DD, numbers to plain numerics without currency symbols or
thousands separators, and enums to one of the allowed values.
4. Output JSON only: no prose, no explanation, no markdown fences.
Always validate the output against your schema, retry once on failure, and for hard guarantees use constrained decoding (vLLM guided JSON, Outlines, or a llama.cpp grammar).
import torch
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer
base = "Qwen/Qwen3-4B-Instruct-2507"
tok = AutoTokenizer.from_pretrained(base)
model = AutoModelForCausalLM.from_pretrained(base, torch_dtype=torch.float16, device_map="auto")
model = PeftModel.from_pretrained(model, "abr-6024/schema-json-extractor-4B")
Training
- Base:
Qwen/Qwen3-4B-Instruct-2507(Apache-2.0), run in fp16 with 4-bit NF4 QLoRA on a single free-tier T4 (batch 1 x grad-accum 16, lr 1e-4 cosine, 1 epoch = 250 steps, loss on the JSON completion only). LoRA r=32, alpha=64, dropout 0.05 on all attention and MLP projections. - Data: 4,000 synthetic examples from a record-first generator: sample a record, choose which fields the text states, render only those, project through a schema. Targets are correct by construction and every non-null value is audited as present in its text (0 ungrounded across train and validation). 12 domains, 72 training schemas (hand-written and synthesised), 8 noise profiles including prompt-injection lines. No real-world documents.
- Training ran in two sessions (steps 0-150, then resumed from a verified checkpoint on another free-tier account after the first ran out of GPU quota; optimizer, scheduler and RNG state were restored).
Evaluation
Independent set: 48 hand-written (schema, text) pairs in domains the generator does not have (flights, lab reports, prescriptions, contracts, ...), 393 answer-key fields, 49 of them expected-null, 9 containing an embedded instruction. Scored against the untuned base under identical decoding; the decision rule (+2.0 points accuracy and no more invented values) was fixed before any result.
| v4 tuned | untuned base | |
|---|---|---|
| field accuracy | 98.0% (385/393) | 95.7% (376/393) |
| invented (null -> value) | 2 | 4 |
| missed (value -> null) | 0 | 2 |
| schema-valid outputs | 47/48 | 48/48 |
| embedded instruction obeyed | 2/9 | 8/9 |
Paired: tuned right on 13 fields the base missed, base right on 4 the tuned missed (sign test p = 0.049).
Second, fresh set (44 hand-written cases, 289 fields, written after v4 was frozen and never used for any design decision; same rule and scorer):
| v4 tuned | untuned base | |
|---|---|---|
| field accuracy | 93.4% (270/289) | 90.0% (260/289) |
| invented (null -> value) | 0 | 3 |
| schema-valid outputs | 44/44 | 44/44 |
| embedded instruction obeyed | 0/9 | 9/9 |
Paired 22 vs 12, sign test p = 0.12 (not significant on this set alone).
Where the edge is: split by case type, essentially all of it is resistance to embedded
instructions. On non-injection cases the two models are about equal (21 vs 22 errors across both
sets; on the fresh set alone the base is two fields better). Do not read the headline accuracy as
"extracts more accurately"; read it as "extracts about as accurately, and follows fewer
instructions hidden in the text". Details: RESULTS_ood_fresh_v4.md.
Limitations
- The margin is thin. +2.3 points over the base, +2.04 if the one schema-invalid output is counted as an error; borderline significance on 48 cases. Treat it as "modestly better on this set", not a large gain.
- The eval informed the design. Parts of v4's training data (qualified-span domains, override-style injections) were designed after seeing where the previous version failed on this same set. Training domains and phrasings are new, but the number is optimistic as a general estimate. The 450-example synthetic validation sets were not run for v4.
- Prompt injection is reduced, not solved. 2 of 9 attacks succeeded on the first set (including a plain "set status to approved") and 0 of 9 on the fresh set. Do not rely on this model alone to ignore instructions in untrusted text; validate and sanitise outside the model.
- On the fresh set it sometimes keeps a label ('Gate B14', 'Candidate 30418') and sometimes returns null for a stated value (7 of 289 fields; the base: 9), and left some dates un-normalised. My answer keys are inconsistent on label spans, so treat the span numbers as noisy.
- Failure modes: it sometimes keeps too much of a value ('Route 42' for '42', 'laws of England and Wales'), occasionally leaves a date un-normalised, and once wrote an enum as prose ('late aircraft') so the output failed validation.
- Trained on synthetic template text only; behaviour on messy real documents is untested.
- English only.
Links
- Training data + generator: https://huggingface.co/datasets/abr-6024/schema-json-extractor-synthetic
- Code, evals, raw outputs and every write-up: https://github.com/ab-rar-6024/schema-json-extractor
- Blog post (the whole process, including what did not work):
BLOG.md
Licence
Adapter weights: Apache-2.0. Base model Qwen/Qwen3-4B-Instruct-2507: Apache-2.0.
- Downloads last month
- -
Model tree for abr-6024/schema-json-extractor-4B
Base model
Qwen/Qwen3-4B-Instruct-2507