RAG în 2026: cum alegi vector search-ul potrivit pentru producție
Ghid practic pentru CTO și arhitecți AI: ScaNN, DiskANN, Qdrant, LanceDB, USearch — ce funcționează în DC pe NVMe și ce alegi pentru workstation.
RAG în 2026: cum alegi vector search-ul potrivit pentru producție
Două lucrări academice din ultimii cinci ani au schimbat economia RAG-ului mai mult decât orice model nou de embeddings: Vamana / DiskANN de la Microsoft Research (NeurIPS 2019) și anisotropic vector quantization de la Google Research (ICML 2020). Fără ele, un index pe un miliard de vectori cerea servere cu sute de GB RAM. Cu ele, același index încape pe un singur nod cu 64 GB RAM și un NVMe decent. Articolul ăsta arată ce înseamnă concret diferența — și ce alegem în producție pentru clusterele care servesc clienții noștri.
Algoritmii care au schimbat regulile
Până în 2019, vector search la scară mare se rezuma practic la HNSW (Hierarchical Navigable Small World) ținut integral în memorie. Logica era simplă: graful de proximitate are nevoie de salt aleator între noduri, iar fiecare miss la cache costă microsecunde, deci totul în RAM. Consecința practică: 1 miliard de vectori float32 de 768 dimensiuni = ~3 TB de RAM. Inacceptabil pentru orice buget care nu vine de la hyperscaler.
Echipa de la Microsoft Research India a publicat la NeurIPS 2019 lucrarea DiskANN, semnată de Suhas Subramanya, Devvrit, Rohan Kadekodi, Ravishankar Krishnaswamy și Harsha Simhadri. Contribuția centrală e graful Vamana — construit explicit pentru acces secvențial pe SSD, cu o regulă de pruning care reduce drastic numărul de salturi necesare per query. Concret: graful și vectorii originali stau pe disc, iar în RAM ții doar vectorii comprimați (Product Quantization). La căutare faci câteva zeci de hop-uri pe SSD în loc de mii în RAM, dar fiecare hop costă ~100 µs pe NVMe — și ajunge.
Anul următor, Google Research a publicat ScaNN cu anisotropic vector quantization — semnată Ruiqi Guo, Philip Sun, Erik Lindgren, Quan Geng, David Simcha, Felix Chern și Sanjiv Kumar. Insight-ul e contra-intuitiv: când comprimi un vector, nu vrei să minimizezi eroarea totală de reconstrucție. Vrei să minimizezi eroarea pe componenta paralelă cu query-ul, pentru că aia contează la inner product. Funcția de pierdere anizotropă penalizează diferit componenta paralelă față de cea ortogonală — și rezultatul, măsurat pe ann-benchmarks.com, e dublu QPS la aceeași acuratețe față de competitorii din 2020.
Cele două idei se combină. Astăzi rulezi Vamana pe disc cu cuantificare în RAM, sau ScaNN pur in-memory pentru latențe foarte mici. Costul per miliard de vectori a scăzut cu un ordin de mărime — și asta a făcut posibilă noua generație de produse RAG care manipulează corpusuri legale, medicale sau de cod cu sute de milioane de fragmente. Vezi și discuția noastră despre când RAG-ul bate fine-tuning-ul — fără economia asta, alegerea era forțată.
Peisajul tehnologic 2026
Șase tehnologii merită cunoscute, fiecare cu un teren clar de aplicare.
Qdrant — scris în Rust, cu API HTTP/gRPC, suport nativ pentru filtre payload complexe în timpul căutării. Implementează atât HNSW in-memory cât și storage on-disk cu scalar/binary quantization. Default-ul nostru pentru DC.
Milvus — distribuit, cu separare compute/storage. Suportă indexul DISKANN ca tip nativ, bazat exact pe Vamana de la Microsoft. Are sens dacă ai deja Kubernetes operațional și volume de tip “câteva miliarde de vectori” peste un singur tenant.
pgvector — extensia Postgres. Simplă, integrată cu restul datelor relaționale. Bună până la ~10 milioane de vectori per tabel. Peste asta, latențele pleacă în sus chiar și cu HNSW activ.
LanceDB — embedded, format columnar Lance (Rust). Nu cere server separat. Citește direct de pe disc cu acces random foarte rapid și stochează vectorii alături de date brute multimodale în același fișier. Ideal pentru workstation și aplicații desktop.
USearch — bibliotecă HNSW single-file de la Unum, compatibilă cu 11 limbaje și un singur fișier index portabil între ele. Bună pentru embedded și edge unde Qdrant ar fi over-engineered.
FAISS — biblioteca Meta. Excelentă pentru research și prototipuri. Lipsa persistenței native și a unei API server-side o scoate din producție pentru noi.
Decision matrix
| Context | Volum | Latență țintă | Tehnologie recomandată |
|---|---|---|---|
| Producție DC, filtre complexe | 10M – 1B+ | < 50 ms p95 | Qdrant on-disk + int8 |
| Producție DC, multi-tenant K8s | > 1B per tenant | < 100 ms p95 | Milvus + DISKANN |
| Aplicație existentă pe Postgres | < 10M | < 100 ms | pgvector |
| Workstation, RAG local | 100K – 10M | < 20 ms | LanceDB |
| Edge / embedded / mobile | < 1M | variabilă | USearch |
| Research, prototip | orice | irelevant | FAISS |
flowchart TD
A[Aleg tehnologia vectorială] --> B{Rulez pe<br/>workstation sau DC?}
B -->|Workstation / laptop| C{Stochez și<br/>multimodal?}
C -->|Da| D[LanceDB]:::good
C -->|Nu, doar vectori| E[USearch]:::niche
B -->|DC / cluster| F{Volum<br/>per tenant?}
F -->|Sub 1B vectori| G[Qdrant on-disk<br/>+ Scalar Quantization]:::good
F -->|Peste 1B, K8s ready| H[Milvus + DISKANN]:::neutral
classDef good fill:#15803d,stroke:#166534,color:#fff
classDef neutral fill:#475569,stroke:#334155,color:#fff
classDef niche fill:#1d4ed8,stroke:#1e40af,color:#fff
Playbook DataCenter — Qdrant on-disk + cuantificare
În clusterul nostru intern care alimentează AEGIS și Lexnomia rulăm Qdrant pe noduri cu NVMe Enterprise (Samsung PM9A3 sau Micron 7450) și 128 GB RAM per nod. Pattern-ul nu e exotic, dar combinația de setări face diferența între un index care încape pe trei noduri și unul care ar cere zece.
Cheia e configul hibrid: vectori originali pe disc, vectori cuantificați în RAM. Qdrant păstrează full-precision pe disc pentru rescoring și permite oversampling dinamic. În RAM intră doar versiunea int8 (Scalar Quantization), care conform documentației Qdrant reduce memoria per vector cu un factor de 4 — un vector de 768 float32 trece de la 3072 bytes la 768 bytes. Dacă ai nevoie de mai mult, Binary Quantization scade cu un factor de 32, dar cu rescoring obligatoriu pentru a recupera recall-ul.
Config-ul minim pentru o colecție de producție arată așa:
from qdrant_client import QdrantClient
from qdrant_client.http import models
client = QdrantClient(url="https://qdrant-prod.caitech.local:6333", api_key=API_KEY)
client.create_collection(
collection_name="docs_lexnomia_v3",
vectors_config=models.VectorParams(
size=768,
distance=models.Distance.COSINE,
on_disk=True,
),
quantization_config=models.ScalarQuantization(
scalar=models.ScalarQuantizationConfig(
type=models.ScalarType.INT8,
quantile=0.99,
always_ram=True,
),
),
hnsw_config=models.HnswConfigDiff(
m=16,
ef_construct=128,
on_disk=True,
),
optimizers_config=models.OptimizersConfigDiff(
memmap_threshold=20000,
),
)
Câteva detalii care contează în practică:
quantile=0.99taie outlier-ii înainte de mapping float32 → int8. Fără el, un singur vector aberant strică scala pentru tot setul. 0.99 e un compromis bun pentru embeddings produse de modele OpenAI, Cohere sau BGE.m=16șief_construct=128sunt defaults rezonabile pentru recall@10 peste 95%. Dacă ai latență prea mare, scaziefla query-time, nu la indexare.memmap_threshold=20000mută segmentele mari pe mmap în loc să le încarce direct — utile când nodul are mai multe colecții concurente.
Pentru filtre payload (an, jurisdicție, tip de document) Qdrant indexează separat câmpurile pe care le marchezi explicit. La 50M+ vectori, fără index pe payload, filtrul devine bottleneck-ul, nu căutarea ANN.
Binary Quantization (1 bit per dimensiune) merită încercată doar peste 500M vectori și doar cu embeddings antrenate pe distribuții relativ izotrope (OpenAI text-embedding-3-large e ok, multe modele open-source nu sunt). Testează cu un set de validare reprezentativ înainte să-l pui în producție.
Playbook Workstation — RAG local pe laptop de putere
Al doilea pattern e mai puțin discutat, dar îl folosim intern pentru indexarea repo-urilor de cod, a corpusurilor legale clasificate și pentru recenta noastră platformă DR off-site. Mașina de referință: Dell Pro Max 16 Plus cu Intel Core Ultra 9 285HX (24 cores, 24 threads, până la 5.5 GHz), 64 GB DDR5, 4 TB NVMe și NVIDIA RTX PRO Blackwell pentru laptopuri workstation. E un laptop, nu un rack. Și totuși indexează 5 milioane de fragmente PDF în câteva ore.
Aici alegerea naturală e LanceDB. Trei motive concrete:
- Zero ops — embedded, fără server, fără Kubernetes. Pornești un proces Python și ai DB.
- Format columnar Lance — același fișier ține și textul brut, și metadata, și vectorii. Nu mai jonglezi între Postgres pentru metadata și Qdrant pentru vectori.
- Random access pe NVMe — Lance e proiectat de la zero pentru ML pe object store și SSD, cu zero-copy versioning.
GPU-ul nu rulează vector search-ul (LanceDB e CPU-bound pe acces). Rolul lui e la embeddings: rulezi un model BGE-M3 sau Nomic local cu vLLM sau llama.cpp, generezi vectorii pe GPU și-i scrii direct în LanceDB. Pe Blackwell, embeddings la 5000+ docs/secundă pentru modele 300M parametri. Vezi și pattern-ul nostru pentru SIEM cu LLM local — aceeași arhitectură, alt corpus.
Codul minim:
import lancedb
import pyarrow as pa
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("BAAI/bge-m3", device="cuda")
db = lancedb.connect("/data/rag_local")
schema = pa.schema([
pa.field("vector", pa.list_(pa.float32(), 1024)),
pa.field("text", pa.string()),
pa.field("source", pa.string()),
pa.field("page", pa.int32()),
])
table = db.create_table("docs", schema=schema, mode="overwrite")
batch = [
{"text": "Regulamentul GDPR articolul 17 ...", "source": "gdpr.pdf", "page": 42},
{"text": "Codul fiscal 2026 art. 126 ...", "source": "codfiscal.pdf", "page": 18},
]
vectors = model.encode([d["text"] for d in batch], normalize_embeddings=True)
for d, v in zip(batch, vectors):
d["vector"] = v.tolist()
table.add(batch)
table.create_index(metric="cosine", num_partitions=256, num_sub_vectors=16)
query = model.encode("ce drepturi am la ștergerea datelor", normalize_embeddings=True)
results = table.search(query).limit(10).to_pandas()
Pentru USearch pattern-ul e similar, doar că separi explicit indexul de payload. Avantajul: un singur fișier .usearch portabil din Python în Rust sau Swift — util dacă vrei să livrezi același index într-o aplicație mobile. Pentru un agent local conversațional cu memorie persistentă, USearch + SQLite e combinația cu cea mai mică amprentă.
Un detaliu de exploatare: pe workstation, fragmentarea NVMe contează. Dacă rescrii indexul des, programează compactare săptămânală — LanceDB are optimize() exact pentru asta, iar USearch are save()/load() care rescrie ordonat. Fără ele, latența urcă lent în câteva luni.
Concluzie — ce alegi în 2026
Vector search nu mai e blocajul. Modelele de embeddings, retrievalul hibrid (dense + BM25), reranking-ul și fereastra de context sunt acum lucrurile pe care le optimizezi în ordinea asta. Dacă alegi Qdrant on-disk cu int8 pentru cluster și LanceDB pe workstation, ai acoperit 90% din scenariile de producție pentru o echipă engineering europeană mid-market, fără să te legi de un cloud provider și fără bill lunar surpriză.
Ce nu e clar din benchmark-uri: cum se comportă stack-ul pe corpusul tău specific, cu filtre reale și user-i concurenți. Aici poate ajuta o sesiune scurtă de validare. Discutăm despre arhitectura ta de retrieval pe pagina noastră de servicii AI și infrastructură.
Lectură suplimentară
- Când dense retrieval bate keyword search și când nu
- Cum implementezi citation grounding fără să strici latența
- Routing inteligent între LLM-uri în funcție de cost și complexitate
Lectură estimată: 11 minute