Norsk RAG: BGE-M3 gir bedre gjenfinning enn engelske embedding-modeller

Når RAG over norske dokumenter returnerer feil avsnitt og gir tynne svar, ligger feilen i ni av ti tilfeller i embedding-modellen, ikke i språkmodellen bakerst. En stor og dyr LLM kan ikke svare godt på feil kontekst.

Relevante avsnitt havner ikke øverst

De fleste embedding-modeller er trent tungt på engelsk og fanger dårlig betydningen i norsk tekst. Et avsnitt som svarer direkte på spørsmålet kan få lavere likhet enn et irrelevant avsnitt som tilfeldigvis deler noen ord med det. Da får språkmodellen feil kontekst, og svaret blir dårlig uansett hvor stor LLM-en er.

Det er lett å sjekke. Still et konkret spørsmål mot en norsk dokumentsamling og les de fem øverste treffene. Ligger riktig avsnitt på plass ni, er feilen i gjenfinningen.

BGE-M3 gir dense og sparse fra samme modell

Diagram som viser BGE-M3 embedding-modell som produserer både dense og sparse representasjon fra samme modell, kombinert i hybrid gjenfinning

BGE-M3 er en flerspråklig embedding-modell som håndterer norsk godt. Den lager både dense og sparse representasjon fra samme modell. Dense fanger betydningen. Sparse fanger eksakte termer som koder, egennavn og forkortelser, som ellers drukner i ren vektorlikhet. Norsk fagtekst har mange produktnavn og interne begreper, og der gjør sparse-delen stor forskjell.

from FlagEmbedding import BGEM3FlagModel

model = BGEM3FlagModel("BAAI/bge-m3", use_fp16=True)

docs = ["Kontrollenheten tilbakestilles ved lang trykk på knappen.",
"Filteret byttes hver tredje måned."]
out = model.encode(docs, return_dense=True, return_sparse=True)

dense = out["dense_vecs"] # semantisk likhet
sparse = out["lexical_weights"] # eksakte termer
Del dokumentene etter strukturFor store chunks blander det relevante innholdet med støy. For små chunks skiller setningen fra konteksten den trenger. Del etter dokumentets egen struktur: avsnitt, overskrifter og naturlige grenser. Ikke del midt i en tabell eller en prosedyre.

Skjematisk RAG-pipeline med evalueringssløyfe: spørsmål gjennom gjenfinning mot norsk dokumentindeks, topp-k treff måles mot fasit med recall@k

chunk_size = 512 # tokens, ikke tegn
overlap = 64 # behold kontekst over grensene
# del på avsnitt først, fall tilbake på lengde
Evaluer på egne norske dokumenterEngelske benchmarks sier ingenting om hvordan modellen treffer på din terminologi. Lag et lite sett med reelle spørsmål og kjente fasit-avsnitt, og mål gjenfinningen direkte.

# enkel recall@k på eget sett
hits = 0
for q, gold_id in eval_set:
top = retrieve(q, k=5)
if gold_id in top:
hits += 1
print("recall@5:", hits / len(eval_set))
Kjør samme sett med en engelsk modell og med BGE-M3. Forskjellen i recall@5 er som regel tydelig, og tallet gjelder dine egne dokumenter. Mål dette før du bruker penger på en større LLM.