Embedding är en lista med tal. Det är allt. Du tar en text, kör den genom en modell som BAAI/bge-m3 eller text-embedding-3-large, och ut kommer en vektor på säg 1024 dimensioner. Den vektorn säger ungefär "den här texten ligger nära de här andra texterna i mening". Det är inte magi. Det är geometri. När jag förklarar det här för folk som beställer en RAG brukar de bli besvikna, för de hade föreställt sig något mer mystiskt. Det är det inte.
Jag tycker att RAG har blivit ett av de mest missförstådda begreppen i hela AI-svängen just nu. Folk pratar om det som en produkt man köper, eller en lösning man slår på. Det är det inte heller. Det är en arkitektur, och som alla arkitekturer består den av en massa småbeslut som tillsammans avgör om den fungerar eller inte. När den inte fungerar är det oftast inte själva språkmodellen som är problemet. Det är allt det andra runt omkring.
Vad RAG egentligen är, utan glansen
Retrieval Augmented Generation betyder att du letar upp relevanta textbitar i ett dokumentarkiv innan du ställer frågan till en språkmodell, och sen klistrar in de bitarna i prompten. Det är det. En sökmotor framför en LLM. Skillnaden mot en vanlig sökmotor är att du söker semantiskt istället för på exakta ord, och att resultatet inte presenteras som länkar utan blir råmaterial åt modellen som skriver ett svar.
När du embedar en text omvandlar du den till siffror i ett högdimensionellt rum. Texter som handlar om liknande saker hamnar nära varandra. När en användare ställer en fråga embedar du frågan på samma sätt, och letar upp de textbitar vars vektorer ligger närmast frågans vektor. Det är cosine similarity, eller dot product, beroende på hur du normaliserar. Inget mer avancerat än så på den nivån. Pgvector i Postgres klarar det. Qdrant, Weaviate, Pinecone, alla gör i grunden samma sak.
Det jag är trött på är att folk pratar om vektor-databaser som om det vore själva poängen. Det är det inte. Det är ett enkelt verktyg. Det viktiga händer innan datat kommer dit, och efter att det kommit ut.
Chunking är där hela kvaliteten avgörs
Säg att du har en samling PDF:er. Avtal, manualer, intern dokumentation, ett par tusen sidor totalt. Du ska bygga en RAG som kan svara på frågor om det här. Första steget är att dela upp texten i mindre bitar, eftersom du inte kan embeda hela dokument och få vettiga resultat. En vektor som representerar 80 sidor är värdelös, för den blir ett genomsnitt av allt och pekar ingenstans specifikt.
Då börjar problemet. Hur stora ska bitarna vara? 500 tecken? 1500? Ska du dela på meningar, på stycken, på rubriknivåer? Vad gör du när en tabell går över en chunk-gräns? Vad gör du med fotnoter? Vad gör du med ett avtal där paragraf 12 hänvisar till definitionen i paragraf 3? Om du splittar dem hamnar de i två olika vektorer som aldrig ses tillsammans, och då hittar inte sökmotorn ihop dem när någon frågar.
Min teori är att 80 procent av RAG-kvaliteten sitter i chunking. Inte i embedding-modellen, inte i vektor-databasen, inte i prompten till slutet. I hur du delar upp texten. Och det här är trist, för chunking är inte sexigt. Det är att sitta och stirra på dokumentstrukturer, testa olika strategier, läsa hundra exempel och se var det går fel.
Vi brukar starta med en hybrid. Strukturmedveten splittning på rubriker och stycken där det är möjligt, fallback till fönsterbaserad splittning med överlappning där dokumenten är ostrukturerade. Sen lägger vi metadata på varje chunk: vilket dokument den kommer från, vilket avsnitt, vilken sida, vilken paragraf. Den metadatan blir helt avgörande senare. Mer om det strax.
Top-1 är inte svaret
När du gör en vektor-sökning får du tillbaka en sorterad lista med träffar. Den första träffen är den vars vektor ligger närmast frågan. Naiva implementationer plockar bara den och skickar in i prompten. Det går sönder ungefär lika ofta som det funkar.
Problemet är att vektor-similarity är trubbig. Två texter kan ligga nära i embedding-rummet utan att den ena faktiskt svarar på den andra. En text som nämner samma nyckelord men i fel sammanhang kan rankas högt. En text som svarar perfekt men med ovanliga formuleringar kan rankas lågt. Embeddingmodellen är inte tränad på just ditt domän-språk, och det märks.
Det är här reranking kommer in. Du tar de tio eller tjugo översta träffarna från vektor-sökningen och kör dem genom en mer kapabel modell som faktiskt läser frågan och varje kandidat och bedömer relevans. Cohere har en bra rerank-modell. BAAI har en open-source. Du kan också göra det med en mindre LLM som Llama 3.1 8B eller Qwen2.5 om du vill köra lokalt. Det kostar lite extra latency, kanske 200-400 millisekunder, men det förändrar kvaliteten dramatiskt.
Jag fattar fortfarande inte varför fler inte gör det här från start. Kanske för att det inte syns i de första demos man bygger. Med tio dokument och fem frågor verkar allt funka. Sen lägger du till tusen dokument och plötsligt hittar den fel saker, och då börjar folk skylla på embeddingmodellen.
Källor är inte en feature, det är fundamentet
När RAG-systemet skickar tillbaka ett svar måste det vara spårbart till de chunks det baseras på. Vilken paragraf i vilket avtal? Vilken sida i vilken manual? Utan det är svaret bara en gissning som råkar låta säker. Och språkmodeller är väldigt bra på att låta säkra även när de har fel.
Det är därför metadatan från chunking-steget är så avgörande. När en chunk plockas upp och stoppas in i prompten ska modellen instrueras att referera till källorna, och frontend ska visa dem klickbart för användaren. Hela poängen med RAG, åtminstone i en B2B-kontext, är att svaret ska gå att verifiera. Annars är vinsten över en ren LLM marginal.
Vi bygger oftast så att varje chunk har ett ID, och i prompten ber vi modellen citera ID:n när den svarar. Sen plockar applikationen ut citationsmarkörerna och slår upp källan ur en tabell. Postgres med jsonb-fält fungerar utmärkt för det. Du behöver inte ens en separat metadata-tjänst. Allt kan ligga i samma rad som vektorn i pgvector.
När en användare ser svaret och kan klicka sig till exakt det stycke i avtalet det handlar om, då har du byggt något användbart. När de bara ser en textmassa utan källor har du byggt en chattrobot med extra steg, och förtroendet rasar första gången den ljuger.
Varför demos lurar dig
En pilot-RAG på hundra dokument fungerar nästan alltid. Du laddar in PDF:erna, kör en standard-chunker, embedar med en hyfsad modell, lägger i pgvector, kopplar mot Anthropic Claude eller OpenAI gpt-5.4, bygger ett enkelt frontend. Resultatet blir imponerande. Du visar det på ett möte. Folk är glada. Beslut tas.
Sen ska det skalas till tiotusen dokument, eller hundratusen, och då börjar saker krackelera. Inte plötsligt, utan gradvis. Den ena dagen märker du att en viss typ av frågor får dåliga svar. Du tittar närmare och inser att chunking-strategin inte tål den nya typen av dokument som tillkom i datasetet. Du fixar det. Nästa vecka kommer en användare och säger att systemet hittade fel paragraf, fast den såg rätt ut. Du gräver och inser att två avtal har nästan identiskt språk men gäller olika tidsperioder, och systemet kan inte skilja dem åt utan tids-metadata.
Sen kommer någon från juridiska som vill att gamla versioner av dokument inte ska komma med i sökningen, bara aktuella. Då behöver du versionshantering. Sen vill någon att vissa dokument bara ska vara sökbara för vissa användargrupper. Då behöver du access control på chunk-nivå. Sen vill någon att svaret ska kunna kombinera information från flera dokument, vilket fungerar tills frågan kräver att modellen drar slutsatser över tre olika källor, och då hittar reranking-steget inte alla tre eftersom de är formulerade olika.
Det är så pilot-RAG blir produktion-RAG. Inte med en stor lansering utan med ett halvår av småjusteringar där varje fix lär dig något om datat du inte visste innan.
Det som ofta saknas
Det vi ofta ser i fältet är att RAG-system byggs utan utvärderingsdata. Folk vet inte hur de ska mäta om systemet blir bättre eller sämre när de ändrar något. Då blir varje förändring en magkänsla. Du byter embeddingmodell från text-embedding-3-small till bge-m3 och tycker att det "känns bättre". Det är inte ingenjörskonst, det är skrock.
Det första vi bygger på en RAG-implementation är en utvärderingsuppsättning. 50 till 200 frågor med korrekta svar och korrekta källor, helst formulerade av folk som faktiskt kan domänen. Sen kan du köra hela RAG-pipelinen mot den uppsättningen och få ut siffror: hur ofta hittar systemet rätt källa? Hur ofta hamnar rätt svar i top-3? Hur ofta är det genererade svaret faktiskt korrekt? När du har de siffrorna kan du göra ändringar och se om de hjälper eller stjälper.
LangSmith och Langfuse kan hjälpa till med spårningen. Ragas är ett bibliotek som ger dig några färdiga mått. Det räcker inte hela vägen, men det är en bättre start än att gissa. Det här är en av få saker där jag tycker att de färdiga verktygen är värda att titta på innan man bygger eget.
Hur vi tänker när vi bygger
När vi får in ett RAG-projekt börjar vi nästan alltid med att gå igenom datat först. Inte arkitekturen, inte modellvalet, inte vilken vektor-databas som ska användas. Datat. Vilka format är dokumenten i? Hur är de strukturerade? Är de versionshanterade? Finns det dubbletter? Hur ser kvaliteten ut? Det är tråkigt arbete och det går inte att hoppa över.
Sen tänker vi igenom vilka frågor systemet ska kunna svara på. Är det punkt-i-text-frågor, där svaret står ordagrant någonstans? Är det syntes-frågor, där svaret kräver att information från flera källor vägs ihop? Är det jämförande frågor? Olika frågetyper kräver olika strategier. En ren RAG fungerar för det första. Det andra kräver agent-flöden där modellen iterativt söker och resonerar. Det är inte samma system.
Modellval kommer sent. Claude, gpt-5.4, eller en lokal Llama 3.1 70B via Ollama? Det beror på datakänslighet, latencykrav, budget, och hur svår syntesen är. För avtals-RAG där datat är känsligt och svaren behöver vara välformulerade kör vi ofta Claude. För enklare uppslag mot publik dokumentation räcker det med en mindre modell. För miljöer där datat absolut inte får lämna kundens nät blir det Llama eller Qwen2.5 på egen hårdvara. Det är inget religiöst val. Det är ett kostnad-mot-kvalitet-beslut.
Hela det här resonemanget, att RAG är en arkitektur och inte en produkt, är det som gör skillnaden mellan en demo som imponerar i tio minuter och ett system som faktiskt används om sex månader. Det är inte komplicerat. Det är bara många små saker som måste göras rätt, och alla små saker tar tid.
På Kapaciti gör vi mycket av det här. Hör av dig om du sitter och funderar på en RAG och inte vet var du ska börja.