How to prompt AI to extract data from a document

Extraction fails in one specific way: the model guesses instead of admitting a field is missing. Define the schema, force a not-found token, and verify the numbers.

Steve Jefferson
Steve Jefferson
Developer Advocate
13 August 20261 min read

The technique that makes extraction reliable is boring: define every field before you show the model the document, force it to emit a specific value when a field is absent, and check the numbers against the source afterwards. Learning how to prompt AI to extract data from a document is mostly learning to stop asking open questions like "pull out the important details," because the model will answer that question, and it will answer it differently on every run.

This is the pattern, with a worked example and the two failure modes that cost real money.

Step 1: write the field list before you write the prompt

Extraction is a schema problem wearing a language problem's clothing. Decide what you want out, in exact terms, before you touch the document.

For each field, settle three things: its name, its type, and what happens when the document does not contain it. That third one is the whole ballgame. A model asked for an invoice due date on an invoice with no due date will not usually say the date is missing. It will calculate one from the issue date and standard payment terms, present it in the same format as every other field, and give you no signal that it was invented.

Step 2: force an explicit not-found value

The instruction that fixes this is one line, and it belongs in every extraction prompt you write:

For any field not explicitly stated in the document, output exactly:
  "NOT_FOUND"
Do not infer, calculate, or estimate any value. Do not use general
knowledge about how documents of this type are usually written.

Two details matter. Use a token that could never be a real value, so a downstream check can spot it: NOT_FOUND, not "n/a" or an empty string, both of which appear in real documents. And ban inference explicitly, because a model's default behaviour is to be helpful, and helpful means filling gaps.

This is the same principle behind why telling AI not to do something does not work in reverse: a bare prohibition is weak, a prohibition paired with a specific alternative action is strong. You are not saying "do not guess." You are saying "when you would guess, write this instead."

Step 3: pin the output format

Ask for JSON with the keys spelled out, not for a description of the data. Prose answers cannot be checked automatically, and "return JSON" without a schema returns a different shape each time. The mechanics are covered in how to get JSON output from AI, but the extraction-specific rule is to include the empty schema in the prompt itself so the model has a template to fill rather than a description to interpret. If your provider supports enforced schemas, as described in OpenAI's structured outputs documentation, use them: a schema the API validates beats a schema the model was asked to respect.

A worked example: invoices

Here is a complete prompt for a common case. It is deliberately plain.

text
Extract the following fields from the invoice below.

Rules:
- Copy values exactly as they appear in the document.
- For any field not explicitly stated, output "NOT_FOUND".
- Never infer, calculate or estimate a value.
- For every amount, also copy the exact line of text you took it from.
- Output only the JSON object, no commentary.

Schema:
{
  "invoice_number": "",
  "issue_date": "",
  "due_date": "",
  "supplier_name": "",
  "supplier_tax_id": "",
  "currency": "",
  "subtotal": "",
  "tax_amount": "",
  "total": "",
  "evidence": { "subtotal": "", "tax_amount": "", "total": "" }
}

Document:
<<<
[paste document text here]
>>>

The evidence block is the part people leave out and then regret. Asking the model to quote the source line for every number turns verification from a manual re-read into a string search. If the quoted line is not in the document, the number is fabricated, and you can catch that in code rather than in an accounts payable dispute three weeks later.

Step 4: verify the numbers, always

Three checks, in order of how much they will save you:

  1. Evidence check.

    Does each quoted line actually appear in the source text? A simple substring match catches fabrication.

  2. Arithmetic check.

    Does subtotal plus tax equal total? Do this in code, not in the prompt. Models are unreliable at arithmetic and completely reliable at copying digits.

  3. Format check.

    Are dates in one format, are amounts free of currency symbols and thousands separators? Normalise in code after extraction, never by asking the model to do both jobs at once.

If you want a second model pass as well, ask it to check rather than to redo, along the lines of prompting AI to check its own work. Re-extracting from scratch and comparing the two runs is a weaker test than it looks, because both runs share the same bias and often invent the same value.

Handling long or messy documents

Two situations break the single-prompt version.

The document is longer than one comfortable request. Split by section rather than by character count, and run one extraction per section with only the fields that section could contain. Splitting mid-table is what produces half-extracted rows. This is a different problem from prompting AI to summarise a long document, where losing detail is acceptable. In extraction it is not.

The document is a scan. Run optical character recognition first and check the text output yourself before extraction. A model handed garbled OCR will smooth it into plausible text, which is the worst possible failure: wrong values that read correctly. If your OCR turns a 7 into a 1, no prompt saves you.

Three fields that need a rule, not just a name

Most fields extract cleanly once the schema is explicit. Three do not, and they are the three that appear in nearly every business document.

  • Dates.

    Write the required output format into the field description, because 03/04 is ambiguous and the model will resolve it by guessing a locale. Say ISO 8601, and say to copy the raw string into a second field so the ambiguity stays visible.

  • Amounts.

    Specify whether you want the currency symbol, the thousands separator and the sign. A refund line that arrives as 1.250,00 in one document and (1,250.00) in another will otherwise land in your database as two unrelated numbers.

  • Names and addresses.

    Decide in advance whether you want them normalised or verbatim, and pick verbatim. Normalisation is a second job, it is lossy, and a model doing it silently will merge two distinct suppliers whose names differ by a suffix.

Batch extraction across many documents

Once the prompt works on one document, resist the urge to paste five in at once. Batching reduces accuracy in a specific and hard-to-notice way: the model carries values across documents, so the second invoice inherits the first one's tax rate when its own is unclear.

Run one document per request, keep the prompt identical, and store the raw response alongside the parsed result. When something looks wrong in your database in a month, the raw response tells you whether the extraction or the parsing was at fault. Keeping the prompt itself under version control matters here too, for the reason described in how to version your prompts: when accuracy drops, the first question is what changed.

When not to prompt AI to extract data from a document

Some documents should not be handed to a model at all. If the values are legally binding and nobody will check the output, the failure mode is silent and expensive. If the document is a structured file already, a parser is cheaper, faster and exact. And if you need the same twelve fields from ten thousand identical forms, a purpose-built extraction service will beat a prompt on cost and consistency.

The sweet spot is documents that vary in layout, arrive in modest volume, and get reviewed by a human before the numbers matter. That is most small-business paperwork, which is why this is one of the highest-value things to learn once you are past the basics of prompt engineering.

FAQ

Why does AI invent values that are not in the document?

Because completing patterns is what the model does. An invoice usually has a due date, so it produces one. Forcing an explicit NOT_FOUND value gives it a permitted way to leave the field empty.

Should I ask for JSON or a table?

JSON, with the empty schema included in the prompt. Tables are fine for reading and bad for parsing, and the schema-as-template approach keeps the key names stable between runs.

Can I extract from a PDF directly?

Only if the PDF contains real text. If it is a scan, run OCR first and read the OCR output before extraction, because a model will quietly smooth garbled characters into confident nonsense.

How do I know the extraction was correct?

Ask for the source line behind every number, then check in code that the quoted line exists in the document and that the arithmetic holds. Both checks are trivial to write and catch the failures that matter.

Does a bigger model extract better?

Somewhat, but format discipline matters more than model size. A clear schema and a not-found rule on a mid-tier model beats a vague request on a frontier one, at a fraction of the cost.

How did this land?

About the author

Steve Jefferson
Steve Jefferson

Developer Advocate

Steve builds something with Swarmz every week and writes up what worked, what broke, and what he'd do differently. Tutorials and hands-on guides are his lane.

Share

Get the next post in your inbox

One email a month. Product updates, engineering posts, and the best of Built with Swarmz.

I agree to receive emails about AI building tips and Swarmz product news. Unsubscribe any time.