26382a7ac6
CI / Clippy (push) Failing after 15m13s
CI / Test (ubuntu-latest) (push) Failing after 16m1s
CI / Test (macos-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Build (no embeddings / no ORT) (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Cookbook (Node) (push) Has been cancelled
CI / Pi Extension (Node) (push) Has been cancelled
CI / Rust SDK (lean-ctx-client) (push) Has been cancelled
CI / Embed SDK (lean-ctx-sdk) (push) Has been cancelled
CI / Python SDK (leanctx) (push) Has been cancelled
CI / Hermes Plugin (Python) (push) Has been cancelled
CI / SDK Conformance Matrix (push) Has been cancelled
CI / Coverage (push) Has been cancelled
CI / cargo-deny (push) Has been cancelled
CI / Adversarial Safety (push) Has been cancelled
CI / Benchmarks (push) Has been cancelled
CI / Output-Quality Gate (eval A/B) (push) Has been cancelled
CI / Documentation (push) Has been cancelled
CI / CI Green (push) Has been cancelled
JetBrains Plugin / Actionlint (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
CodeQL / Analyze (rust) (push) Has been cancelled
JetBrains Plugin / Validation (push) Has been cancelled
JetBrains Plugin / Build (push) Has been cancelled
JetBrains Plugin / Test (push) Has been cancelled
Security Check / Security Scan (push) Has been cancelled
106 lines
5.0 KiB
Markdown
106 lines
5.0 KiB
Markdown
# Dense Backends — where your vectors live
|
|
|
|
The dense (embedding) half of lean-ctx's hybrid retriever needs a vector store.
|
|
By default that store is **in-process and on disk** — no service, no container,
|
|
nothing to operate. For teams that already run a vector database, lean-ctx can
|
|
delegate dense search to it instead.
|
|
|
|
| Backend | Runs where | Setup | Best for |
|
|
|---|---|---|---|
|
|
| **local** (default) | inside the lean-ctx process, persisted next to the BM25 index | none | individuals and most teams — zero-ops, deterministic |
|
|
| **qdrant** | your [Qdrant](https://qdrant.tech) server (self-hosted or cloud) | `LEANCTX_QDRANT_URL` | fleets sharing one index, corpora beyond one machine's RAM |
|
|
| **pgvector** | your PostgreSQL with the [pgvector](https://github.com/pgvector/pgvector) extension | `LEANCTX_PGVECTOR_URL` + `psql` client | orgs that already operate Postgres and want vectors under existing backup/HA/access policies |
|
|
|
|
Both backends consume the **same embedding pipeline** — the local ONNX model
|
|
selected via [`[embedding].model`](custom-embeddings.md) produces the vectors;
|
|
only the storage and the nearest-neighbor search move. BM25, SPLADE, RRF fusion
|
|
and reranking are unaffected by the backend choice.
|
|
|
|
## Selecting a backend
|
|
|
|
```bash
|
|
# Explicit
|
|
export LEANCTX_DENSE_BACKEND=local # default
|
|
export LEANCTX_DENSE_BACKEND=qdrant
|
|
export LEANCTX_DENSE_BACKEND=pgvector
|
|
|
|
# Implicit: setting a backend URL selects that backend automatically
|
|
export LEANCTX_QDRANT_URL=http://127.0.0.1:6333
|
|
export LEANCTX_PGVECTOR_URL=postgres://user:pass@127.0.0.1:5432/leanctx
|
|
# (if both URLs are set, qdrant wins — set LEANCTX_DENSE_BACKEND to override)
|
|
```
|
|
|
|
An unknown value fails fast with a clear error rather than silently falling
|
|
back — retrieval quality should never degrade without you noticing.
|
|
|
|
## Qdrant configuration
|
|
|
|
```bash
|
|
export LEANCTX_QDRANT_URL=http://127.0.0.1:6333 # required
|
|
export LEANCTX_QDRANT_API_KEY=… # optional (Qdrant Cloud / secured instances)
|
|
export LEANCTX_QDRANT_TIMEOUT_SECS=10 # optional, default 10
|
|
export LEANCTX_QDRANT_COLLECTION_PREFIX=lctx_code_ # optional, default shown
|
|
```
|
|
|
|
- **Collections are per project and per model dimension** — the collection name
|
|
is derived from the project root's namespace hash and the embedding model's
|
|
vector width, so switching models can never mix incompatible vectors.
|
|
- **Sync is incremental.** On each dense search lean-ctx upserts only chunks of
|
|
files that changed since the last sync (delete-by-file, then re-upsert). A
|
|
fresh collection is populated once.
|
|
- **The build stays quiet.** The `qdrant` and `pgvector` build features are part
|
|
of the default feature set (so release binaries have them); requesting a
|
|
backend whose feature was compiled out produces an explicit error, not a
|
|
silent local fallback.
|
|
|
|
Run a local Qdrant for testing:
|
|
|
|
```bash
|
|
docker run -p 6333:6333 qdrant/qdrant
|
|
LEANCTX_QDRANT_URL=http://127.0.0.1:6333 lean-ctx search --semantic "auth flow"
|
|
```
|
|
|
|
## pgvector configuration
|
|
|
|
```bash
|
|
export LEANCTX_PGVECTOR_URL=postgres://user:pass@127.0.0.1:5432/leanctx # required
|
|
export LEANCTX_PGVECTOR_TIMEOUT_SECS=10 # optional, default 10
|
|
export LEANCTX_PGVECTOR_TABLE_PREFIX=lctx_code_ # optional, default shown
|
|
```
|
|
|
|
- **Talks through the `psql` CLI** — no native driver, no async runtime added to
|
|
lean-ctx. The PostgreSQL client tools must be on `PATH` (macOS:
|
|
`brew install libpq`, Debian/Ubuntu: `apt install postgresql-client`).
|
|
- **Tables are per project and per model dimension** (same namespacing rule as
|
|
qdrant collections): `lctx_code_<namespace-hash>_d<dims>`, created on first
|
|
use together with `CREATE EXTENSION IF NOT EXISTS vector`. The database user
|
|
needs extension-create rights once (or a DBA pre-installs the extension).
|
|
- **Same incremental sync** — delete-by-file then re-upsert for changed files,
|
|
one full upsert for a fresh table. Point ids are identical to the qdrant
|
|
scheme, so backend switches never mix identities.
|
|
- **Search is exact** (`ORDER BY embedding <=> query`) — correct at any corpus
|
|
size, and you can add an HNSW/IVFFlat index in Postgres later without any
|
|
lean-ctx change.
|
|
|
|
Run a local pgvector Postgres for testing:
|
|
|
|
```bash
|
|
docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=lctx pgvector/pgvector:pg16
|
|
LEANCTX_PGVECTOR_URL=postgres://postgres:lctx@127.0.0.1:5432/postgres \
|
|
lean-ctx search --semantic "auth flow"
|
|
```
|
|
|
|
## What stays true regardless of backend
|
|
|
|
- Embeddings are produced **locally** (ONNX; swappable via
|
|
[`hf:org/repo`](custom-embeddings.md)) — no embedding API, no per-token fees.
|
|
- The lexical BM25 floor is always available: if the dense backend is
|
|
unreachable, hybrid search degrades to BM25 with a warning instead of failing
|
|
the query.
|
|
- Chunk identity is content-derived, so re-indexing an unchanged corpus is a
|
|
no-op on the store.
|
|
|
|
*See also: [Context Infrastructure](context-infrastructure.md),
|
|
[Custom Embedding Models](custom-embeddings.md),
|
|
[lean-ctx vs naive RAG](../comparisons/vs-naive-rag.md).*
|