eduardweb.
RAG & EmbeddingsAvansat#rag#postgres#pgvector#sql#llm

RAG cu pgvector în Postgres: De ce am renunțat la Pinecone pentru Search Hibrid

De Gabriela Neagu, 25 iul. 2026 · 12 vizualizări · 2 like-uri

Postat 25 iul. 2026
sql
WITH vector_search AS (
  SELECT id, content, 1 - (embedding <=> $1::vector) AS vector_score,
         ROW_NUMBER() OVER (ORDER BY embedding <=> $1::vector) AS rank
  FROM document_chunks
  ORDER BY embedding <=> $1::vector
  LIMIT 40
),
text_search AS (
  SELECT id, content, ts_rank_cd(text_vector, websearch_to_tsquery('romanian', $2)) AS text_score,
         ROW_NUMBER() OVER (ORDER BY ts_rank_cd(text_vector, websearch_to_tsquery('romanian', $2)) DESC) AS rank
  FROM document_chunks
  WHERE text_vector @@ websearch_to_tsquery('romanian', $2)
  LIMIT 40
)
SELECT 
  COALESCE(v.id, t.id) AS id,
  COALESCE(v.content, t.content) AS content,
  COALESCE(1.0 / (60 + v.rank), 0.0) + COALESCE(1.0 / (60 + t.rank), 0.0) AS rrf_score
FROM vector_search v
FULL OUTER JOIN text_search t ON v.id = t.id
ORDER BY rrf_score DESC
LIMIT 10;

Am mutat recent un sistem de RAG pentru o platformă enterprise de la o soluție dedicată cloud (Pinecone) direct în Postgres cu pgvector. Proiectul avea în jur de 400.000 de chunk-uri de text, iar costurile lunare pe infrastructură doar pentru vectori deveniseră ridicole. Câștigul? Am economisit peste 500$ pe lună, am scăpat de latența de rețea dintre servicii și, cel mai important, am rezolvat o problemă gravă pe care căutarea pur vectorială o are.

Problema cu vectorii puri (Dense Retrieval)

Căutarea semantică e genială când userul caută concepte. Dacă întrebi „cum reziliez contractul?”, un model de embeddings precum text-embedding-3-small de la OpenAI va găsi paragraful care vorbește despre „renunțarea la servicii”, chiar dacă cuvântul „reziliez” nu apare deloc acolo.

Problema apare când userul caută termeni preciși. De exemplu: coduri de eroare (ERR_502_TIMEOUT), numere de serie, SKU-uri sau nume proprii de aplicații interne. Modelele de embeddings le urăsc. Le diluează în spațiul vectorial și îți returnează rezultate complet irelevante, dar care „sună” similar contextual.

Aici intervine Hybrid Search: combinăm căutarea semantică (vectorială) cu căutarea tradițională de text (BM25 / Full-Text Search).

Indexarea în Postgres: HNSW și tsvector

Pentru vectori, pgvector ne oferă indexul HNSW (Hierarchical Navigable Small World). Spre deosebire de vechiul IVFFlat, HNSW nu necesită un pas de „training” pe date și are un recall mult mai bun, chiar dacă durează mai mult să-l construiești.

Trade-off-ul sincer? HNSW mănâncă RAM la greu. La cele 400k de documente ale noastre cu embeddings de 1536 de dimensiuni, indexul a ocupat aproape 3.2 GB de memorie. Dacă n-ai RAM suficient în instanță, Postgres va începe să facă swap pe disk și latența sare de la 15ms la 800ms instant.

Pentru căutarea text, folosim coloana nativă tsvector cu index GIN. Aceasta simulează foarte bine algoritmul BM25, făcând stemming și eliminând stop-words.

Fuziunea rezultatelor cu RRF (Reciprocal Rank Fusion)

Cum combini un scor de similitudine cosinus (care e între 0 și 1) cu un scor ts_rank din Postgres (care nu e bounded și depinde de frecvența cuvintelor)?

N-ai cum să le aduni direct. Aici intervine RRF (Reciprocal Rank Fusion). În loc să aduni scorurile numerice, le dai fiecăruia o poziție (rank) în topul propriu și aplici formula 1 / (k + rank), unde k e de obicei o constantă de ajustare (standard e 60).

În codul de mai jos aveți un query SQL complet care face ambele căutări în paralel folosind CTE-uri, le combină prin FULL OUTER JOIN și ordonează totul după scorul RRF. Latența medie pe un Postgres cu 4 vCPU și 16GB RAM este sub 35ms.

Concluzia mea după 6 luni în producție

Până la 2-3 milioane de vectori, nu ai absolut niciun motiv rațional să adaugi o bază de date vectorială separată în stack. Postgres cu pgvector și căutare hibridă rezolvă 95% din cazuri cu complexitate de operare zero.

Voi ce folosiți pentru RAG în producție? Ați rămas pe DB-uri dedicate gen Qdrant/Chroma sau ați consolidat totul în baza principală?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

Doar membrii comunității pot lăsa comentarii.