Every signed contract holds a dozen facts that other systems need: who the parties are, when the agreement starts and ends, what is owed and when, and how much notice either side must give. In many companies those facts reach the CRM (customer relationship management system) because someone opens the PDF and types them in, and later someone else opens the PDF again because nobody trusts the typed version. Entity extraction is the technique that reads those facts out of the text automatically. This post explains how it works, and why the model is the smallest part of getting values you can rely on.
What entity extraction does
An entity, in this context, is a specific piece of information with a type: a company name, a date, an amount of money, a period of time. Entity extraction means finding those pieces in running text and labelling them. The older name for the task is named entity recognition, or NER, and today it is often done with a large language model (LLM) that is asked to return the fields in a fixed format. A few terms come up repeatedly, so here they are in one place.
- A field is one fact you want from every contract, such as the expiry date or the notice period.
- A span is the exact stretch of text the value was found in, along with its page and position.
- Confidence is the model's own score for how sure it is about a field. It is a hint, not a guarantee.
- Normalisation is the step that turns the found text into a typed value, such as a real date or a number with a currency.
- Provenance is the record of where a value came from: which document, which page, which span, which model version, and who reviewed it.
The rest of this post is about how those pieces fit together. If your documents are emails and mixed PDFs rather than contracts, getting structured JSON you can trust from emails and PDFs covers the same ideas from a different angle.
Choosing the fields before the model
Take a logistics firm covering pin codes across north India, with a few hundred transporter and warehouse agreements on a shared drive. The tempting brief is "extract everything". A better start is to look at the systems downstream and list what they actually consume. For that firm the list might be party names, effective date, expiry or term, renewal terms, contract value, currency, payment terms, governing law and notice period.
For each field, write down three things: its type, where it usually appears in your contracts, and what should happen when it is absent. A short list is better than a long one. Every field needs its own test examples and its own review rule, and an operations team will not maintain thirty of them.
How a contract becomes a record
A model that finds "the 3rd day of March, 2026" has done its job, but it has not given you a date. It has given you a string. Here is how a contract moves from file to confirmed record, and the model only does step two.
- The contract arrives as a PDF, a scan or a Word file.
- The extractor returns each field with its span and a confidence score.
- Normalisation code turns each string into a typed value.
- Checks compare the value with rules and with the other fields.
- A person reviews only the fields that failed a check.
- The values are written to the record system, first as proposed and then as confirmed.
- 01ContractPDF, scan or Word
- 02Extractfield, span, confidence
- 03Normalisestring to typed value
- 04Checkconfidence and rules
- 05Reviewfailed fields only
- 06Recordproposed, then confirmed
The model does the extraction step. Everything else is ordinary code and ordinary review.
Normalisation deserves more attention than it usually gets, because contracts write the same thing in many ways. It is plain deterministic code with tests, kept separate from the model.
Dates
Dates arrive written out in words, as numbers with an unclear day and month order, or as relative phrases such as "ninety (90) days from the Effective Date". A relative date can only be resolved after the effective date itself is known, so the order of normalisation matters.
Amounts
Amounts arrive as "INR 50,00,000", "Rs. 50 lakh", "fifty lakh rupees only", or a figure with no currency at all. Whether GST (goods and services tax) is included is often stated three pages away from the figure.
Parties
Parties appear twice: once as a legal name in the opening paragraph and afterwards as a defined term such as "the Transporter". The legal name then has to be matched to an existing account in the CRM, including the subsidiary that actually signed, not the group company everyone calls it by. Writing these matched values into the CRM and other systems is an integration problem as much as an AI one, which is the territory of enterprise application integration.
The documents that test an extractor
The clean template is the easy case, and it is also the case a person could handle quickly. The value of extraction lies in the rest, which is why the test set has to be built from the awkward documents. Here are the kinds I would make sure are in it:
- An amendment that changes one clause of a master agreement, so the right value lives in a different file.
- A rate that sits in an annexure, with the body of the contract only referring to it.
- Several amounts with different meanings on one page, such as a fee, a cap, a security deposit and a penalty per day of delay.
- Two dates that both look like a start date, the signature date and the effective date.
- A scanned page where OCR (optical character recognition, the step that turns an image of text into characters) has turned a 5 into an S inside a number.
- A defined term that is quietly redefined in a later section.
If a document type has never appeared in the test set, assume the extractor fails on it until it is shown otherwise. Scanned pages bring their own problems, and the ones that matter most are described in where accuracy breaks when vision models read forms and invoices.
Checks before a value is confirmed
The model's confidence score alone is not enough to confirm a field. A field also has to pass rules the model cannot know about: the expiry comes after the effective date, the amount has a currency, the party matched exactly one CRM account, and the notice period is a plausible number of days.
- Model confidenceabove that field's threshold
- Formata real date, number or code
- Consistencyagrees with the other fields
- Matchparty resolves to one account
- Human reviewonly after a failed check
A field that fails any layer goes to a person instead of the record.
The important part is what the review screen shows. It should show the one field, the page it was found on, and the highlighted span, so a reviewer confirms or corrects it in seconds. If it shows the whole contract, reviewers go back to reading everything, and the time saved disappears.
Confirmed or not, extracted values should not land directly in the live fields of the contract record. Write them as proposed values, in a staging table or in dedicated fields, with provenance attached. Downstream systems read only the confirmed value, and the confirmed value keeps its link back to the span, so anyone who doubts a renewal date can open the page and see it in context.
Provenance earns its place a year later. When a warehouse lease auto-renews because the notice date in the CRM was wrong, the first question is whether that date was typed, extracted or corrected. Without provenance there is no answer, and trust in the whole pipeline goes with it.
Where contract extraction goes wrong
From what I have read and discussed with the team, the problems are rarely in the model. They are in the steps around it. The test set is built from the standard template, so the amendments are discovered after launch. Accuracy is reported per document, when a single wrong expiry date on an otherwise perfect record is the failure that costs money. The date string is treated as a date and normalisation is skipped. The review queue shows the whole document. And values are written straight into live fields, with no record of where they came from.
What to do before the first field goes live
Here is a checklist that follows the order of the pipeline above.
- Each field has a type, a note on where it appears, and a rule for when it is absent.
- Normalisation code is tested against twenty real examples per field type, including relative dates and amounts with no currency.
- Thresholds are set per field, and the validation rules are written down.
- The review screen shows one field with its highlighted span.
- Proposed and confirmed values are stored separately, with provenance on both.
- Someone has run the pipeline on an amendment and on a scanned file and read the output.
The first concrete task is the field list, and the choice of model can wait until it exists. The list decides the test set, the normalisation code, the review rules and the record schema, which together are most of the work.

