Anvil

Live

Personal project - completed QLoRA fine-tuning of Llama 3.1 8B on synthetic contract extraction, with 100% JSON validity, $58.46 measured run cost, and a 0.80M-token monthly breakeven model.

Role
Solo - Python, QLoRA, eval, RunPod, cost modeling
Period
May 2026
Stack
  • Python 3.12
  • uv
  • QLoRA (NF4 + LoRA)
  • Unsloth
  • TRL (SFTTrainer)
  • OpenAI GPT-4o (synthesis and eval)
  • Llama 3.1 8B
  • Hugging Face gated model access
  • RunPod A40
  • Weights & Biases
  • Matplotlib
  • Ruff
  • mypy (strict)
  • pytest
  • GitHub Actions
Links

What it is

A focused engineering artifact, not a SaaS. The shipped pieces:

  • Dataset pipeline - generated 4,000 synthetic NDAs, MSAs, and licenses via GPT-4o with strict JSON-schema enforcement; curated 3,707 accepted records; split them into 2,966 train, 371 validation, and 370 test examples.
  • Training - QLoRA (NF4 + LoRA, rank 16, alpha 32, all_linear targets) on Llama 3.1 8B via Unsloth on a single RunPod A40. The paid run completed 558 optimizer steps in 8,259 seconds, about 2h 18m.
  • Eval - base, fine-tuned, and GPT-4o predictors behind one protocol, run over the same 370-example held-out test split and scored on JSON validity plus per-field extraction quality.
  • Cost model - measured training run cost (synthesis API, GPU time, GPT-4o eval) plus a self-hosted $/1M-tokens model and breakeven volume against continuing to call GPT-4o.
  • CI and rehearsal - the full pipeline can be rehearsed on an M1 against fixtures before renting a GPU; CI covers parsing, schema, cost, charts, preflight, training config, and eval utilities.

Why I built it

To prove I can fine-tune and evaluate an open model end to end, with a defensible cost story, rather than only calling a hosted API. The useful question is whether the fine-tune closes the gap to a frontier model on a narrow structured-output task, and how long it takes for the one-time training cost to pay for itself.

Anvil answers that with numbers tied to committed artifacts: the dataset counts, training log, evaluation JSON, chart images, and cost report are all reproducible from the repo workflow.

Measured result

The base model failed the strict schema gate: 0% valid JSON on the 370-case held-out test split. The fine-tuned adapter produced 100% valid JSON, slightly above GPT-4o’s 99.73% validity on the same cases.

Bar chart comparing JSON validity for base, fine-tuned, and GPT-4o predictors.
JSON validity is the gate: unparsable output receives no field credit.

On per-field extraction score, the fine-tuned adapter reached a 0.899 macro score versus GPT-4o’s 0.881. The task is narrow and synthetic, so I treat that as evidence that the adapter learned the target schema and field distribution, not as a broad claim that it beats GPT-4o.

Grouped bar chart comparing fine-tuned and GPT-4o extraction scores by contract field.
Per-field score across the held-out synthetic contracts.

How it works

Data synthesis with an anti-contamination guard

The training set is synthetic contracts generated under a strict JSON schema, so every sample has a known ground-truth extraction. Before training, a guard hashes the normalized contract text of every sample and aborts the run if any document appears in more than one split. That removes the most common way a fine-tuning benchmark quietly inflates its own scores.

QLoRA on a single A40, rehearsed on M1

The same orchestrator that runs the paid RunPod job runs in a dry-run mode on a base-M1 MacBook against in-repo fixtures, end to end (data-smoke -> train-smoke -> eval-smoke -> cost) with zero API spend. That rehearsal must pass before a paid GPU is rented.

The paid run used a RunPod A40 at $0.44/hr, trained for 3 epochs, and ended at train loss 0.346 and eval loss 0.328.

Line chart of Anvil train and validation loss over 558 optimizer steps.
Training converged quickly and stayed stable through the 3-epoch A40 run.

Three-way eval gated on JSON validity

Base, fine-tuned, and GPT-4o predictors answer the same prompts. Validity is the gate: an output that does not parse against the schema earns no field credit, because an F1 number on unparsable JSON is meaningless. This is where the base model collapses and the fine-tune becomes useful.

Cost and breakeven

The full run cost $58.46: $54.00 for synthesis, $1.76 for A40 GPU time, and $2.70 for GPT-4o eval. The self-hosted inference line is intentionally labeled as a configured A40 serving assumption, not a measured serving benchmark from this project.

Bar chart comparing Anvil's configured A40 self-hosted cost per million tokens against GPT-4o and Claude Sonnet.
Self-hosted cost uses the configured A40 serving-throughput assumption.

At those assumptions, the one-time run cost breaks even against GPT-4o at 0.80M tokens per month over a 12-month horizon.

Breakeven curve comparing cumulative fine-tuned model cost against GPT-4o over twelve months.
Breakeven volume: 0.80M tokens per month against GPT-4o.

Status

Done. The core Anvil milestone is complete: paid data generation, training, evaluation, cost analysis, charts, and documentation are landed. I am intentionally not treating Hugging Face publishing or a demo Space as part of the scope.

Questions

What is Anvil?

Anvil is a completed fine-tuning and evaluation artifact for structured contract extraction. It synthesizes contracts with GPT-4o, curates and splits the dataset, fine-tunes Llama 3.1 8B with QLoRA on a single A40, and compares base, fine-tuned, and GPT-4o predictors on the same held-out test split.

What did the paid run prove?

The fine-tuned adapter reached 100% JSON validity on 370 held-out contracts, while the base model produced 0% valid JSON. It also slightly exceeded GPT-4o on macro field score, 0.899 versus 0.881, on this synthetic extraction benchmark.

How is the methodology kept honest?

An anti-contamination guard hashes normalized contract text and aborts if a sample appears in two splits. JSON validity gates every score, so output that does not parse against the strict schema gets no field credit. The cost model separates measured run cost from the configured A40 serving-throughput assumption.

How does Anvil relate to Forge?

Forge answers how cheap and fast self-hosted inference is once utilization, latency, and quantization are accounted for. Anvil answers whether a small QLoRA fine-tune can close the gap to a frontier API on a narrow task.

Published May 28, 2026, 10:29 PM GMT-3 · Updated May 31, 2026, 10:35 PM GMT-3

← All projects