Skip to main content

Cyber AI România

RAG hibrid în practică: combinarea BM25, embeddings și cross-encoder reranking într-un singur pipeline

Un sistem RAG bazat exclusiv pe embeddings poate înțelege sensul unei întrebări, dar poate rata coduri de produs, numere de contract, acronime sau expresii exacte. Un sistem bazat numai pe BM25 găsește foarte bine cuvintele identice, însă poate rata documentele care folosesc formulări diferite pentru aceeași idee.

Pipeline-ul hibrid le folosește pe amândouă: BM25 pentru precizie lexicală, embeddings pentru similaritate semantică și un cross-encoder pentru ordonarea finală a candidaților.

Elastic și OpenSearch descriu căutarea hibridă ca îmbinarea căutării full-text cu cea vectorială într-o listă comună. BM25 este eficient când termenii exacți contează, iar vectorii sunt utili când întrebarea și documentul exprimă aceeași idee prin cuvinte diferite.

Pregătește documentele pentru ambele tipuri de căutare

Înainte de indexare, împarte documentele în fragmente suficient de mici pentru a putea fi citate și suficient de mari pentru a păstra contextul. Pentru documentație tehnică, poți porni cu aproximativ 300–500 de tokenuri și o suprapunere de 50–80.

Fiecare fragment ar trebui să conțină:

chunk_id
document_id
title
section
text
source_url
updated_at
access_level
embedding

Câmpul text este indexat pentru BM25, iar embedding păstrează reprezentarea vectorială. Nu elimina titlurile, codurile și denumirile tehnice în timpul curățării; acestea sunt exact elementele pe care căutarea lexicală le poate recupera mai bine.

Rulează două căutări în paralel

Pentru întrebarea:

Ce perioadă de retenție se aplică logurilor de autentificare?

pipeline-ul execută două operații:

bm25_hits = lexical_search(query, limit=30)
vector_hits = semantic_search(embed(query), limit=30)

BM25 poate găsi fragmente care conțin exact „retenție” și „loguri de autentificare”. Căutarea vectorială poate găsi și formulări precum „păstrarea jurnalelor de acces” sau „durata stocării evenimentelor de login”.

Nu trimite direct toate cele 60 de rezultate către model. Cele două liste pot conține aceleași fragmente și folosesc scoruri calculate pe scale diferite.

Combină listele cu Reciprocal Rank Fusion

O variantă practică este Reciprocal Rank Fusion, prescurtat RRF. Metoda combină pozițiile documentelor în liste, nu valorile brute ale scorurilor. Din acest motiv, nu trebuie să compari direct un scor BM25 de 12,4 cu o similaritate vectorială de 0,82.

Elastic recomandă RRF ca punct de pornire pentru căutarea hibridă, deoarece funcționează cu indicatori de relevanță diferiți și necesită puțină ajustare inițială.

Fluxul poate arăta astfel:

candidates = rrf_fusion(
    result_lists=[bm25_hits, vector_hits],
    rank_constant=60
)

candidates = deduplicate(candidates)
candidates = candidates[:40]

Nu presupune că valoarea 60 sau limita de 40 este optimă pentru orice proiect. Păstrează-le ca valori inițiale și testează-le pe propriile întrebări.

Aplică cross-encoder reranking

Retrieverele rapide compară separat query-ul și documentele. Cross-encoderul primește simultan perechea formată din întrebare și fragment și calculează un nou scor de relevanță.

Această evaluare este mai precisă, dar mai costisitoare. Din acest motiv, cross-encoderul nu trebuie rulat pe întreaga bază de date, ci doar pe candidații deja recuperați. Sentence Transformers recomandă exact acest model în două etape: recuperare rapidă a unui set mai mare și reranking precis al rezultatelor selectate.

Exemplu:

pairs = [(query, item["text"]) for item in candidates]
scores = cross_encoder.predict(pairs)

reranked = sorted(
    zip(candidates, scores),
    key=lambda item: item[1],
    reverse=True
)

final_context = reranked[:8]

Pentru început, recuperează 20–50 de candidați și trimite către LLM numai primele 5–10 fragmente după reranking. Dacă alegi prea puține rezultate înainte de cross-encoder, documentul corect poate fi eliminat prematur. Dacă alegi prea multe, latența și costul cresc.

Construiește răspunsul numai din fragmentele finale

Promptul generatorului trebuie să interzică completarea golurilor:

Răspunde numai pe baza fragmentelor furnizate.

Pentru fiecare afirmație importantă, indică sursa și secțiunea.
Dacă informația nu apare în context, spune clar că nu poate fi confirmată.
Nu combina reguli din versiuni diferite ale aceluiași document.

Păstrează în context document_id, titlul, secțiunea și data actualizării. Astfel, răspunsul poate cita sursa reală și poate evita folosirea unui document expirat.

Evaluează fiecare etapă separat

Nu măsura numai dacă răspunsul final „sună bine”. Creează un set de întrebări reale și notează fragmentele corecte pentru fiecare întrebare.

Urmărește:

Recall@k pentru BM25
Recall@k pentru embeddings
Recall@k după RRF
MRR sau nDCG după reranking
acuratețea citărilor
latența totală
procentul răspunsurilor neconfirmate

Qdrant recomandă construirea unui set ground truth și testarea parametrilor pe datele proiectului, deoarece numărul candidaților și modelele potrivite diferă între domenii.

Un pipeline hibrid bun nu înseamnă doar „BM25 plus vectori”. Ordinea contează: recuperezi lexical și semantic, unești rezultatele, elimini duplicatele, aplici reranking și abia apoi construiești răspunsul. În acest mod, RAG-ul păstrează atât precizia termenilor exacți, cât și înțelegerea semantică.

Surse folosite

Elastic – Hybrid Search, Reciprocal Rank Fusion și Ranking and Reranking
OpenSearch – Keyword, Semantic and Hybrid Search
Sentence Transformers – Retrieve & Re-Rank și Cross-Encoders
Qdrant – Hybrid Search with Reranking și FastEmbed Rerankers

Facebook
X
WhatsApp

Te-ar putea interesa si: