CAI Technology
Menu ☰
rag · · 12 min citire

RAG multilingv RO + EN: pattern de implementare cu BGE-M3

Cum construiți un RAG care răspunde în română pe corpus mixt RO+EN: cross-lingual retrieval, prompts adaptive, citation language match.

CAI Technology · Ultima revizuire: 30.04.2026
RAG multilingv RO + EN: pattern de implementare cu BGE-M3

RAG multilingv RO + EN: pattern de implementare cu BGE-M3

Multe companii românești au corpusuri mixte: contracte și legislație în română, dar și manuale tehnice, white papers și standarde internaționale în engleză. Un asistent care servește această realitate trebuie să răspundă într-o singură limbă (de obicei româna utilizatorului), dar să poată recupera și sintetiza informație din ambele limbi.

Acest articol descrie pattern-ul tehnic pentru un RAG multilingv RO + EN, cu BGE-M3 ca encoder, focus pe cross-lingual retrieval, prompts adaptive și citation language match — provocările care apar în producție.

TL;DR

De ce BGE-M3 pentru cross-lingual

BGE-M3 a fost antrenat explicit pe 100+ limbi cu cross-lingual alignment. Asta înseamnă că vectorul pentru „concediere disciplinară” în română și „disciplinary dismissal” în engleză sunt aproape în spațiul vectorial. Cosine similarity între acești vectori este tipic peste 0.85.

Practic, asta vă permite:

Alternativele (a) traducerea queries la engleză înainte de retrieval, sau (b) doi indici separați cu alegere bazată pe language detection, sunt mai complicate, mai lente, și mai puțin precise.

Arhitectura pattern-ului

Query (RO sau EN)


Language detection (opțional, pentru output instruction)


BGE-M3 encoder → query vector (1024d)


Vector search pe index unic mixt RO + EN → top-50
+
BM25 search per limbă (două BM25 indici, fuzionate cu RRF)


Cross-encoder reranker multilingv (BGE-reranker-v2-m3)


Top-10 fragmente (mix RO + EN)


LLM cu prompt adaptive


Răspuns în limba utilizatorului + citări în limba originală a documentului

Pasul 1 — Indexarea mixtă

Fragmentele se indexează cu metadata lang care marchează limba originală:

class Fragment:
    text: str
    lang: str           # "ro" | "en"
    document_id: str
    document_title: str
    offset_start: int
    offset_end: int
    embedding: list[float]   # din BGE-M3, dimensiune 1024

Indexarea folosește același encoder (BGE-M3) pentru ambele limbi. Rezultatul: vectori comparabili cross-lingual.

Capcană: chunking-ul trebuie să respecte structura documentului în limba lui. Documentele juridice românești au o structură ierarhică diferită de un white paper englez. Folosiți chunking semantic per limbă.

Pasul 2 — BM25 per limbă

BM25 nu funcționează cross-lingual (este lexical, nu semantic). Soluția: două indici BM25 separați (unul RO, unul EN), interogați în paralel, fuzionați cu RRF împreună cu rezultatele dense.

def hybrid_search(query: str, lang_hint: str = None, top_k: int = 50):
    dense_results = vector_db.search(encoder.encode(query), k=top_k)
    bm25_ro = bm25_index_ro.search(query, k=top_k)
    bm25_en = bm25_index_en.search(query, k=top_k)
    fused = rrf_fuse([dense_results, bm25_ro, bm25_en], k=top_k)
    return fused

Pasul 3 — Reranking cross-lingual

BGE-reranker-v2-m3 este multilingv prin design. Acceptă pereche (query RO, document EN) și produce scor relevant. Nu cere traducere intermediară.

În practică, am observat că scorurile rerankers pe fragmente cross-lingual sunt ușor mai conservatoare (-0.05 până la -0.10) față de same-language. Dacă vreți să balansați acest bias, aplicați un boost de +0.05 pe scoruri cross-lingual.

Pasul 4 — Prompt adaptive

