contract-extractor / docs /DECISIONS.md
myke69's picture
Add files using upload-large-folder tool
3752e5d verified
|
Raw
History Blame Contribute Delete
4.38 kB

Decisions, in plain English

This explains what we changed and why, without jargon. Read top to bottom.

1. Which branch do we build on?

We have three branches:

  • main β€” the original working app.
  • feature/complete-ui β€” main plus bug fixes and 5 new features (Risk Heatmap, Contract Comparison, Chat, Defined-Terms glossary). It also swapped the AI model that tags clauses to "LegalBERT" β€” that swap was a mistake (see below).
  • dynamic β€” the one we use. Built on main, it adds the dynamic baseline, all the genuine bug/accuracy fixes, the 5 features, and the fine-tuning tools β€” while keeping main's better DeBERTa model (no LegalBERT).

Decision: use dynamic. It is the best of all worlds, and merges cleanly into main.

2. LegalBERT vs DeBERTa β€” why we did NOT use LegalBERT

The app tags each clause with a type ("this is a liability clause", "this is an auto-renewal clause"). It uses an AI model to do that.

  • The name "LegalBERT" sounds better because it has "legal" in it. But LegalBERT, on its own, cannot classify anything β€” it only understands legal words. To make it classify, you must train it first.
  • The feature/complete-ui branch tried to use LegalBERT without training, by comparing "how similar" a clause is to a description. That method is weak and was never measured. It also came with a stricter software licence.
  • The original model (DeBERTa) can classify out of the box with no training, scored a real 0.61 in our tests, and has a clean licence.

Decision: keep DeBERTa. "Legal" in the name did not make it better.

3. The dynamic baseline β€” removing the hardcoded numbers

The app flags risky clauses by comparing them to "what's normal" (e.g. "a liability cap above 12 months is risky"). The problem: those numbers (12 months, 60 days, 99% uptime…) were typed directly into the code. If a judge asks "where does 12 come from?", the honest answer was "we made it up."

We fixed this:

  • The numbers now live in a data file with a source, not in the code.
  • A script (extract_cuad_baselines.py) can calculate those numbers from 500+ real contracts, so the answer becomes "it's the median of 500 real contracts" instead of a guess.
  • As you upload your own contracts, the baseline can adapt toward them β€” but it never drops below the safe default, so nothing breaks.
  • A safety test proves the new system produces the exact same flags as before on our demo contract, so accuracy did not drop.

Decision: baselines are now data, not hardcoded β€” and provably safe.

4. Fine-tuning β€” making the clause tagger smarter

"Fine-tuning" = taking the DeBERTa model and teaching it our exact task using thousands of example clauses that experts already labelled (the CUAD dataset, 13,000+ labels).

  • Today (no training): 0.61 accuracy.
  • After fine-tuning: expected 0.75–0.85 (a real, measurable jump).

We built the full toolkit so the team isn't stuck:

  1. prepare_cuad.py β€” turns the raw dataset into training examples.
  2. train_classifier.py β€” trains the model (one command).
  3. eval/run_eval.py --classifier finetuned β€” measures the result.

Training the full model is faster on a GPU (e.g. Google Colab); the tools run anywhere. See FINE_TUNING.md.

Decision: fine-tune DeBERTa (not LegalBERT).

5. Do we train Qwen? No.

Qwen is the separate AI that writes out obligations in plain English. It is a different kind of model (it generates text, it doesn't tag).

  • It already works without training.
  • Training it would need a GPU, a special dataset we don't have, and lots of time β€” for little gain.
  • The cheap, same-day way to improve it is better instructions/examples in the prompt, not training.

Decision: do NOT train Qwen. Improve it with prompting if needed.

Summary table

Question Answer
Which branch? dynamic
LegalBERT or DeBERTa? DeBERTa (LegalBERT was worse + unmeasured)
Hardcoded baselines? Replaced with data-derived, adaptive baselines
Fine-tune the tagger? Yes β€” DeBERTa on CUAD (0.61 β†’ ~0.75–0.85)
Train Qwen? No β€” prompt-tune instead