Skip to content

sririthishpalani-max/JavaDocRAG

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

JavaDoc RAG — JDK 25 API Q&A System

A production-grade Retrieval-Augmented Generation system that answers Java developer questions using the Oracle Java SE 25 / JDK 25 API documentation as its sole source of truth — with inline citations back to the exact Javadoc section.

Python FastAPI FAISS Claude License

Question: "What does ArrayList.add(E) return?"
→ Answer:  "add(E) returns true (as specified by Collection.add) [1]"
→ Cites:   [1] https://docs.oracle.com/.../ArrayList.html#add(E)
→ Related: java.util.ArrayList#add(E), java.util.ArrayList#add(int,E)

Ask a question in plain English or with a precise symbol (ArrayList#add(int,E)) and get a grounded answer with citations — no hallucinated APIs, every claim traceable to official docs.


Why this exists

LLMs are confidently wrong about API contracts: return values, thrown exceptions, null-handling, since versions, and overload behavior. This system constrains the model to only answer from retrieved JDK 25 Javadoc, attaches a citation to every statement, and routes precise symbol queries straight to the source — so the answer is auditable.

Features

  • Hybrid retrieval — BM25 (exact identifiers) + dense embeddings (semantics), fused with Reciprocal Rank Fusion, then re-ranked by a cross-encoder.
  • Symbol-aware routing — a query parser detects fully-qualified names, camelCase members, and method signatures, and does a direct DB lookup before falling back to search — eliminating retrieval noise on precise queries.
  • Structure-aware chunking — one chunk = one Javadoc section (e.g. a single method-detail block), which matches how the docs are actually organized.
  • Grounded generation with citations — Claude answers only from retrieved context and emits inline [n] citations linking to the exact Javadoc URL.
  • Multimodal — optional CLIP-based image ingestion/search and a /query-with-image endpoint for diagram-augmented questions.
  • PDF ingestion — pull in supplementary PDFs (e.g. PostgreSQL manuals) alongside Javadoc.
  • Web UI + REST API — a single-page chat front-end served at /, plus a documented FastAPI backend with type-ahead suggestions.
  • Evaluation suite — gold-standard regression questions covering return values, exceptions, null contracts, inheritance, since queries, and overload disambiguation.

Tech stack

Python 3.11 · FastAPI · FAISS · sentence-transformers (BGE) · rank_bm25 · cross-encoder (MS MARCO MiniLM) · CLIP · Anthropic Claude · SQLite · BeautifulSoup · PyMuPDF


Architecture

                          ┌────────────────────── ingest pipeline ──────────────────────┐
                          │  Crawler ─→ Parser ─→ Chunker ─→ Embedder ─→ Index           │
                          │  (async,     (Javadoc   (1 chunk =   (BGE)      (FAISS +      │
                          │   rate-ltd)   HTML)      1 section)              BM25 + SQLite)│
                          └──────────────────────────────────────────────────────────────┘
                                                       │
                                                       ▼
   POST /query ──→  QueryParser ──→ symbol lookup? ──→ BM25 ─┐
                                                              ├─ RRF fusion ─→ cross-encoder rerank ─→ top-k
                                          dense search ───────┘                                          │
                                                                                                        ▼
                                                                            Claude (answer + inline citations)

Key design decisions

Concern Decision Rationale
Chunking 1 chunk = 1 Javadoc section (not fixed token windows) Javadoc is already structured; method-detail sections are the ideal retrieval unit
Retrieval Hybrid BM25 + dense + RRF + cross-encoder BM25 wins on exact identifiers; dense wins on semantics; the reranker arbitrates
Symbol routing Parser detects FQN/member → direct DB lookup before hybrid search Eliminates retrieval noise for precise queries like ArrayList#add(int,E)
Storage SQLite (metadata) + FAISS (vectors) + pickle (BM25) Zero-infrastructure; runs locally; swap to Postgres + pgvector for production
Embeddings BAAI/bge-*-en-v1.5 Strong on technical text; BGE instruction-tuning improves recall
Reranker cross-encoder/ms-marco-MiniLM-L-6-v2 Fast cross-encoder; good quality/latency trade-off
LLM Claude Sonnet Excellent instruction-following; accurate on API docs

Project structure

JavaDocRAG/
├── config.py                     # All tunable knobs (reads .env)
├── requirements.txt
├── .env.example
├── static/
│   └── index.html                # Single-page chat web UI (served at /)
├── resource/                     # Sample PDFs for PDF ingestion demos
├── src/
│   ├── cli/
│   │   ├── ingest.py             # Crawl → parse → chunk → embed → index
│   │   ├── serve.py              # FastAPI server
│   │   └── check_db.py           # Inspect the indexed SQLite DB
│   ├── crawler/
│   │   ├── crawler.py            # Async crawler with rate limiting
│   │   ├── parser.py             # Javadoc HTML → RawSection objects
│   │   └── pdf_parser.py         # PDF → text sections (PyMuPDF)
│   ├── chunker/
│   │   └── chunker.py            # RawSection → token-aware Chunk
│   ├── indexer/
│   │   ├── db_store.py           # SQLite read/write for chunks
│   │   ├── embedder.py           # sentence-transformers wrapper
│   │   ├── image_embedder.py     # CLIP image embeddings
│   │   ├── bm25_index.py         # rank_bm25 wrapper
│   │   ├── faiss_store.py        # FAISS wrapper
│   │   └── hybrid_retriever.py   # BM25 + dense → RRF → rerank pipeline
│   ├── query/
│   │   └── query_parser.py       # Symbol detection + intent classification
│   └── generator/
│       └── generator.py          # Claude answer generation + citation building
└── tests/
    ├── eval.py                   # Regression evaluation suite
    └── test_multimodal.py        # Multimodal retrieval tests

Quick start

1. Install

# Python 3.11+ recommended
python -m venv .venv
source .venv/bin/activate          # Windows: .venv\Scripts\activate
pip install -r requirements.txt

2. Configure

cp .env.example .env
# Edit .env and set ANTHROPIC_API_KEY

3. Ingest (crawl + index)

# Quick smoke-test with the first 100 pages
python src/cli/ingest.py --max-pages 100

# Full ingest of all JDK 25 API pages (~4,000 pages)
python src/cli/ingest.py

# Re-build indexes without re-crawling (pages already in DB)
python src/cli/ingest.py --skip-crawl

# Ingest a supplementary PDF
python src/cli/ingest.py --pdf resource/postgresql-16-A4.pdf

4. Serve

python src/cli/serve.py
# Web UI:  http://localhost:8000/
# Docs:    http://localhost:8000/docs

5. Query

curl -s -X POST http://localhost:8000/query \
  -H "Content-Type: application/json" \
  -d '{"question": "What does ArrayList ensure about nulls?"}' \
  | python -m json.tool

Example response:

{
  "question": "What does ArrayList ensure about nulls?",
  "answer": "ArrayList permits null elements [1]...",
  "citations": [
    {
      "index": 1,
      "url": "https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/ArrayList.html#class-description",
      "type_fqn": "java.util.ArrayList",
      "section_title": "ArrayList – Description"
    }
  ],
  "related_apis": ["java.util.ArrayList", "java.util.List"],
  "latency_ms": 1240.5
}

6. Evaluate

python tests/eval.py --server http://localhost:8000   # against running server
python tests/eval.py --inline                          # in-process, no server

API reference

Method & path Purpose
POST /query Main Q&A endpoint (text)
POST /query-with-image Q&A augmented with an uploaded image
POST /chat Conversational endpoint
GET /suggest?q=<partial> Type-ahead FQN/member suggestions
GET /stats Index statistics
GET /health Liveness / readiness check
GET / Web UI

POST /query body: { "question": string, "top_k": 8, "debug": false } Response: { answer, citations[], related_apis[], latency_ms, debug_chunks? }


Configuration

Key settings (full list in config.py / .env.example):

Variable Default Description
ANTHROPIC_API_KEY Required. Your Anthropic API key
CLAUDE_MODEL claude-sonnet-4-6 Generation model
EMBEDDING_MODEL BAAI/bge-small-en-v1.5 Embedding model
RERANKER_MODEL cross-encoder/ms-marco-MiniLM-L-6-v2 Cross-encoder reranker
BM25_TOP_K / DENSE_TOP_K 50 / 50 Candidates before fusion
RERANK_TOP_K 8 Final chunks after reranking
MAX_CONCURRENT / REQUEST_DELAY 5 / 1.0 Crawler concurrency & politeness

Known limitations

  • JS-rendered content — the crawler fetches raw HTML only; standard Oracle Javadoc pages are static, so this is rarely an issue in practice.
  • Crawl politeness — default 1 req/s avoids Oracle rate limits; raise REQUEST_DELAY if you see 429s.
  • No incremental re-index — re-running ingest re-embeds all chunks; diff-by-content-hash is a planned improvement.
  • Overload disambiguation — for heavily overloaded methods (e.g. String.valueOf), all overloads are returned and answered with subheadings.

License

MIT — see LICENSE.

About

RAG system that answers Java/JDK 25 API questions with cited, source-grounded answers — hybrid BM25 + dense retrieval, cross-encoder reranking, and Claude.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors