---
title: "How to chat with your PDF using RAG"
canonical_url: "https://www.nutrient.io/blog/chat-with-pdf/"
md_url: "https://www.nutrient.io/blog/chat-with-pdf.md"
last_updated: "2026-07-22T10:51:42.259Z"
description: "Chat with PDF turns a document into a Q&A interface. How the retrieval pipeline works, how to build one, and why extraction decides if the answers are right."
---

**TL;DR**

- Chatting with a PDF lets a user ask it questions in natural language and get answers grounded in its content.

- Under the hood, it’s retrieval-augmented generation (RAG): Extract the PDF’s content, split it into chunks, embed them, retrieve the relevant chunks for a question, and let a large language model (LLM) answer from them.

- The build is short. The accuracy problem is upstream: A PDF with tables, scans, or multicolumn layout has to be extracted correctly first, or the model answers from broken input.

- This guide covers how it works, how to build one, and how to skip the plumbing with Nutrient [AI Assistant](https://www.nutrient.io/sdk/ai-assistant/).

Chat-with-PDF tools let you upload a document and ask it questions like “what’s the penalty clause?”, “summarize section 4”, or “what was Q2 revenue?”, instead of scrolling through pages. Almost all of them work the same way: retrieval-augmented generation over the document’s text.

This article explains how that pipeline works, walks through building one, and covers the part that decides answer quality: getting clean content out of the PDF in the first place.

## How chat with PDF works

A chat-with-PDF app is a RAG pipeline scoped to one document (or a small set). The flow is outlined below.![Chat-with-PDF pipeline: A PDF is extracted and chunked, and the chunks are embedded and stored in a vector store. A user question is embedded, the most relevant chunks are retrieved, and an LLM generates an answer grounded in them. Extraction quality determines whether the retrieved chunks contain the answer.](@/assets/images/blog/2026/chat-with-pdf/chat-with-pdf-pipeline.png)

1. **Extract** the text (and tables, and any text from scanned pages) from the PDF.

2. **Chunk** the content into passages small enough to embed and retrieve.

3. **Embed** each chunk into a vector and store it.

4. **Retrieve** the chunks most relevant to the user’s question.

5. **Generate** an answer with an LLM, passing the retrieved chunks as context.

The model never “reads” the whole PDF on each question. It answers from the handful of chunks retrieval pulled, which is why both chunking and extraction matter as much as the model.

## Building a chat-with-PDF app

Here’s a minimal version with [LangChain](https://docs.langchain.com/): Load a PDF, index it, and answer questions with an agent that retrieves on demand.

You’ll need:

- Python 3.10+

- An OpenAI API key set as `OPENAI_API_KEY`

- The required packages — `pip install langchain langchain-community langchain-openai langchain-text-splitters pypdf`

```python

from langchain_community.document_loaders import PyPDFLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_core.vectorstores import InMemoryVectorStore
from langchain.chat_models import init_chat_model
from langchain.agents import create_agent
from langchain.tools import tool

# 1. Extract and chunk the PDF.

pages = PyPDFLoader("contract.pdf").load()
splits = RecursiveCharacterTextSplitter(
    chunk_size=1000, chunk_overlap=200
).split_documents(pages)

# 2. Embed and store the chunks.

vector_store = InMemoryVectorStore(OpenAIEmbeddings(model="text-embedding-3-small"))
vector_store.add_documents(splits)

# 3. Give an agent a retrieval tool.

@tool(response_format="content_and_artifact")
def search_pdf(query: str):
    """Retrieve passages from the PDF relevant to the query."""
    docs = vector_store.similarity_search(query, k=4)
    return "\n\n".join(d.page_content for d in docs), docs

model = init_chat_model("gpt-4o-mini", model_provider="openai")
agent = create_agent(
    model,
    tools=[search_pdf],
    system_prompt=(
        "Answer questions about the PDF using the search tool. "
        "If the retrieved passages don't contain the answer, say you don't know."
    ),
)

# 4. Ask.

result = agent.invoke(
    {"messages": [{"role": "user", "content": "What is the penalty clause?"}]}
)
print(result["messages"][-1].content)

```

That’s a working chat-with-PDF backend for a clean, born-digital PDF. Wrap it in a chat UI and you have the app.

## The part that decides accuracy: Extraction

Step 1, `PyPDFLoader`, is where this breaks on real documents. A loader that pulls the raw text layer works for a born-digital report. It fails on the documents people actually want to chat with:

- **Scanned PDFs** have no text layer, so the loader returns empty pages. Without optical character recognition (OCR), there’s nothing to index.

- **Tables** get flattened into a run of numbers, so “what was Q2 revenue?” retrieves a chunk where the figure has lost its label.

- **Multicolumn and complex layouts** come out in the wrong reading order, so chunks mix unrelated text.

When that happens, the model isn’t wrong; it’s answering faithfully from broken input. The fix is to replace naive text loading with real extraction: [OCR](https://www.nutrient.io/blog/document-ai-vs-ocr.md) for scans, table detection that preserves structure, and layout-aware reading order.

Swap the loader for an extraction step that handles those cases. Nutrient’s [Data Extraction API](https://www.nutrient.io/guides/dws-data-extraction.md) returns clean Markdown — with OCR, tables, and reading order already resolved — which you chunk and embed exactly as before:

```python

import requests
from langchain_text_splitters import RecursiveCharacterTextSplitter

# Replace PyPDFLoader with extraction that runs OCR, detects tables,

# and preserves reading order, returning Markdown.

response = requests.post(
    "https://api.nutrient.io/extraction/parse",
    headers={"Authorization": "Bearer your_api_key_goes_here"},
    files={"file": open("contract.pdf", "rb")},
    data={"instructions": '{"mode":"understand","output":{"format":"markdown"}}'},
)
markdown = response.json()["output"]["markdown"]

# Chunk the extracted Markdown, then embed and index as before.

splits = RecursiveCharacterTextSplitter(
    chunk_size=1000, chunk_overlap=200
).create_documents([markdown])

```

Everything downstream stays identical. The chunks are just built from content that survived extraction, so the table figure and the scanned clause are actually in the index when the agent goes looking.

[Try the Data Extraction API](https://www.nutrient.io/guides/dws-data-extraction.md)

If your documents include scans, tables, or forms, extraction quality sets the ceiling on answer quality. Nutrient’s [AI document and data extraction SDK](https://www.nutrient.io/sdk/ai-document-processing/) handles OCR, intelligent character recognition (ICR), table detection with cell-level coordinates, and layout-aware reading order, returning structured output you can chunk and embed. The same problem on the retrieval side is covered in our [multimodal RAG](https://www.nutrient.io/blog/multimodal-rag.md) and [agentic RAG](https://www.nutrient.io/blog/agentic-rag.md) posts.

## Skipping the plumbing with a managed AI Assistant

Build the pipeline yourself when you need control over chunking, the model, and the vector store. If you’d rather not run that stack, a managed document AI handles the retrieval, model orchestration, and UI for you.

|                                 | Build it yourself                                                       | Managed AI Assistant                             |
| ------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------ |
| Setup                           | Wire up extraction, chunking, embeddings, a vector store, and a chat UI | Drop-in backend service your viewer connects to  |
| Control                         | Full control over chunking, model, and vector store                     | Opinionated defaults, less to tune               |
| Extraction (OCR, tables, scans) | You integrate it yourself                                               | Built in                                         |
| Chat UI                         | You build it                                                            | Included with the document viewer                |
| LLM provider                    | Any                                                                     | OpenAI, Azure OpenAI, AWS Bedrock, and Anthropic |
| Maintenance                     | You own the stack                                                       | Managed for you                                  |
| Best when                       | You need a custom pipeline                                              | You want to ship fast                            |

Nutrient [AI Assistant](https://www.nutrient.io/sdk/ai-assistant/) does this. It runs as a backend service your document viewer connects to, works with major LLM providers (OpenAI, Azure OpenAI, AWS Bedrock, and Anthropic), and is available for web, iOS, Android, and Flutter. Through it, users can:

- **Ask questions** and get context-aware answers from the document.

- **Summarize** long documents or specific pages.

- **Translate** content into other languages.

- **Redact** sensitive information through natural-language commands.

- **Compare** versions and categorize the differences.

Pair it with the [Web SDK](https://www.nutrient.io/sdk/) so the chat sits next to a real document viewer. The [getting started guides](https://www.nutrient.io/sdk/ai-assistant/getting-started.md) and an [open source demo](https://github.com/PSPDFKit/ai-assistant-demo) cover setup.

**Other no-build options**

- [Nutrient PDF Editor for Claude Cowork](https://www.nutrient.io/claude-desktop/) lets you chat with and edit PDFs inside Claude, with no signup.

- [Document Engine MCP Server](https://www.nutrient.io/blog/nutrient-document-engine-mcp-server-release/) lets AI agents like Claude process documents through natural-language commands.

**Call to Action**

Add chat to your document viewer with Nutrient AI Assistant

[Learn More](https://www.nutrient.io/sdk/ai-assistant/)

## FAQ

#### What is chat with PDF and how does it work?

Chat with PDF lets you ask a document questions in natural language and get answers drawn from its content instead of reading it manually. It works through retrieval-augmented generation (RAG): The PDF is extracted, split into chunks, and embedded. Then the chunks most relevant to your question are retrieved and passed to an LLM that answers from them.

#### How do you build a chat-with-PDF app?

Extract the PDF’s text, split it into chunks, embed and store them in a vector store, retrieve the chunks relevant to each question, and have an LLM answer from them. The code above shows a minimal [LangChain](https://docs.langchain.com/) version.

#### Why does my chat-with-PDF app give wrong answers?

Most often, the document wasn’t extracted correctly: A scanned page returned no text, or a table was flattened into a run of numbers. The model answers from whatever was indexed, so fix extraction before blaming the model.

#### Can chat with PDF handle scanned documents and tables?

Yes, but only if extraction runs OCR and table detection first. A plain text-layer loader returns nothing for a scanned page and flattens tables, so the answer is already missing before retrieval runs.

#### Should you build a chat-with-PDF app or use an existing tool?

Build it when you need control over chunking, the model, and the vector store, or when you have to keep documents on your own infrastructure. Use a managed AI Assistant when you want to ship fast without running the retrieval stack yourself.

#### Which LLMs can power a chat-with-PDF app?

Any model works if you build the pipeline yourself. Nutrient AI Assistant works with OpenAI, Azure OpenAI, AWS Bedrock, and Anthropic, so you’re not locked into one provider.

## Conclusion

Chatting with a PDF is RAG pointed at a single document: extract, chunk, embed, retrieve, answer. The pipeline is a few lines of code, and the model does the visible work, but the answers are only as good as what extraction pulled out of the PDF. A flattened table or a skipped scan produces confident, wrong answers, no matter which model you use.

Get extraction right with the [AI document and data extraction SDK](https://www.nutrient.io/sdk/ai-document-processing/), or skip the stack entirely with the managed [AI Assistant](https://www.nutrient.io/sdk/ai-assistant/). [Contact our team](https://www.nutrient.io/contact-sales/) to talk through your use case.
---

## Related pages

- [The business case for accessibility: Five ways it drives enterprise value](/blog/5-ways-accessibility-drives-enterprise-value.md)
- [Accessibility Untangled Why It Matters Guide](/blog/accessibility-untangled-why-it-matters-guide.md)
- [Advanced Techniques For React Native Ui Components](/blog/advanced-techniques-for-react-native-ui-components.md)
- [`vector_store` holds your indexed documents (see the multimodal RAG post](/blog/agentic-rag.md)
- [Ai Document Automation Extraction To Action](/blog/ai-document-automation-extraction-to-action.md)
- [Ai Legal Assistant Document Authoring](/blog/ai-legal-assistant-document-authoring.md)
- [Angular File Viewer Pdf Image Office Files](/blog/angular-file-viewer-pdf-image-office-files.md)
- [Auto Tagging And Document Accessibility In Dotnet Sdk](/blog/auto-tagging-and-document-accessibility-in-dotnet-sdk.md)
- [Best Document Viewers](/blog/best-document-viewers.md)
- [The CEO’s AI playbook: Why decision architecture beats model selection](/blog/ceo-ai-playbook-decision-architecture.md)
- [Complete Guide To Pdfjs](/blog/complete-guide-to-pdfjs.md)
- [Construction Document Data Extraction](/blog/construction-document-data-extraction.md)
- [Convert One Drive Files To Pdf In Sharepoint](/blog/convert-one-drive-files-to-pdf-in-sharepoint.md)
- [Create And Edit Pdfs In Flutter](/blog/create-and-edit-pdfs-in-flutter.md)
- [Create Pdfs With React](/blog/create-pdfs-with-react.md)
- [Creating A Document Scanner With Ocr In Python](/blog/creating-a-document-scanner-with-ocr-in-python.md)
- [Creating And Filling Pdf Forms Programmatically In Javascript](/blog/creating-and-filling-pdf-forms-programmatically-in-javascript.md)
- [The CTO’s AI playbook: Why accountability architecture beats orchestration](/blog/cto-ai-playbook-accountability-architecture.md)
- [Digital Signatures](/blog/digital-signatures.md)
- [Digital Workflow Automation](/blog/digital-workflow-automation.md)
- [Document Ai Vs Ocr](/blog/document-ai-vs-ocr.md)
- [Document Viewer](/blog/document-viewer.md)
- [Document Watermarking](/blog/document-watermarking.md)
- [Emerging threats: Your logging system may be an agentic threat vector](/blog/emerging-threats-your-logging-system.md)
- [app.py](/blog/extract-text-from-pdf-using-python.md)
- [How To Add Digital Signature To Pdf Using React](/blog/how-to-add-digital-signature-to-pdf-using-react.md)
- [How To Build A Dotnet Maui Pdf Viewer](/blog/how-to-build-a-dotnet-maui-pdf-viewer.md)
- [How To Build A Flutter Pdf Viewer](/blog/how-to-build-a-flutter-pdf-viewer.md)
- [or](/blog/how-to-build-a-javascript-pdf-viewer-with-pdfjs.md)
- [How To Build A Javascript Pdf Viewer](/blog/how-to-build-a-javascript-pdf-viewer.md)
- [or](/blog/how-to-build-a-nextjs-pdf-viewer.md)
- [How To Build A Powerpoint Viewer Using Javascript](/blog/how-to-build-a-powerpoint-viewer-using-javascript.md)
- [Using Yarn](/blog/how-to-build-a-react-excel-viewer.md)
- [How To Build A React Native Pdf Viewer](/blog/how-to-build-a-react-native-pdf-viewer.md)
- [How To Build A React Powerpoint Viewer](/blog/how-to-build-a-react-powerpoint-viewer.md)
- [How To Build A Reactjs File Viewer](/blog/how-to-build-a-reactjs-file-viewer.md)
- [or](/blog/how-to-build-a-reactjs-pdf-viewer-with-react-pdf.md)
- [or](/blog/how-to-build-a-reactjs-pdf-viewer.md)
- [How To Build A Reactjs Viewer With Pdfjs](/blog/how-to-build-a-reactjs-viewer-with-pdfjs.md)
- [How To Build A Vuejs Pdf Viewer With Pdfjs](/blog/how-to-build-a-vuejs-pdf-viewer-with-pdfjs.md)
- [How To Build A Vuejs Pdf Viewer](/blog/how-to-build-a-vuejs-pdf-viewer.md)
- [How To Build An Android Pdf Viewer](/blog/how-to-build-an-android-pdf-viewer.md)
- [How To Build An Angular Pdf Viewer With Ng2 Pdf Viewer](/blog/how-to-build-an-angular-pdf-viewer-with-ng2-pdf-viewer.md)
- [How To Build An Angular Pdf Viewer With Pdfjs](/blog/how-to-build-an-angular-pdf-viewer-with-pdfjs.md)
- [How To Convert Docx To Pdf Using Javascript](/blog/how-to-convert-docx-to-pdf-using-javascript.md)
- [How To Convert Docx To Pdf Using Python](/blog/how-to-convert-docx-to-pdf-using-python.md)
- [How To Convert Html To Pdf Using Html2pdf](/blog/how-to-convert-html-to-pdf-using-html2pdf.md)
- [or](/blog/how-to-convert-html-to-pdf-using-react.md)
- [or](/blog/how-to-convert-html-to-pdf-using-wkhtmltopdf-and-python.md)
- [How To Convert Word To Pdf In Nodejs](/blog/how-to-convert-word-to-pdf-in-nodejs.md)
- [or](/blog/how-to-create-a-react-js-signature-pad.md)
- [How To Create Pdfs With React To Pdf](/blog/how-to-create-pdfs-with-react-to-pdf.md)
- [How To Edit Pdfs Using Ios Pdf Library](/blog/how-to-edit-pdfs-using-ios-pdf-library.md)
- [How To Embed A Pdf Viewer In Your Website](/blog/how-to-embed-a-pdf-viewer-in-your-website.md)
- [How To Generate Pdf From Html With Nodejs](/blog/how-to-generate-pdf-from-html-with-nodejs.md)
- [base_url tells WeasyPrint where to resolve relative asset paths](/blog/how-to-generate-pdf-reports-from-html-in-python.md)
- [Open an image.](/blog/how-to-use-tesseract-ocr-in-python.md)
- [From an HTML string.](/blog/html-in-pdf-format.md)
- [Javascript Pdf Libraries](/blog/javascript-pdf-libraries.md)
- [Linearized Pdf](/blog/linearized-pdf.md)
- [Swift Package Manager](/blog/mobile-pdf-sdk.md)
- [`elements` come from your document parser — each has a type and content.](/blog/multimodal-rag.md)
- [Nutrient Vs Conga Composer](/blog/nutrient-vs-conga-composer.md)
- [Online Document Viewer](/blog/online-document-viewer.md)
- [Open Pdf In Your Web App](/blog/open-pdf-in-your-web-app.md)
- [Pdf Page Labels](/blog/pdf-page-labels.md)
- [Pdf Sdk Compliance Security Checklist](/blog/pdf-sdk-compliance-security-checklist.md)
- [Pdf Sdk Performance Benchmark](/blog/pdf-sdk-performance-benchmark.md)
- [Pdf Ua Compliance Guide](/blog/pdf-ua-compliance-guide.md)
- [Pdfjs Annotation Editor Layer](/blog/pdfjs-annotation-editor-layer.md)
- [Pdfjs Area Annotations Canvas Capture](/blog/pdfjs-area-annotations-canvas-capture.md)
- [Pdfjs Coordinate Systems Pdf To Screen](/blog/pdfjs-coordinate-systems-pdf-to-screen.md)
- [Pdfjs Eventbus Guide](/blog/pdfjs-eventbus-guide.md)
- [Pdfjs Limitations Commercial Upgrade](/blog/pdfjs-limitations-commercial-upgrade.md)
- [Pdfjs Native Annotation Layer Forms](/blog/pdfjs-native-annotation-layer-forms.md)
- [Pdfjs Navigation Zoom Rotation](/blog/pdfjs-navigation-zoom-rotation.md)
- [Pdfjs Pdf Page Manipulation Pdf Lib](/blog/pdfjs-pdf-page-manipulation-pdf-lib.md)
- [Pdfjs React Viewer Setup](/blog/pdfjs-react-viewer-setup.md)
- [Pdfjs Rendering Overlays React Portals](/blog/pdfjs-rendering-overlays-react-portals.md)
- [Pdfjs Server Side Text Extraction](/blog/pdfjs-server-side-text-extraction.md)
- [Pdfjs Sticky Note Annotations](/blog/pdfjs-sticky-note-annotations.md)
- [Pdfjs Text Highlight Annotations](/blog/pdfjs-text-highlight-annotations.md)
- [Pdfjs Text Search Pdffindcontroller](/blog/pdfjs-text-search-pdffindcontroller.md)
- [Pdfjs Thumbnail Sidebar](/blog/pdfjs-thumbnail-sidebar.md)
- [Process Flows](/blog/process-flows.md)
- [React Native Pdf Annotation](/blog/react-native-pdf-annotation.md)
- [or](/blog/sample-blog-updated.md)
- [Open an image file.](/blog/tesseract-python-guide.md)
- [Top 5 Javascript Pdf Viewers](/blog/top-5-javascript-pdf-viewers.md)
- [Convert an HTML file to PDF.](/blog/top-ten-ways-to-convert-html-to-pdf.md)
- [Vector Pdf](/blog/vector-pdf.md)
- [Wcag2 Accessibility Requirements Documents](/blog/wcag2-accessibility-requirements-documents.md)
- [Web Sdk Is Now Headless](/blog/web-sdk-is-now-headless.md)
- [What Are Annotations](/blog/what-are-annotations.md)
- [What Is A Vpat](/blog/what-is-a-vpat.md)
- [What Is Pdf Ua](/blog/what-is-pdf-ua.md)
- [Why Pdfium Is A Trusted Platform For Pdf Rendering](/blog/why-pdfium-is-a-trusted-platform-for-pdf-rendering.md)
- [Why Your Ai Agent Hallucinates Pdf Table Data](/blog/why-your-ai-agent-hallucinates-pdf-table-data.md)

