All projectsAI · Retrieval

rag-document-qa.

Spring AIGPT-4opgvectorWebFluxJava 21
01

What it does

Full-stack RAG (Retrieval-Augmented Generation) application: upload documents, ask natural-language questions, get streamed answers grounded in the source text. Spring Boot 3.3 + Spring AI 1.0, OpenAI GPT-4o, PostgreSQL + pgvector for vector search, with a 3-strategy PDF extraction pipeline (PDFBox → Tesseract OCR → GPT-4o Vision) and SSE token streaming with source citations.

02

How it works

An upload returns 202 Accepted with a document ID straight away and the work continues in the background, so the frontend polls the document's status through PROCESSING, READY, and FAILED.

Extraction goes through a DocumentHandler per file type. For PDFs the handler runs a three-strategy waterfall per page: PDFBox digital text first, Tesseract OCR when that comes back too short, and GPT-4o Vision as the last resort, so no page is silently skipped.

The extracted text is chunked with JTokkit against OpenAI's CL100K_BASE tokenizer into 500-token chunks with 50 tokens of overlap, embedded with text-embedding-3-small, and stored in pgvector behind an IVFFlat index of 100 lists.

A question is embedded the same way and matched by cosine similarity in native SQL, top-k 5 by default. The retrieved chunks go into the prompt, and the answer comes back over Server-Sent Events on a Flux<ServerSentEvent> so each token is flushed past Tomcat's 8 KB buffer and reaches the browser immediately, followed by the source citations.

03

Design decisions

  1. 01Asynchronous ingestion: the upload returns 202 Accepted with a document ID at once and the frontend polls status (PROCESSING, READY, FAILED).
  2. 02Strategy pattern for extraction: one handler per file type behind a DocumentHandler interface; PDF, DOCX, PPTX, XLSX, text, and images.
  3. 03PDF three-strategy waterfall per page: PDFBox digital text, then Tesseract OCR, then GPT-4o Vision as the last resort, so no page is silently skipped.
  4. 04Token-aware chunking with JTokkit using OpenAI's CL100K_BASE tokenizer: 500-token chunks with 50-token overlap.
  5. 05Native SQL for cosine similarity search on pgvector with an IVFFlat index (100 lists); top-k 5 by default.
  6. 06Server-Sent Events over a Flux<ServerSentEvent> so each token is flushed past Tomcat's 8 KB buffer and reaches the browser immediately.
  7. 07Cross-document search implemented purely in SQL, with no schema change; confidence is the average cosine similarity of the retrieved chunks.
04

Stack

Language
Java 21
Framework
Spring Boot 3.3, Spring MVC, Spring AI 1.0
Models
OpenAI GPT-4o, text-embedding-3-small (1536 dimensions)
Vector store
PostgreSQL 16 with pgvector
Persistence
Spring Data JPA (Hibernate), Flyway
Streaming
Project Reactor, Spring WebFlux
Extraction
Apache PDFBox, Tesseract via Tess4J, GPT-4o Vision, Apache POI
Tokenization
JTokkit
API and tooling
SpringDoc OpenAPI, Lombok
Frontend
Vanilla HTML/CSS/JS
Build and run
Docker Compose
05

Source

More work

See the other systems, or say hello.