About Professional
How I Build How I Build Meet the Team
Technology Homelab App Showcase Case Studies
Maverick & Luke Say Hello

Case study

Building a Self-Hosted RAG Service Instead of Adopting a Black Box

Replaced an opaque, poorly-performing off-the-shelf RAG stack with a purpose-built retrieval service: incremental content-hash ingestion, a fast similarity index, a least-privilege database role, and a clean authenticated query contract that a second app consumed without rework.

The challenge

An earlier attempt at a "knowledge base" retrieval layer had adopted an off-the-shelf RAG tool with an embedded vector store. It technically worked, but retrieval quality was poor: broad questions returned generic model answers instead of answers grounded in the ingested source. The stack was also opaque: there was no way to tune how documents were chunked, how retrieval ranked, or where the similarity threshold sat. It had also been wired to call a local embedding model directly, bypassing the mandatory AI gateway, on an untested assumption.

Two premises had calcified around the failure: that a real RAG layer "needed a dedicated AI machine," and that the off-the-shelf tool was good enough to keep. Both turned out to be wrong. The real problem was the ingestion approach (embedding one giant concatenated file) and the tool's opacity, not a hardware limit. A lean, embedding-only service would run fine on the existing hardware, against the Postgres database already there.

Approach

I built a self-hosted RAG service that serves as the retrieval substrate: not a chat UI, but the thing any app can call to get back relevant, cited chunks of a knowledge source. Three decisions drove the build-vs-adopt call:

  1. Transparency and tunability. Owning the chunking, retrieval, reranking, and similarity threshold was the decisive factor: exactly what the off-the-shelf tool couldn't do, and exactly what had made its retrieval poor.
  2. Reuse the database already running. A vector-search extension lives inside the existing database, so there was no separate vector database to operate, back up, or monitor: a whole operational surface eliminated.
  3. Compliant by construction. Routing embeddings through the mandatory AI gateway was satisfied natively by the design, rather than bypassed as the earlier tool had done.

Architecture: a small backend service (one process serving both an admin UI and a JSON API), a dedicated schema tracking collections (a multi-collection model; v1 seeds one), documents (each carrying a content hash that drives incremental ingest), and chunks (the embedding plus provenance columns, including heading, character offsets, and chunk index, so retrievals can cite location, not just the file). The embedding column carries a fast similarity index. The service connects to the database as a dedicated least-privilege login role scoped to only its own schema, through the connection pooler, never with admin credentials. The public contract is a single authenticated query endpoint returning ranked, cited chunks, with tunable top-K and similarity threshold, deliberately shaped to match the consumer app's existing config object so the two round-trip without translation.

Some execution highlights:

Results

What this demonstrates