6.0 KiB
lean-ctx vs naive RAG
Last updated: June 2026 | "Naive RAG" here means the common pattern: chunk everything, embed the chunks into a vector DB, retrieve top-k by cosine similarity, stuff the results into the prompt. It's a great default for large, unstructured corpora — and a poor default for a codebase.
Overview
| lean-ctx | Naive RAG | |
|---|---|---|
| Core idea | Two halves under one pipeline: compress into the window when the material fits, retrieve when it's too big | Retrieve top-k chunks by vector similarity, always |
| Retrieval | Hybrid: BM25 + learned-sparse SPLADE + dense vectors, fused with RRF, then reranked | Single-signal: dense cosine top-k |
| Structure awareness | Tree-sitter AST + code graph (calls, deps, blast radius) | None — text chunks only |
| Determinism | Byte-stable outputs (prompt-cache safe) | Depends on the embedding/index; often not |
| Locality | 100% local single binary | Usually an external vector DB + embedding API |
| Portability of memory | OKF (Markdown) + signed ctxpkg | Vendor-specific index |
The core difference: two problems, not one
Knowledge management for agents is really two problems, and naive RAG only addresses one of them:
-
"It fits, but it's verbose." A file, a diff, a shell log, a handful of docs. The right move is to compress it into the window losslessly — read modes, structural crushing, cached re-reads. Embedding-and-retrieving here loses information you already had room for. This is lean-ctx's default and its origin.
-
"It's too big to fit." A large or dynamic knowledge base. Now you must retrieve — and lean-ctx does, with a hybrid retriever (lexical BM25 + dense embeddings, fused with RRF, optionally reranked), not a single cosine signal.
Naive RAG applies tool #2 to everything, including material that never needed retrieval. That's the "context-stuffing" failure mode: more chunks, lower signal, higher cost, and answers that quietly drift because the model is reasoning over lossy fragments. lean-ctx picks the right half for the material, under one pipeline.
The structure-aware moat
A codebase is not a bag of paragraphs. Functions call functions; a change has a blast radius; a symbol has a definition and references. lean-ctx is structure-aware: it parses 20+ languages with tree-sitter, builds a code graph, and can answer "who calls this / what breaks if I change it" — questions a pile of embedded text chunks fundamentally cannot answer.
Naive vector search treats getUser() and the string "get user" as roughly the
same thing. lean-ctx knows one is a symbol with callers and the other is prose.
That structural signal is the moat: it's what makes retrieval precise on code,
and it's why lean-ctx doesn't rely on embeddings alone. The graph is used at
retrieval time too — associative spreading activation (ACT-R style) surfaces
structurally close code, and the reranker is grounded in 2025 code-retrieval
research (CoRNStack, SACL, SweRank). Embeddings come from a local ONNX model
(swappable; a model2vec fast path skips the attention pass), so this runs with no
external vector DB, no embedding API, and no minutes-long, CPU-melting index
build — the exact overhead that makes people wary of RAG.
Trust: a reproducible retrieval floor
lean-ctx ships a benchmark scorecard (recall@5 / recall@10 / MRR) with a
determinism_digest, plus a dual-arm cost evaluation — so the retrieval quality
floor and the savings are numbers you can re-run, not marketing. Embeddings are
default-on in the hybrid retriever; the lexical BM25 floor is deterministic and
reproducible on its own.
Portable, not locked in
When knowledge leaves a naive-RAG system, it leaves as a vendor-specific vector index. lean-ctx exports knowledge as OKF — plain, git-diffable Markdown — or as a signed, verifiable ctxpkg for distribution. Your accumulated project knowledge is yours to read, edit, review, and move.
Where naive RAG is the right call
We're honest about this — naive RAG (or a plain vector DB) is a better fit when:
- The corpus is huge and unstructured — millions of documents, support tickets, web pages, PDFs — where there is no structure to exploit and brute-force semantic recall is exactly what you want.
- You need cross-domain semantic search at scale, decoupled from any one repo, as a standalone service many apps query.
- You already run a vector DB and want the simplest possible "embed + top-k" path with no code-structure requirements.
lean-ctx is built for coding agents on a codebase. If your problem is "semantic search over a giant text corpus," a dedicated vector database is the right tool — and lean-ctx's hybrid retriever can still complement it for the code half.
When to use which
| Your situation | Use |
|---|---|
| A coding agent that reads files, runs shells, navigates a repo | lean-ctx |
| Knowledge that must be small in-window, precise, and cheap | lean-ctx (compress) |
| A large project knowledge base that needs recall | lean-ctx (hybrid retrieve) |
| A giant, unstructured, cross-app text corpus | a dedicated vector DB / RAG |
| You want portable, hand-editable, no-lock-in memory | lean-ctx (OKF) |
Summary
Naive RAG answers one question — "retrieve top-k similar chunks." lean-ctx answers the real question — "get the right knowledge into the window, whether by compressing what fits or retrieving what doesn't" — and does it with structural awareness of code, deterministic output, and portable memory. Different tools for different jobs; for coding agents, structure and the two-halves pipeline win.
See also: How retrieval works, Context Infrastructure, Dense Backends (local / Qdrant), Knowledge Formats, lean-ctx vs Mem0, lean-ctx vs claude-context.