We measure how the site is used so we can improve it. Allow cookies and we can follow a visit across pages instead of measuring each page alone. Privacy policy.

PDF parser for RAGWhere RAG quality is actually won or lost

Most RAG accuracy problems are parsing problems wearing a costume. Inteleto parses documents into positioned blocks and then chunks them structurally — parent and child chunks, token-capped, each one prefixed with the heading path it sits under — so a retrieved chunk arrives with enough context to be understood and enough metadata to be cited back to a page. No model calls happen at ingest, so the cost of chunking does not scale with how often you change your mind about it.

We built this for our own retrieval product, which is a harsher customer than an API buyer: every answer it produces has to carry a citation somebody can click and check.

Private beta · no card · we reply by hand

Four RAG failures that are really parsing failures

When retrieval quality plateaus, the usual response is to change embedding model, then reranker, then prompt. It is worth checking first whether the information ever made it into the index.

The answer is confidently wrong about a number
The table it came from was flattened into prose during extraction, so the value lost the column it belonged to. No embedding model recovers that.
Retrieval misses documents you know contain the answer
The pages were scanned and never OCR'd, or were OCR'd badly enough that the query terms are not in the index at all. The corpus looks complete and is not.
Chunks read as fragments with no subject
Fixed-size splitting cut through the middle of a clause. A chunk that says "the limit is 30 days" without saying which limit is unusable to the model and to the human checking it.
Citations point at a file, not a place
Position was discarded at extraction. If a chunk does not carry its page and region, nobody can verify the claim without reading the whole document.

Parent/child chunks, and why both

Chunking pulls in two directions. Small chunks match precisely — a tight passage embeds cleanly and ranks well. Large chunks are actually intelligible when they arrive. Picking one size means losing whichever property you did not pick.

So chunks are created in pairs. The child is what gets embedded and matched; the parent is the wider passage handed to the model once the child has won. Both are cut on the document's own structure — sections and headings first, with a token cap as a backstop rather than as the rule — and every chunk carries the heading path it sits under, so a fragment about “the limit” still says which section's limit it is.

There are no model calls anywhere in this. That keeps ingest cheap, but the reason it matters more is reproducibility: a deterministic chunker can be versioned, and bumping the version re-chunks the corpus the same way every time instead of producing a slightly different corpus on each run.

What a chunk arrives with

Enough to embed, enough to cite, and enough to invalidate later:

  • The text, with its heading path prefixed.
  • Its parent chunk, for the context the model sees after the match.
  • Source document, page number and position on the page.
  • A content hash, so a re-parse can tell what actually changed.
  • The stage versions that produced it — extraction engine and chunker — so stale output is identifiable rather than assumed fresh.

Frequently asked questions

Why blame the parser for bad retrieval?
Because retrieval can only rank what extraction produced. A table that arrived as scrambled text cannot be matched by a query about the number inside it, and a chunk cut through the middle of a clause reads as gibberish to both the embedding model and the person checking the citation. Swapping embedding models does not recover information that was destroyed before indexing.
How are chunks split?
On the document's own structure — sections and headings first, with a token cap as the backstop rather than as the rule. Each chunk is created as a parent/child pair: the child is what gets embedded and matched, the parent is the wider passage returned for context. Every chunk is prefixed with its heading path, so a fragment about "the limit" still says which section's limit it is.
Does chunking cost a model call per document?
No. Chunking is fully deterministic — no LLM in the ingest path. That matters beyond cost: a deterministic chunker can be versioned, and changing the version re-chunks the corpus reproducibly instead of producing a different result on every run.
Can I bring my own embedding model and vector store?
Yes. The parsing and chunking stages hand back Markdown, positioned blocks and chunk records; what you embed them with and where you put them is yours. The full platform ships an opinionated version of that — hybrid dense and BM25 retrieval — but the parser does not require it.
What stops the same page being re-parsed and re-billed?
Extraction is content-addressed per page range and keyed to the engine version, so a page range that has already been extracted at the current version is never sent to a GPU again, whoever uploads it. Re-uploading the same document costs nothing to extract.

Request parsing API access

Standalone parsing is in private beta. Tell us what you are parsing and we will come back with real numbers for your documents — throughput, accuracy on your formats, and cost per page.

No card, no automated sequence. One human reply.