RAG over PDF, DOCX and PPTX: the ingestion pipeline that made answers trustworthy
How we built background PDF, DOCX and PPTX conversion for a RAG knowledge base, and what breaks when parsing and chunking are an afterthought.
By Ahmed Khalid, Tecifo
- Published
- Reading time
- 7 min read
Why the first RAG prototype gives vague answers
The first RAG prototype gives vague answers because the documents went in badly. Text extracted from a PDF loses its headings, a slide deck becomes a soup of bullet fragments, a Word table turns into one long line, and the chunks reaching the model are fragments. Retrieval looks fine in a demo and fails on the first real question.
Teams reach for a bigger model or a cleverer prompt at this point. The fix is upstream. On the enterprise knowledge platform we took from proof of concept to production over 1,145 hours, most of the gain in answer quality came from the ingestion pipeline: how files were converted, how the text was cut, and how each tenant's documents were kept apart. The model stayed the same.
Converting PDFs, DOCX and PPTX in background jobs
Document conversion belongs in background jobs, one converter per format, with retries, so a large upload never holds up the person who uploaded it and a failed conversion fixes itself. The prototype converted inside the upload request: a long PDF froze the page, a slide deck with images timed out, and the user saw a spinner.
Each format breaks in its own way and needs its own converter. PDFs come in two kinds: text PDFs, where the characters are there but the reading order and the headings are not, and scanned PDFs, which are images and need OCR before they are text at all. Columns interleave, headers and footers repeat on every page and end up inside the content, and a table becomes a column of numbers with no idea which row they belonged to.
Slide decks are worse than they look. A PPTX is title, bullets, speaker notes and the text inside shapes, and a generic extractor returns them in an order that has nothing to do with how a human reads the slide. Notes often carry the actual explanation and get dropped. Tables on slides are shapes, not tables.
Word documents are the kindest of the three and still need care. Headings are styles, which is useful if the author used them and useless if they made headings by bolding text. Tables survive extraction as rows, which is what you want. Tracked changes and comments can leak into the text if the converter is not told to ignore them.
The platform's pipeline queued a job per upload, ran the converter for that format, stored the plain text with its structure markers, and marked the document ready. Failures retried with a backoff and, after the last retry, told the uploader which file failed and why. Nothing in the user's session waited on any of it.
Chunking that respects document structure
A chunk should be a unit a person would recognise: a section under a heading, one slide with its notes, one table row with its header row attached. Fixed character windows cut across those boundaries, so the chunk that matches a question often starts in the middle of one idea and ends in the middle of the next.
The platform chunked along the structure the converters preserved: headings in PDFs and DOCX, slide boundaries in PPTX, rows in tables. Each chunk stored where it came from, the document, the page or slide, and the heading above it, which is what later made citations possible. Overlap between chunks was small and deliberate, enough to carry a sentence that straddled a boundary and no more.
The one rule we would keep above all others: store the source with the chunk. A chunk without a page number is an answer without evidence, and enterprise buyers ask for the evidence.
Tenant isolation at retrieval time
Each workspace's documents must be invisible to every other workspace at the database level, enforced by row-level security on the chunks and embeddings tables, with no shared index across tenants. A filter in application code is a convention; a policy in Postgres is a guarantee an auditor can read.
The prototype kept documents separate in application code. The platform moved isolation to Supabase row-level security on every table, including the chunks and embeddings, and added a test that signed in as a second workspace and tried to read the first. Retrieval queries ran as the requesting user, so a query could not return a passage the user's workspace did not own, however the application code was written.
A question set you re-run after every change
The platform's quality was measured against a set of real questions from the client's users, with the expected sources for each, re-run after every change to the converters, the chunking or the retrieval. A change that improved one format's answers and broke another's showed up in that run, not in a customer email.
The set does not need to be large to be useful; it needs to be real. Questions users asked, including the awkward ones about a figure on slide fourteen, are worth more than any synthetic benchmark. We kept a note on each entry of why it was there, which stopped the set from being pruned down to the easy cases.
Streaming answers with citations
Answers streamed to the user with citations to the chunks they drew on, each citation naming the document and the page or slide, so a reader could open the source and check. Streaming made the wait feel short; the citations made the answer trustworthy.
Citations came for free from the chunking decision above. Because every chunk carried its source, the model could be asked to reference the passages it used and the interface could turn each reference into a link. Answers without a supporting passage were flagged as such rather than dressed up.
Writing back to the knowledge base only after human approval
When the AI proposed a change to the knowledge base, a person saw the proposed edit with the evidence behind it and approved or rejected it before anything was written. This was a hard requirement for enterprise buyers and, in our view, the right default for any system that can change the documents it answers from.
The approval queue became part of the product. Suggested edits accumulated with their evidence; a knowledge owner worked through them; approved ones were applied and re-ingested through the same pipeline as a new upload. The AI never had a write path that skipped the queue.
Failure modes by file type
What we saw on each format, and what fixed it.
File type: PDF, text
- What goes wrong
- Reading order breaks across columns; headers and footers repeat inside the content; tables flatten
- What fixed it
- Layout-aware extraction, header and footer stripping, tables kept as rows with the header row attached
File type: PDF, scanned
- What goes wrong
- No text layer; extraction returns nothing or garbage
- What fixed it
- OCR step in the converter, with a confidence flag stored on the document
File type: PPTX
- What goes wrong
- Titles, bullets, notes and shape text come out in the wrong order; notes dropped
- What fixed it
- One chunk per slide with title, body and notes in reading order
File type: DOCX
- What goes wrong
- Headings lost when the author bolded instead of styling; comments and tracked changes leak
- What fixed it
- Heading detection from styles with a fallback on formatting; converter told to ignore revisions
File type: Any format, large
- What goes wrong
- Conversion inside the request times out the upload
- What fixed it
- Background job per upload, one converter per format, retries with backoff
File type: Any format, many tenants
- What goes wrong
- A shared index returns another workspace's passage
- What fixed it
- Row-level security on chunks and embeddings; retrieval runs as the user
Questions we get about document ingestion
Which vector database did you use? The knowledge platform ran on Supabase, which kept the embeddings next to the data and under the same row-level security. We also build on Pinecone, Qdrant and ChromaDB when a project calls for a separate index; the isolation rules do not change.
Does chunk size matter more than the chunking method? Less than the method. Chunks that follow the document's structure at a sensible size beat perfectly sized chunks that cut across it.
Can this ingest Notion and other sources as well as files? Yes. The platform also pulled from the Notion API. A source connector is another converter: it produces the same structured text and the rest of the pipeline is unchanged.
How long does a pipeline like this take to build? The knowledge platform's whole production build was 1,145 hours over six months, of which ingestion was one part. A first pipeline for two or three formats is a much smaller build; the written plan sets the number.
What we would do on your project
We ask for a handful of your real documents in each format and twenty real questions, then run them through a first pass and show you where the answers break and why. The plan that comes out of it, converters, chunking, isolation and the question set, is the discovery sprint, from $2,500. Book a free architecture call to start. The build behind this article is the enterprise knowledge platform, and the RAG development service describes the full scope.
Services this draws on
RAG and document AI
Answers from your own documents, with the sources shown and each team's data kept separate.
MVP to production
Your Lovable, Bolt or proof-of-concept app audited and rebuilt where it matters, while it keeps running.
The builds behind it
- Billed hours
- 1,145
- Duration
- 6 months
- Client rating on Upwork
- 5.0
Enterprise AI knowledge platform
Starling MX
A live proof of concept became an enterprise AI knowledge platform in six months, without going offline.
Keep reading
Prompt caching and context-window budgeting on a Claude knowledge platform
How we cut Claude API cost and latency on an enterprise knowledge platform with prompt caching and context-window budgeting, with the trade-offs we hit.
- Published
- Reading time
- 8 min read
Lovable to production: the 12 checks we run before real users arrive
12 checks before real users hit your Lovable app: Supabase RLS, secrets, auth, webhooks, background jobs, tests, CI and monitoring.
- Published
- Reading time
- 8 min read