Research Assistant Platform

Source-grounded research over uploaded PDFs.

This view explains the project as a working system: what it is for, how the web app, FastAPI service, ADK agent, Gemini clients, PostgreSQL, pgvector, ingestion pipeline, retrieval service, citations, evaluation, and security boundaries fit together.

Purpose

The platform is a portfolio-grade research workspace inspired by the useful parts of NotebookLM and ChatGPT, but built to expose the mechanics: source parsing, retrieval, agent tool use, citations, traces, quality checks, and security boundaries.

User problem

Generic chat systems often answer without showing which passages influenced the response. This project prioritizes traceable evidence and refusal when evidence is too weak.

Target user

Developers, researchers, students, analysts, and specialists who need to reason over a private document collection and verify source claims.

Version 1 outcome

Five uploaded PDFs can be queried, relevant chunks are retrieved, answers cite exact pages, and behavior is measurable through deterministic tests and later evals.

Architecture

The system keeps UI, API, model calls, agent orchestration, ingestion, retrieval, and storage in explicit boundaries. That makes the stack easier to test and harder to blur with hidden framework behavior.

Browser
  -> Next.js Web App
      -> FastAPI Agent API
          -> Gemini chat client
          -> Google ADK Research Agent
              -> read-only tools
              -> retrieval-backed search_documents
          -> Document Ingestion Service
              -> PDF validation
              -> PyMuPDF extraction
              -> page-bounded chunking
              -> embedding generation
          -> Retrieval Service
              -> query embedding
              -> pgvector similarity search
              -> metadata filters
              -> evidence packaging
          -> PostgreSQL + pgvector

Web app

Provides the user workflow: collection selection, PDF upload, question submission, answer rendering, citations, retrieved evidence, health checks, and later evaluation report views.

Agent API

Owns request validation, dependency construction, stable error responses, model client calls, ADK runtime execution, session handling, document endpoints, retrieval diagnostics, and response schemas.

Storage

PostgreSQL stores documents, original PDF bytes, pages, chunks, hashes, index status, collection identity, and vector embeddings. pgvector performs local similarity search.

Phase Roadmap

The roadmap is ordered by dependency. Each phase proves one layer before adding the next so the project avoids hiding fundamentals behind managed abstractions.

Phase 0

Repository and foundations

Monorepo, Next.js, FastAPI, Docker Compose, PostgreSQL, pgvector, linting, tests, and environment handling.

Implemented
Phase 1

Gemini fundamentals

Simple Gemini request, structured output, streaming, timeout handling, token metadata, latency, and prompt versioning.

Implemented
Phase 2

Tool calling

Explicit read-only document tools, validated tool input, safe tool failures, and inspectable tool traces.

Implemented
Phase 3

Google ADK

One ADK research agent, session handling, runtime adapter, structured final answers, and tool invocation tests.

Implemented
Phase 4

Document ingestion

PDF upload, validation, SHA-256 duplicate detection, PyMuPDF extraction, page records, chunks, persisted sources, and re-indexing.

Implemented
Phase 5

Local RAG

Embeddings, pgvector schema, vector retrieval, metadata filters, retrieval debug view, cited answers, and insufficient-evidence behavior. Embedding abstraction complete; pgvector integration and retrieval system in progress.

In Progress
Phase 6

Evaluation and quality

Deterministic quality metrics including retrieval recall@k, citation validity, fact coverage, and forbidden-claim detection. Full eval dataset and CLI scoring tool implemented.

Implemented
Phases 7-11

Security, MCP, cloud, governance

Adversarial tests, threat model, reusable MCP server, Google Cloud deployment, Terraform, model cards, and portfolio artifacts.

Planned

API Surface

The FastAPI service is the main integration boundary. It keeps request and response contracts typed with Pydantic models and maps expected failures to stable error codes.

Endpoint Purpose Important response details
GET /health Checks service health and database connectivity. Returns ok only when the API can connect to PostgreSQL.
POST /chat Runs the plain Gemini chat path from Phase 1. Returns answer, model name, prompt version, and latency.
POST /chat/stream Streams Gemini response chunks as newline-delimited events. Returns chunk, done, or error events with stable event types.
POST /agent/chat Runs the ADK research agent with optional session continuation and corpus filters. Returns answer, session ID, citations, retrieved chunks, refusal state, warnings, trace, model, prompt version, and latency.
POST /documents Uploads a PDF into a collection and indexes source-derived records. Returns document metadata, page count, status, and chunk count.
GET /documents/{id} Fetches persisted document metadata. Includes filename, MIME type, hash, page count, status, and timestamps.
GET /documents/{id}/pages/{page} Fetches extracted page text for citation inspection. Returns page number, text, and source identity.
POST /documents/{id}/reindex Rebuilds page and chunk records from stored source bytes. Returns refreshed document status and chunk count.
POST /retrieval/search Debugs retrieval without invoking the agent. Returns ranked chunks, scores, configured top-k, minimum score, and latency.

