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

De ce am renunțat la Pinecone pentru pgvector în Postgres (și cum facem hybrid search)

De Diana Oprea, 22 iun. 2026 · 19 vizualizări · 2 like-uri

Postat 22 iun. 2026
sql
WITH semantic_search AS (
  SELECT id, 1 - (embedding <=> $1) AS similarity_score
  FROM documents
  ORDER BY embedding <=> $1
  LIMIT 50
),
text_search AS (
  SELECT id, ts_rank_cd(text_search_vector, query) AS lexical_score
  FROM documents, to_tsquery('romanian', $2) query
  WHERE text_search_vector @@ query
  ORDER BY lexical_score DESC
  LIMIT 50
)
SELECT 
  COALESCE(s.id, t.id) AS id,
  (COALESCE(s.similarity_score, 0) * 0.7) + (COALESCE(t.lexical_score, 0) * 0.3) AS hybrid_score
FROM semantic_search s
FULL OUTER JOIN text_search t ON s.id = t.id
ORDER BY hybrid_score DESC
LIMIT 10;

Salutare! Am trecut recent prin furcile caudine ale unui proiect de RAG (Retrieval-Augmented Generation) unde clientul voia inițial o bază de date vectorială dedicată. După ce am calculat costurile și overhead-ul de mentenanță pentru o infrastructură separată, am decis să ținem totul în Postgres cu pgvector. A fost cea mai bună decizie pentru cele 120.000 de documente din sistem.

De ce să te complici cu sincronizarea datelor între o bază de date relațională și un Vector DB extern? Pierzi tranzacționalitate, ai latență de rețea și adaugi un punct critic de eșec în producție. Cu pgvector, adaugi pur și simplu o coloană de tip vector în tabela ta existentă și ai rezolvat problema.

Indexarea: HNSW vs IVFFlat

La început, pe un set mic de date, căutarea secvențială e rapidă. Dar când treci de câteva zeci de mii de rânduri, query-urile încep să agațe. Am pățit asta când interogările durau peste 180ms.

Soluția a fost trecerea la un index HNSW (Hierarchical Navigable Small World). Spre deosebire de IVFFlat, HNSW nu are nevoie de o etapă de training și oferă o acuratețe mult mai bună la căutare (recall ridicat), chiar dacă baza de date suferă modificări frecvente. Am rulat un index pe distanța cosinus și latența a scăzut instant la sub 12ms.

Dar există un trade-off major: indexul HNSW mănâncă foarte multă memorie RAM și durează destul de mult să se construiască. Pentru dimensiunea de 1536 (specifică modelelor OpenAI), trebuie să fii foarte atent la resursele alocate serverului de Postgres.

De ce embeddings-urile pure nu sunt suficiente

Modelele de embeddings sunt excelente pentru a înțelege contextul semantic. Dacă utilizatorul caută "probleme cu autentificarea", modelul va returna documente despre "eroare la login" sau "resetare parolă".

Totuși, embeddings-urile sunt extrem de slabe la potriviri exacte: coduri de eroare (ex: "ERR-502"), ID-uri de produse sau termeni extrem de specifici. Aici intervine căutarea lexicală (BM25). În Postgres, nu avem BM25 nativ out-of-the-box, dar avem Full-Text Search (FTS) cu tsvector și tsquery, care se comportă extrem de similar în practică.

Căutarea Hibridă (Hybrid Search)

Pentru a obține cele mai bune rezultate în RAG, combinăm cele două lumi. Rulăm o căutare semantică prin pgvector și una lexicală prin FTS, apoi le combinăm scorurile.

Provocarea este că scorul de similaritate cosinus (între 0 și 1) nu se poate aduna direct cu scorul ts_rank (care poate fi mai mare de 1). În exemplul de cod atașat, am folosit o metodă simplă de normalizare și ponderare. Alocăm o pondere de 70% pentru căutarea semantică și 30% pentru cea lexicală.

Această abordare ne-a salvat de la implementarea unui serviciu complex de re-ranking (cum ar fi Cohere) și rulează direct în baza de date, într-un singur query SQL. Voi ce folosiți pentru RAG în producție? Rămâneți la Postgres sau preferați baze dedicate?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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