.NETRAGC#Tutorial

Build a "Chat with your PDF" App in .NET

Let users ask questions about a PDF and get grounded answers. Build a chat-with-your-documents app in C# using extraction, embeddings, and retrieval-augmented generation.

“Chat with your PDF” is one of the most requested AI features — upload a document, ask questions, get answers grounded in that document. It’s a perfect, self-contained application of RAG. This guide builds one in .NET, end to end.

The pipeline

Four steps, two of them one-time per document:

  1. Extract the text from the PDF.
  2. Chunk it into passages and embed each one.
  3. Retrieve the chunks most relevant to the user’s question.
  4. Answer using only those chunks as context.

Step 1: Extract text from the PDF

Use a PDF library (such as PdfPig or another .NET PDF reader) to pull the text out, page by page:

using UglyToad.PdfPig;

string ExtractText(string path)
{
    using var doc = PdfDocument.Open(path);
    return string.Join("\n", doc.GetPages().Select(p => p.Text));
}

Step 2: Chunk and embed

You can’t embed a whole document as one vector — retrieval would be too coarse. Split into overlapping passages and generate an embedding for each:

var chunks = ChunkText(pdfText, size: 500, overlap: 75);   // your splitter
foreach (var chunk in chunks)
{
    var vector = (await embedder.GenerateAsync(chunk)).Vector;
    store.Add(chunk, vector);   // in-memory list, or pgvector for scale
}

For a single uploaded PDF, an in-memory list is fine; for many documents, use pgvector.

Step 3: Retrieve the relevant chunks

When a question comes in, embed it and pull the closest chunks (semantic search):

var q = (await embedder.GenerateAsync(question)).Vector;
var top = store.NearestTo(q, k: 4);   // the 4 most relevant passages

Step 4: Answer, grounded in the document

Build a prompt that gives the model only those chunks and instructs it to answer from them — and to admit when the answer isn’t there:

var context = string.Join("\n\n", top);
var prompt = $"""
    Answer the question using ONLY the context below, which comes from the user's document.
    If the answer isn't in the context, say you couldn't find it in the document.

    Context:
    {context}

    Question: {question}
    """;

var answer = await chatClient.GetResponseAsync(prompt);

That “answer only from the context, and say when you can’t” instruction is what keeps the app honest — it answers from the PDF instead of the model’s general knowledge, and it says “not in the document” instead of inventing something.

Making it production-grade

  • Cite the source — return which chunk/page an answer came from, so users can verify.
  • Cache the embeddings — embed a document once on upload, not on every question.
  • Handle scanned PDFs — image-only PDFs need OCR before extraction.
  • Mind the tokens — retrieving too many chunks inflates cost; tune k down.

Note: PDF and embedding library APIs vary; verify against your chosen packages. The pipeline — extract, chunk, embed, retrieve, answer-from-context — is the stable, provider-independent recipe behind every “chat with your documents” feature.

Takeaway

A “chat with your PDF” app is RAG applied to one document: extract the text, chunk and embed it, retrieve the passages relevant to each question, and answer using only those passages. Ground the model firmly in the retrieved context — “answer only from this, say when you can’t” — cite sources, and cache the embeddings. That’s a genuinely useful feature you can build in an afternoon in .NET.

Next: chunking strategies for RAG to improve the answers this returns.


Have a correction or a topic you want covered? Email mani.bc72@gmail.com.