Data Flow

Ingestion and answering are intentionally separate. Deterministic indexing happens before any agent reasoning. The agent later consumes retrieval output as evidence.

1 Upload

The browser sends a PDF and optional collection ID to the API.

2 Validate

The API checks media type, size, page count, PDF validity, and duplicate hash.

3 Extract

PyMuPDF extracts page text while preserving page numbers for citations.

4 Chunk

Pages are split into bounded overlapping chunks with document and page metadata.

5 Embed

The embedding client generates fixed-dimension vectors for chunk text.

6 Persist

Document, source bytes, pages, chunks, hashes, status, and embeddings are stored.

RAG Pipeline

Phase 5 connects persisted document chunks to the ADK agent through a local retrieval service. The design keeps retrieval inspectable instead of delegating it to a managed black box.

Embedding generation

The embedding interface supports fake deterministic vectors in tests and Gemini embeddings in local runs. Document embeddings and query embeddings use different request purposes so provider formatting stays centralized.

Similarity search

PostgreSQL stores vectors through pgvector. Retrieval uses cosine distance, top-k limits, metadata filters, and a minimum score threshold before packaging evidence for the API or agent.

Evidence boundary

Retrieved text is untrusted. The answer prompt must frame chunks as evidence, never as instructions that can modify tools, policy, credentials, or authorization.

Citations and refusal

Structured citations must map to retrieved chunks and exact pages. When evidence is too weak or citations cannot be validated, the response should refuse or warn instead of presenting unsupported claims.

Core Contracts

The project relies on stable typed contracts at module boundaries. These contracts make endpoint tests and later evaluations possible.

Document

  • id, collection_id, filename, MIME type, SHA-256 hash
  • Page count, indexing status, creation timestamp
  • Stored source bytes for reproducible re-indexing

Chunk

  • Chunk ID, document ID, page start, page end, index
  • Content hash and extracted content
  • Vector embedding for pgvector search

Agent answer

  • Answer text, citations, refusal flag, warnings
  • Retrieved chunks and normalized scores
  • Session ID, model, prompt version, latency, tool trace

Verification

The repository favors deterministic tests for default runs and explicit live smoke tests only when secrets and services are available.

Default checks

pnpm format:check
pnpm lint
pnpm test
pnpm --dir apps/web build
uv run --directory apps/agent-api ruff check .
uv run --directory apps/agent-api pytest

Test focus

  • Endpoint contracts and stable error responses
  • PDF upload validation, duplicate detection, page extraction, chunking, and re-indexing
  • Embedding request formatting and vector shape validation
  • Retrieval ranking, score filtering, top-k limits, and metadata filters
  • Agent tool traces, citations, insufficient-evidence behavior, and session handling

Live checks: Gemini smoke tests require GEMINI_API_KEY and an explicit opt-in flag. Docker Compose endpoint checks should be used when Docker is available to verify PostgreSQL and pgvector behavior outside pure unit tests.

Active Phase 5 Blockers

These items are the critical path for completing local RAG. They must be resolved to progress from embedding abstraction to full retrieval and citation capability.

pgvector column and indexing

Chunks table needs vector embedding column, pgvector type binding, and cosine-distance index. Schema migration must support both fresh and migrated Phase 4 databases without hidden side effects.

Embedding pipeline

Chunk embedding generation at ingestion time, query embedding at retrieval time, and proper request-purpose separation for Gemini embeddings API. Deterministic fake embeddings in tests.

Retrieval service and filters

Cosine similarity search with top-k limits, configurable minimum score thresholds, and enforced collection/document filters for both debug endpoints and agent tool calls.

Citations and evidence validation

Structured citations mapping to exact chunks and pages, citation validation against retrieved evidence, and refusal behavior when evidence is insufficient or citations cannot be validated.

Phase 5 Critical Path

Complete local RAG by implementing vector storage, retrieval, and citations before moving into security and cloud phases.

  1. Add pgvector embedding column to chunks table and create cosine index with fresh and migrated database support.
  2. Implement embedding generation at PDF ingestion (deterministic fake embeddings in tests, Gemini embeddings in live runs).
  3. Build retrieval service: similarity search, top-k limits, minimum score filtering, and collection/document scope enforcement.
  4. Add retrieval debug endpoint and integrate into agent tool to replace temporary in-memory search.
  5. Implement structured citations with validation: map to exact pages, verify against retrieved chunks, refuse insufficient evidence.
  6. Add endpoint and integration tests covering retrieval, citations, and insufficient-evidence refusal across multiple documents.