Two Jev calls, one optional trim. Here is exactly what happens.
jextract treats extraction as retrieval plus decision, never generation. LiteParse turns the PDF into positioned text in memory. Jev, a model that answers questions with probabilities instead of writing text, is asked once where each field lives and once which candidate span is its value; free-text spans get one more question to trim them to the exact words. Everything below is from one real run over the sample invoice: 12/12 fields, 813ms, $0.00055.
- PDF bytes
- taxonomy: fields with name, description, type
- text items with boxes (no OCR unless asked)
- lines by baseline
- segments at wide x-gaps: columns, label | value
- chunks by vertical gap, ≤ 900 chars
- 6 chunks with bbox
- page sizes
- state = { document_chunks: { c0: …, c5: … } }
- 12 questions, one per field
- each question: which chunk holds the value of <field>? options = chunk ids + none
- answers in parallel over the same state
- > 22k tokens → windows in parallel, merged
- per field: distribution over chunks
- p(none) = field absent
- top chunk (+ runner-up or neighbour) per field
- typed candidates: regex, label splits, segments, proper nouns, each marked «…» in its line
- state = only the located chunks
- choice per field over candidates + none
- enum → its options · boolean → yes/no
- text, normalised value
- confidence = p(chosen) × (1 − p(none))
- page, bbox, top candidates
- string/id spans that came from a line, segment or label split
- every prefix/suffix token window of the span (2..n tokens)
- noul per field: is the picked span already exact?
- choice per field: if not, which window is the complete value?
- trim applies only when p(exact) < 0.5
- exact span, sub-box
- confidence × (½ + ½·p(window))
- `refined.from` keeps the original
One field, end to end.
The page on the left is the real invoice drawn from LiteParse boxes. The right pane shows the actual question Jev received for the chosen field and the probabilities it returned, taken from the captured requests below.
Every text item with its font, size and box. No layout model, no OCR unless asked. jextract rebuilds lines by baseline and splits them into segments wherever the horizontal gap is wide, so labels, values and columns stay separate and each keeps its own box.
Why chunks as state
Jev reads the state once and answers every question against it. Putting the whole document in as chunks and asking one question per field costs one request, and the answer is a distribution over chunk ids, which is exactly a retrieval result with calibrated scores.
Why candidates are cut in code
A date, an amount or an IBAN has a shape. Regex finds every span of that shape for free; Jev only has to decide which one is the field. The value returned is a real span with a real box, so it can be verified against the page and never hallucinated.
Why this is fast and cheap
Parsing is milliseconds. Two Jev requests of a few thousand input tokens each run in about 150 ms and cost a few hundredths of a cent. There are no output tokens, so the field count barely moves the cost and never adds a serial decode step.
Request by request.
Open any row to see the question text, the options offered and the probability Jev put on each. The app shows this same view for your own documents under the Jev calls tab.
3 requests, 30 questions, 13.2k tokens, $0.00055.
Every request carries a state (the chunks Jev reads) and a set of questions answered in parallel over that state. Nothing is generated: each answer is a probability distribution over the options offered, which is why the whole taxonomy fits in two round trips, three when a free-text span needs trimming.
INVOICE Northwind Traders Ltd. 14 Harbour Street, Suite 300 Seattle, WA 98101 Invoice number: NW-2026-0912 billing@northwind.example Invoice date: September…
Bill to Ship to Contoso Pharmaceuticals GmbH Contoso Distribution Center Attn: Accounts Payable Industriepark 4 Friedrichstraße 120 60314 Frankfurt am M…
Description Qty Unit price Amount Jev inference - 1.2B input tokens (September) 1 $50.40 $50.40 Enterprise support plan - Gold tier 1 $1,200.00 …
Subtotal $3,670.40 Discount (5%) -$183.52 VAT 19% $662.51 Total due $4,149.39
Payment instructions Bank: First Cascade Bank IBAN: GB29 NWBK 6016 1331 9268 19 SWIFT/BIC: NWBKGB2L Reference: NW-2026-0912
Thank you for your business. Late payments accrue 1.5% interest per month.
INVOICE Northwind Traders Ltd. 14 Harbour Street, Suite 300 Seattle, WA 98101 Invoice number: NW-2026-0912 billing@northwind.example Invoice date: September…
Bill to Ship to Contoso Pharmaceuticals GmbH Contoso Distribution Center Attn: Accounts Payable Industriepark 4 Friedrichstraße 120 60314 Frankfurt am M…
Description Qty Unit price Amount Jev inference - 1.2B input tokens (September) 1 $50.40 $50.40 Enterprise support plan - Gold tier 1 $1,200.00 …
Subtotal $3,670.40 Discount (5%) -$183.52 VAT 19% $662.51 Total due $4,149.39
Payment instructions Bank: First Cascade Bank IBAN: GB29 NWBK 6016 1331 9268 19 SWIFT/BIC: NWBKGB2L Reference: NW-2026-0912
Thank you for your business. Late payments accrue 1.5% interest per month.
picked: Northwind Traders Ltd. line: INVOICE Northwind Traders Ltd.
picked: Contoso Pharmaceuticals GmbH line: Contoso Pharmaceuticals GmbH Contoso Distribution Center
picked: GB29 NWBK 6016 1331 9268 19 line: IBAN: GB29 NWBK 6016 1331 9268 19
- Why two Jev calls and not one?
- The second call's options depend on the first call's answer: candidates are cut from the chunk Jev located. Both calls fan out over every field in parallel, so the count is two per document whether the taxonomy has 5 fields or 40.
- Why not ask Jev to read the whole document at once for the value?
- Jev chooses among options; it does not write text. Offering every span in a long document as an option would be enormous. Locating the chunk first keeps the pick question to a dozen typed candidates, which is also what makes the probabilities sharp.
- What happens on long documents?
- Chunks are grouped into windows of about 22k tokens. Each window gets its own locate request, run in parallel; per-window probabilities are merged, weighting each window by how much probability it did not assign to 'none'. The pick call still happens once.
- How is confidence computed?
- For a picked span, confidence is the probability Jev assigned to that candidate multiplied by the probability that the field is present at all (one minus the locate call's p(none)). Enums and booleans are judged from context, so their confidence is the choice probability alone.
- What does the deterministic part do?
- Everything that is not a judgment: parsing, line and chunk construction, regex candidates for dates, amounts, ids, emails and phones, label/value splits, proper-noun phrases, date normalisation and number parsing. Code is free and exact; Jev decides only where code cannot.
- Where does it fail?
- Long clause-like values (a liability cap written as a sentence), ambiguous descriptions (current title vs headline title), multi-column prose where lines merge across columns, tables that should come back as arrays, and scanned pages without OCR. The candidates list on each field shows what Jev was offered, which makes these cases easy to spot.
- What did the refine round borrow from jev-extract?
- Three ideas from the open-source jev-extract benchmark: mark each option inside its context («…») so duplicate values in different places stay distinguishable; choose spans as contiguous token windows inside an already-located unit instead of enumerating the whole document; and gate boundary changes, because a bare “prefer shorter” prior over-trims names. On the four sample documents this took field exact-match from 90% to 94% for about 150 ms and $0.0001 more per document.