The Problem
I kept noticing the same frustration across jobs. Everyone is drowning in documents.
Researchers spend days skimming PDFs for a single finding. Compliance officers, lawyers, and engineers all face the same bottleneck: the information exists, but finding it eats hours, sometimes weeks. Teams end up duplicating work because the person who solved it last quarter has already moved on.
What if you could just ask a normal question and the system would search your entire knowledge base, pull the exact pieces that matter, and show you precisely where the answer came from?
That idea became Narayan. I built it under my proprietorship at Upperture Interactive, not for one industry, but for anyone buried in document stacks.
The hard part is that documents are messy. Papers love two-column layouts. Legal docs are full of dense jargon and cross-references. And because people make real decisions with the answers, every response needs to be traceable and grounded in the actual text. No hallucinations, no confidence without evidence.
The Architecture
If you’ve built RAG systems before, the basic pattern is familiar: extract text, chunk it, embed it, store vectors, retrieve, then generate. Narayan runs that pattern on Azure AI Foundry — Azure OpenAI for embeddings and generation, and Azure AI Search as the vector store. The devil is in the details, especially with real documents.
Getting the Text Right
Standard PDF parsers like PyPDF massacre two-column layouts. Text from the left column gets interleaved with the right, and your embeddings end up on pure garbage.
I switched to PyMuPDF because it respects reading order, pulling blocks top to bottom, left to right within columns:
blocks = page.get_text("blocks", sort=True)
text_blocks = [b[4].strip() for b in blocks if b[6] == 0 and len(b[4].strip()) > 20]
full_text = "\n\n".join(text_blocks)
Those double newlines are intentional. When the text splitter hits them, it respects paragraph boundaries first, so sentences stay intact instead of getting sliced mid-thought.
Before anything gets indexed, each file is hashed with SHA-256. If the content hash already exists, the upload is skipped — no duplicate documents silently inflating the index.
Chunking and Retrieval
Chunk size is everything. Too small and you lose context, too big and the LLM gets distracted by noise. I landed on 1000-character chunks with 200-character overlap, roughly one dense paragraph, with enough overlap that context doesn’t vanish at the edges.
For embeddings I used Azure OpenAI’s text-embedding-3-small, with vectors and metadata stored in Azure AI Search. Every chunk carries stable metadata: filename, page number, document ID, chunk index.
Retrieve, Rerank, Generate
When a question comes in, Narayan runs two-stage retrieval: embed the query, over-fetch the top 10 candidate chunks from Azure AI Search by vector similarity, then rerank down to the best 3 before handing them to the model. That last narrowing matters — feeding 10 mediocre chunks to the LLM is worse than feeding 3 good ones.
The system prompt is non-negotiable. It forces the model to use only the provided sources, cite them by source file and page number, and admit when it doesn’t know rather than guess.
Lessons Learned
Two-column layouts matter more than you’d think. PyPDF made the first version useless. PyMuPDF plus block sorting was a real jump in quality.
Overlap is not optional. Without the 200-character overlap, context regularly vanished across chunk boundaries. A question about treatment efficacy would split the description from the results.
Two-stage retrieval earns its keep. Over-fetching then reranking to the top 3 was a bigger accuracy win than any single-shot similarity search, and cheaper than throwing more chunks at the model.
Metadata is free value. A filename and page number turns “the system said X” into “here is exactly where X lives in the document.”
Why This Matters
Narayan sits between generic chatbots and overly specialized tools. Researchers get faster literature reviews, teams query their own knowledge base without flipping through files by hand.
The real win is traceability. Every answer points back to an exact page. In medicine, law, or compliance, that’s not a nice-to-have, it’s essential. Even in lower-stakes domains, being able to check the source is what makes people trust the answer.