Qwen3-1.7B · Job-Posting JSON Extraction (LoRA)
A LoRA adapter for Qwen/Qwen3-1.7B that extracts a strict, flat 16-field JSON schema from
unstructured job postings.
It was trained on labels produced by gpt-4o-mini and benchmarked against that same teacher model.
The question the project set out to answer was narrow: can a small open model, fine-tuned on a few
thousand teacher-labelled examples, do this job closely enough to a cheap hosted API to be worth
running yourself?
Short answer: it reaches
0.884 macro-F1 against the teacher's
0.925 while serving 1k
documents for
$0.139 against $0.480. Read the
Limitations
before trusting that.
Model Details
Model Description
- Developed by: Raza Ali (@razaali1607)
- Model type: LoRA adapter (PEFT) for a decoder-only causal LM, supervised fine-tuning
- Language(s) (NLP): English
- License: Apache-2.0, inherited from the
Qwen/Qwen3-1.7B base model
- Finetuned from model:
Qwen/Qwen3-1.7B
Model Sources
Uses
Direct Use
Given the raw text of a job posting, the model emits a single JSON object conforming to a flat
16-field schema (title, company, location, employment type, seniority, salary range, education level,
required skills, and similar). It is intended for batch enrichment of job-posting corpora, where the
alternative is a per-document call to a hosted API.
Downstream Use
The adapter is a reasonable starting point for other strict-schema extraction tasks over short
English documents, though it has only been evaluated on job postings and would need re-training for a
different schema.
Out-of-Scope Use
- Any decision about a person. These fields are not verified facts; they are one model's reading
of a document that another model labelled. Do not use the output to screen, rank, or match
candidates.
- Non-English postings, or documents from other domains — untested.
- Treating output as ground truth.
posting_date in particular is unreliable (see below).
- General instruction following. The adapter is tuned narrowly for this one extraction format.
Bias, Risks, and Limitations
These are the reasons not to over-read the results table.
-
Teacher labels are not ground truth. Outside the 300 reviewed documents, every training label
is gpt-4o-mini's opinion, and the model is trained to imitate it, mistakes included. Where the
teacher was checked against a reviewer, its weakest fields were posting_date 0.167,
education_level 0.950 and company 0.957. The first is not a close call: the teacher fabricated
a plausible date for most postings that never stated one, and the fine-tune learned to do the same.
-
One domain, one seed, one configuration. Job postings only; SEED = 1337 throughout; a single
set of hyperparameters, one LoRA rank, one learning rate. No sweep was run and no confidence
intervals were computed, so nothing here speaks to variance across runs.
-
The gold set was model_verified, not human-verified end to end. A human audited a
28-document sample and found at least one field error in 25% of them. That residual error rate
is a floor under every accuracy number here — including the teacher's, which is scored against
the same set. There is no inter-annotator agreement figure, because there was one reviewer.
-
n = 300. The standard error on a per-field F1 at that size is around 0.030, so differences
smaller than about three points are not meaningful and should not be ranked. The fine-tune's
0.041 gap to the teacher is real but narrow.
-
Cost figures are derived, not measured. $/1k docs divides measured throughput by an assumed
$0.35/h GPU rate. A different rate or a spot instance moves the column without anything about
the model changing.
Recommendations
Validate the output against your JSON Schema at the boundary rather than trusting the model to always
emit valid JSON — it does so 99% of the time, not 100%. If you need a hard guarantee of shape, use
constrained decoding, but see the Results section first: it does not improve correctness here, and
it costs latency. Treat posting_date as unusable without a separate rule-based extractor.
How to Get Started with the Model
1from peft import PeftModel
2from transformers import AutoModelForCausalLM, AutoTokenizer
3
4BASE = "Qwen/Qwen3-1.7B"
5ADAPTER = "razaali1607/qwen3-1.7b-jobpost-lora"
6
7tok = AutoTokenizer.from_pretrained(BASE)
8model = AutoModelForCausalLM.from_pretrained(BASE, torch_dtype="float16", device_map="auto")
9model = PeftModel.from_pretrained(model, ADAPTER)
10model.eval()
11
12prompt = tok.apply_chat_template(
13 [{"role": "user", "content": f"Extract the schema as JSON:\n\n{posting_text}"}],
14 tokenize=False,
15 add_generation_prompt=True,
16) # use the same prompt template as training — see the repo
17
18out = model.generate(**tok(prompt, return_tensors="pt").to(model.device), max_new_tokens=256)
19print(tok.decode(out[0], skip_special_tokens=True))
The exact prompt template and the JSON Schema live in the
project repository; results will degrade if
you deviate from the training-time format.
Training Details
Training Data
- Corpus: 7,500 real postings from
xanderios/linkedin-job-postings
(MIT), deduplicated and length-filtered.
- Labels: 4,500 training rows labelled by
gpt-4o-mini via the OpenAI Batch API, at a total
labelling cost of $1.10.
- Held-out gold: 300 documents reviewed field by field. No gold document appears in training.
Training Procedure
Supervised fine-tuning (TRL SFTTrainer) on teacher-labelled prompt/JSON pairs.
Training Hyperparameters
- Training regime: fp16
- Method: LoRA, r = 16
- Trainable parameters: 1.00% of the base model
- Epochs: 2
- Seed: 1337
- LoRA alpha / dropout / target modules: [Fill in from your training config]
- Learning rate / batch size / max sequence length: [Fill in from your training config]
Speeds, Sizes, Times
- Training time: 3.3 hours
- Hardware: 1 × NVIDIA Tesla T4 (Turing, sm_75),
cuda:0 only
- Peak VRAM: 10.07 GB
Evaluation
Testing Data, Factors & Metrics
Testing data: the 300-document held-out gold set described above.
Factors: results are disaggregated per schema field in the project repository; fields with fewer
than 30 populated gold values are flagged low-n.
Metrics:
- schema-valid % — proportion of outputs that parse and validate against the JSON Schema.
- macro-F1 — per-field F1 averaged across the 16 fields. Parse failures score as wrong, which is
why the validity column matters to the accuracy column.
- p50 ms/doc (batch 1) — single-stream latency: what one user waits.
- amortized ms/doc @ best batch — wall-clock ÷ documents at the fastest non-OOM batch size. This
is a throughput figure and is never quoted as a latency.
- $/1k docs — derived from throughput at an assumed $0.35/h GPU rate.
Results
| arm | schema-valid % | macro-F1 | Δ vs teacher | p50 ms/doc (bs 1) | amortized ms/doc @ best batch | $/1k docs |
|---|
base_fewshot | 62.0 | 0.570 | −0.354 | 8900 | 8675 (bs 4) | 0.843 |
base_fewshot_constrained | 91.0 | 0.682 | −0.242 | 12448 | 12448 (bs 1) | 1.211 |
lora_ft (this adapter) | 99.0 | 0.884 | −0.041 | 8616 | 1428 (bs 8) | 0.139 |
lora_ft_constrained | 100.0 | 0.878 | −0.047 | 12852 | 12852 (bs 1) | 1.250 |
teacher (gpt-4o-mini) | 100.0 | 0.925 | ±0.000 | API | API | 0.480 |
| null baseline | — | 0.000 | — | — | — | — |
Latency figures: 10 timed documents × 3 repeats per arm, Tesla T4, fp16, plain
transformers.generate() (no vLLM). The teacher's latency cells read API because its measurement
is sequential network wall-clock from a laptop and is not comparable to a local generate(); its
cost uses standard, not Batch API, rates, since a latency-sensitive deployment cannot wait on a
24-hour queue.
Summary
Fine-tuning recovers most of the gap between a prompted small model and the hosted API that taught
it: macro-F1 0.570 → 0.884 against a teacher at 0.925, with schema-validity going 62% → 99%.
The result worth carrying away, though, is about constrained decoding. Constraining the decoder
to the JSON Schema takes validity from 62% → 91% on the baseline and 99% → 100% on the fine-tune, so
validity is essentially free. Accuracy is not. On the baseline the constraint genuinely helps
(−0.354 → −0.242 vs teacher) because parse failures were being scored as wrong. On the fine-tune,
which already emits valid JSON almost always, macro-F1 moves 0.884 → 0.878 — no improvement, inside
the ±0.030 standard error — while single-stream latency rises from 8616 ms to 12852 ms.
Constrained decoding guarantees the shape of the answer. It has nothing to say about whether the
answer is right.
Environmental Impact
Carbon emissions can be estimated using the
Machine Learning Impact calculator presented in
Lacoste et al. (2019).
- Hardware Type: NVIDIA Tesla T4
- Hours used: 3.3 (training) plus a small number of inference-benchmark hours
- Cloud Provider: Kaggle (free tier,
GPU T4 x2 accelerator, one GPU used)
- Compute Region: [More Information Needed]
- Carbon Emitted: [More Information Needed]
Technical Specifications
Model Architecture and Objective
Decoder-only causal language model (Qwen3-1.7B) with a LoRA adapter, trained with a
next-token-prediction objective on prompt/JSON-completion pairs.
Compute Infrastructure
Hardware
1 × NVIDIA Tesla T4 (16 GB, Turing sm_75). Peak training VRAM 10.07 GB.
Software
PEFT, TRL, Transformers, PyTorch, fp16. vLLM was deliberately not used — its Turing support is
degrading and debugging it would have cost GPU-hours the project did not have. Unsloth, ONNX Runtime
and GGUF export were out of scope. On an A10, L4 or A100 with vLLM, throughput would be substantially
better and the $/1k docs column would drop, so read the cost figures as an upper bound for this
serving path, not as the best achievable.
Citation
BibTeX:
1@misc{ali2026jobpostlora,
2 author = {Raza Ali},
3 title = {Qwen3-1.7B Job-Posting JSON Extraction (LoRA)},
4 year = {2026},
5 publisher = {Hugging Face},
6 howpublished = {\url{https://huggingface.co/razaali1607/qwen3-1.7b-jobpost-lora}}
7}
APA:
Ali, R. (2026).
Qwen3-1.7B job-posting JSON extraction (LoRA) [Model]. Hugging Face.
https://huggingface.co/razaali1607/qwen3-1.7b-jobpost-lora
Glossary
- macro-F1 — the unweighted mean of per-field F1 across all 16 schema fields, so a rare field
counts as much as a common one.
- schema-valid % — output parses as JSON and validates against the target schema.
- Constrained decoding — restricting the decoder at each step so only tokens that keep the output
conformant to the grammar are sampled.
- Amortized ms/doc — throughput, not latency: total wall-clock divided by document count at a
given batch size.
Model Card Authors
Model Card Contact
Framework versions