Prompt-ul către LLM trebuie să conțină explicit:

  1. Limba dorită de output (de obicei limba query-ului).
  2. Limba fragmentelor — pentru fiecare fragment în parte.
  3. Instrucțiunea de a nu „traduce” citările, ci de a păstra textul original.

Exemplu:

Sistemul: Asistent juridic. Răspunzi STRICT pe baza fragmentelor.

REGULI:
1. Răspunsul TĂU trebuie să fie în {output_language}.
2. Citările (verbatim_quote) trebuie păstrate ÎN LIMBA originală a fragmentului.
3. NU traduce citările.
4. Adaugă o notă scurtă care indică limba fragmentului dacă diferă de limba răspunsului.

Fragmente:
[1] (lang=ro, doc_id=DOC_RO_123): "Concedierea disciplinară conform articolului 248..."
[2] (lang=en, doc_id=DOC_EN_456): "Disciplinary dismissal under EU framework..."

Întrebare utilizator (limba: ro): {query}

Pasul 5 — Citation language match

Aceasta este cea mai subtilă regulă. Fără ea, LLM-urile au tendința să traducă citările pentru „consistență”. Asta strică citation grounding.

În validation gate, verificați:

def validate_citation_language(citation, fragment):
    if fragment.lang == "ro":
        return is_likely_romanian(citation.verbatim_quote)
    if fragment.lang == "en":
        return is_likely_english(citation.verbatim_quote)

Capcane practice

Diacritice inconsistente. Documente RO publice au amestec de diacritice corecte și aproximative. Normalizarea diacriticelor înainte de indexare îmbunătățește retrieval-ul. Dar pentru validare textuală, păstrați ambele variante (originalul + normalized) pentru match.

Nume proprii. Numele de instituții, persoane, companii apar adesea identic în RO și EN. BM25 cross-lingual prinde uneori match-uri pe nume proprii.

Traducerile oficiale. Pentru directive UE, există versiuni oficiale paralele RO și EN. Dacă indexați ambele, RAG-ul va prezenta ambele ca surse, ceea ce poate dubla informația. Soluția: dedup pe (regulation_id, article_number).

Vocabulary mismatch. „Procurement” în engleză vs „achiziții publice” în română — ambele se referă la același concept, dar BM25 nu conectează automat. Dense retrieval cu BGE-M3 face conexiunea.

Evaluare. Benchmark-ul vostru intern trebuie să conțină perechi (query RO, ground truth fragmente RO + EN) și (query EN, ground truth RO + EN).

Diagramă pattern complet

Document RO (chunking semantic structurat)

    BGE-M3 encoder → vector unique multilingv

Document EN (chunking adaptat)

Query (RO sau EN)
  → Language detect (output instruction)
  → BGE-M3 → dense top-50 cross-lingual
  → BM25 RO + BM25 EN (per limbă)
  → RRF fusion
  → BGE-reranker-v2-m3 (cross-encoder, multilingv)
  → Top-10 (mix RO + EN)
  → LLM cu prompt adaptive
  → Validation: citate în limba originală a fragmentului
  → Răspuns + citări active cu link la fragment

Concluzie operațională

RAG multilingv RO + EN nu este o complicație, este o cerință standard pentru corpusuri reale din România. Pattern-ul cu BGE-M3 + BM25 per limbă + cross-encoder rerank + prompt adaptive elimină majoritatea problemelor cross-lingual fără a impune dublă infrastructură.

Pentru clienții CAI Technology cu corpus mixt, acest pattern este implementarea recomandată.

Articole conexe

Surse externe

Următorul pas

Pentru o evaluare a corpusului propriu cu pattern-ul multilingv RO + EN, putem rula un POC pe 1000 documente mixte și benchmark de calitate în 2 săptămâni.

Începem cu o conversație de 30 de minute.

Audit AI-readiness gratuit pentru companii peste 50 angajați. Răspundem în 24 de ore.