---
title: "DocuVision: PDF Q&A Without LangChain Plus a Vector DB"
date: "2026-09-09"
author: "Pierre Brunelle"
tags:
  - Document RAG
  - PDF
  - TableModel
  - Embeddings
  - Multimodal AI
  - Pixeltable Cloud
  - Retrieval
description: "Ingest prospectuses, chunk with page position, retrieve, then cite. Pixeltable is the document type, the splitter view, and the index — not Unstructured plus Chroma."
url: "https://www.pixeltable.com/blog/docuvision-pdf-chart-qa"
---

# DocuVision: PDF Q&A Without LangChain Plus a Vector DB

**Summary:** DocuVision is the analyst tool: a 50-page prospectus becomes searchable passages with page position, then an LLM answers with those passages as context. You do not stitch LangChain, PyPDF, Unstructured, and Chroma. You declare `Docs` and a `Chunks` view. The index follows the insert. `pip install pixeltable`.

 
## The Product

 

 - Ingest PDFs

 - Chunk with position attached

 - Ask “What was the Q3 revenue breakdown across regions?” and retrieve the passages

 - Synthesize a cited answer from those rows

 

 
The longer procedural tutorial is [production document RAG](/blog/document-pdf-processing-rag-pixeltable). This post is the class-based receipt. Text chunks are the searchable surface. Page images — charts as pixels — are a later column, not a second product we pretend to OCR here.

 
## The Stitch You Delete

 
A loader, a splitter, an embedding job, a vector collection, a retriever class, a chain. Delete a PDF and the chunks in Chroma are your problem. In a catalog, delete the document; the view and the index follow. That is the same lineage claim as [zombie vectors](/blog/deconstructing-ai-frankenstein-stack).

 
## The Receipt

 
```python
import pixeltable as pxt
from pixeltable.functions.document import document_splitter
from pixeltable.functions.huggingface import sentence_transformer
from pixeltable.serving import FastAPIRouter

TableModel = pxt.model_base()
text_embed = sentence_transformer.using(model_id='all-MiniLM-L6-v2')

class Docs(TableModel, name='docs'):
 filename: pxt.String
 doc: pxt.Document

class Chunks(
 TableModel,
 name='chunks',
 base=Docs,
 iterator=document_splitter(document=Docs.doc, separators='token_limit', limit=300),
):
 __indexes__ = [pxt.EmbeddingIndex(text, string_embed=text_embed)]

@pxt.query
def retrieve_chunks(question: str, top_k: int = 8):
 sim = Chunks.text.similarity(string=question)
 return (
 Chunks.order_by(sim, asc=False)
 .limit(top_k)
 .select(Docs.filename, Chunks.text, Chunks.pos)
 )

api = FastAPIRouter(name='docuvision')
api.add_insert_route(Docs, path='/docs', inputs=[Docs.doc, Docs.filename])
api.add_query_route(path='/retrieve', query=retrieve_chunks)

# After retrieve_chunks(question):
# from pixeltable.functions import gemini
# gemini.generate_content([question, *passage_texts], model='gemini-2.5-flash')
```

 
`text` and `pos` come from the splitter. Retrieval is the index. Generation is one Gemini call over those strings — not a second vector database, and not chart OCR. Page images are a later column if you need vision on figures. Same `app.py` on Cloud: `pxt db update` → `pxt schema update` → `pxt service update`.

 
## What This Is Not

 
Not “we read the bar chart as numbers.” That needs page images and a vision column you add later. Not a warehouse. Not LangChain as a religion — you can keep an agent; the document graph does not live in a chain.

 
## People Also Ask

 
**Why `token_limit` 300?** It is the docs default for passage RAG. Change the iterator kwargs; do not change the table.

 
**Do I need Chroma?** No.

 
**How do I go to Cloud?** Same file. `PIXELTABLE_API_KEY`, `pxt://org:db`, then `pxt db update` → `pxt schema update` → `pxt service update`.

 
**Is this an AI automation workflow?** Yes. Insert a PDF; the splitter view and index run as the table. The category is [AI automation workflow](/blog/ai-automation-workflow).

 
## Chunk the File, Not the Stack

 
Declare the document. Split it. Index the text. Ask the question. Keep the analyst loop. Delete the loader zoo.

 
A lecture video paired with a slide deck — page view plus frames — is [LectureSync](/blog/lecturesync-slide-lecture-qa).

 

 - **[Pixeltable on GitHub](https://github.com/pixeltable/pixeltable)**: `pip install pixeltable`

 - **[ClipFinder](/blog/clipfinder-semantic-video-moment-search)** — NL video moments

 - **[CallSense](/blog/callsense-sales-call-intelligence)** — sales-call auditor

 - **[SnapCatalog](/blog/snapcatalog-product-visual-search)** — shop-the-look

 - **[SafeStream](/blog/safestream-ugc-video-moderation)** — UGC gate

 - **[ClaimBot](/blog/claimbot-multimodal-fnol-triage)** — claims triage

 - **[Pixeltable documentation](https://docs.pixeltable.com)**