RAG-arkitekturen: indeksering og uthenting
Kartlegg de to fasene i RAG: den offline-baserte indekseringsfasen, som deler opp, embedder og lagrer dokumenter, og den online-baserte uthentingsfasen, som finner relevant kontekst for hver spørring.
RAG-arkitekturen: indeksering og uthenting er en gratis leksjon i AI Engineering Academy på CoddyKit. Dette er leksjon 2 av 4. Du kan lese hele leksjonen gratis nedenfor – og deretter øve praktisk i nettleseren med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i AI Engineering Academy, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i AI Engineering Academy inneholder totalt 4 leksjoner.
RAG har to separate faser
Et RAG-system opererer i to grunnleggende forskjellige faser som kjøres på ulike tidspunkter. Den offline indekseringsfasen behandler dokumentene dine én gang (eller når de endres) og klargjør en søkbar indeks. Den online hente-fasen kjører i sanntid for hver brukerspørring. Det er viktig å forstå dette skillet når du skal utforme systemer som både er raske ved spørringer og enkle å vedlikeholde over tid.
Indekseringsfasen: Trinn én – last inn
Indekseringen starter med innlasting av dokumenter: lesing av råfiler fra kildesystemene dine. Dokumentene kan være PDF-er, Word-filer, HTML-sider, Markdown-filer, databas rader eller hvilken som helst tekstkilde. Hvert dokument lastes inn i minnet som ren tekst, samtidig som strukturen bevares så langt det er mulig. Biblioteker som pypdf, python-docx og unstructured håndterer det krevende arbeidet med formatspesifikk parsing.
from pypdf import PdfReader
def load_pdf(path):
reader = PdfReader(path)
pages = []
for i, page in enumerate(reader.pages):
text = page.extract_text()
pages.append({'text': text, 'page': i + 1, 'source': path})
return pages
docs = load_pdf('company_policy.pdf')
print(f'Loaded {len(docs)} pages')Indekseringsfasen: Trinn to – del opp
LLM-er har begrensede kontekstvinduer, og det er lite effektivt å hente hele dokumenter. Den innlastede teksten deles opp i mindre deler på omtrent 200–1000 tokens hver. God oppdeling bevarer den semantiske sammenhengen: En del bør uttrykke en komplett idé. En vanlig strategi bruker overlappende vinduer, slik at setninger nær grensene mellom delene forekommer i to deler og hindrer informasjonstap ved oppdelingen.
from langchain_text_splitters import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # characters per chunk
chunk_overlap=50, # overlap between chunks
separators=['\n\n', '\n', '. ', ' ']
)
for page in docs:
chunks = splitter.split_text(page['text'])
for chunk in chunks:
# Each chunk carries metadata from its source page
print(f'Chunk ({len(chunk)} chars): {chunk[:80]}...')Indekseringsfasen: Trinn tre – lag embedding
Hver tekstdel konverteres til en tett vektorembedding som representerer den semantiske betydningen numerisk. Du kaller en embedding-modell – for eksempel OpenAI sin text-embedding-3-small – for hver del og mottar en flyttallstabell med mange dimensjoner. Deler med lignende betydning gir vektorer som ligger nær hverandre i dette høydimensjonale rommet, og det er dette som muliggjør semantisk likhetssøk.
from openai import OpenAI
client = OpenAI()
def embed_chunks(chunks):
texts = [c['text'] for c in chunks]
response = client.embeddings.create(
model='text-embedding-3-small',
input=texts
)
for i, chunk in enumerate(chunks):
chunk['embedding'] = response.data[i].embedding
return chunks
# Batch up to 2048 texts per API call
embedded = embed_chunks(all_chunks)Indekseringsfasen: Trinn fire – lagre
De embeddede delene lagres i en vektordatabase sammen med metadataene deres (kildefil, sidetall, seksjonstittel). Vektorlageret bygger en indeksstruktur (vanligvis HNSW) som muliggjør raskt tilnærmet nærmeste-nabo-søk. Denne indeksen lagres på disk, slik at den overlever omstarter. Indeksering skjer vanligvis én gang ved oppsett og trinnvis når nye dokumenter legges til.
import pinecone
pc = pinecone.Pinecone(api_key='YOUR_KEY')
index = pc.Index('rag-documents')
# Upsert vectors with metadata
vectors_to_upsert = [
(
chunk['id'],
chunk['embedding'],
{'text': chunk['text'], 'source': chunk['source'], 'page': chunk['page']}
)
for chunk in embedded_chunks
]
# Upsert in batches of 100
for i in range(0, len(vectors_to_upsert), 100):
index.upsert(vectors=vectors_to_upsert[i:i+100])
print('Indexing complete')Hentefasen: Embedding av spørringen
Når en bruker sender inn en spørring, starter den nettbaserte hentefasen. Det første trinnet er å lage en embedding av brukerens spørsmål ved hjelp av den samme embedding-modellen som ble brukt under indekseringen. Dette er avgjørende: Hvis du indekserte med text-embedding-3-small, må du også bruke text-embedding-3-small ved spørringer. Spørringsembeddingen er en vektor som koder den semantiske betydningen av det brukeren spør om.
def embed_query(question):
response = client.embeddings.create(
model='text-embedding-3-small', # MUST match indexing model
input=[question]
)
return response.data[0].embedding
user_question = 'What is our parental leave policy?'
query_vector = embed_query(user_question)
print(f'Query embedded: {len(query_vector)}-dim vector')Hentefasen: ANN-søk
Spørringsembeddingen sendes til vektorlageret, som utfører et tilnærmet nærmeste-nabo-søk (ANN) for å finne de K delene hvis embedding-er ligner mest på spørringsvektoren. Dette søket er svært raskt (vanligvis under 10 ms), fordi HNSW-indekser bytter bort litt treffsikkerhet mot enorme hastighetsgevinster sammenlignet med uttømmende søk. Du henter de K beste delene – vanligvis K=5 til K=20.
results = index.query(
vector=query_vector,
top_k=5,
include_metadata=True
)
print(f'Retrieved {len(results.matches)} chunks:')
for match in results.matches:
print(f' Score: {match.score:.3f} | Source: {match.metadata["source"]}')
print(f' Text: {match.metadata["text"][:100]}...')
print()Koble sammen de to fasene
Det viktigste poenget er at indeksering og henting er utformet for å fungere sammen. Embedding-modellen må være identisk i begge faser, fordi det matematiske rommet vektorene ligger i, er spesifikt for modellen. Hvis du bytter embedding-modell, må du indeksere alle dokumentene på nytt. Vektorlageret er bindeleddet: Det mottar vektorer under indekseringen og returnerer vektorer under hentingen. Dermed kobles fasene tidsmessig fra hverandre, samtidig som de holdes samordnet i vektorrommet.
Metadat filtrering under henting
Vektorsøk finner semantisk lignende deler, men noen ganger trenger du også å filtrere etter metadata. Du kan for eksempel bare hente deler fra dokumenter som ble lastet opp i 2025, eller bare fra HR-avdelingen. Vektorlager støtter forhåndsfiltrering eller etterfiltrering på metadatafelter. Forhåndsfiltrering (støttet av Pinecone og Qdrant) bruker filteret før ANN-søket, noe som er raskere og mer treffsikkert enn etterfiltrering av de K beste resultatene.
# Retrieve only from HR department documents
results = index.query(
vector=query_vector,
top_k=5,
filter={'department': {'$eq': 'HR'}},
include_metadata=True
)
# Or filter by date range
results = index.query(
vector=query_vector,
top_k=5,
filter={
'upload_year': {'$gte': 2024},
'doc_type': {'$eq': 'policy'}
},
include_metadata=True
)Trinnvis indeksering ved oppdateringer
I produksjon endres dokumentsamlingen over tid. En effektiv indekseringsarkitektur støtter trinnvise oppdateringer: Når et dokument redigeres, sletter du de eksisterende vektorene etter ID og oppdaterer med de nye. Når dokumenter slettes, fjerner du vektorene deres. Gi hver del en deterministisk ID basert på kildebanen til dokumentet og delens posisjon, slik at du alltid kan finne og oppdatere de riktige vektorene uten å indeksere alt på nytt.
import hashlib
def make_chunk_id(source_path, chunk_index):
# Deterministic, stable ID for each chunk
key = f'{source_path}::chunk_{chunk_index}'
return hashlib.md5(key.encode()).hexdigest()
def update_document(source_path, index):
# Delete old vectors for this document
index.delete(filter={'source': source_path})
# Re-index the updated document
new_chunks = load_and_chunk(source_path)
new_embedded = embed_chunks(new_chunks)
index.upsert(vectors=new_embedded)
print(f'Updated {source_path}: {len(new_chunks)} chunks')Hele RAG-pipelinen i oversikt
Den komplette RAG-arkitekturen ser slik ut: Offline: Dokumenter → Laster → Oppdeler → Embedding-modell → Vektorlager. Online: Brukerspørring → Embedding-modell → Vektorlager (ANN-søk) → K beste deler → Prompt-sammensetting → LLM → Svar. Offline-pipelinen kjører én gang per dokumentoppdatering. Online-pipelinen kjører på millisekunder for hver brukerspørring, og LLM-en ser bare den relevante konteksten, ikke hele dokumentsamlingen.
Hurtigsjekk
Test forståelsen din av konsepter innen KI-teknikk fra denne leksjonen.
Oppsummering av leksjonen
I denne leksjonen lærte du: den offline indekseringsfasen, som består av trinnene last inn, del opp, lag embedding og lagre, og som kjøres én gang per dokument, den online hentefasen, som lager embedding av spørringen, utfører ANN-søk og returnerer de K beste delene på millisekunder, samt strategier for trinnvis indeksering som holder vektorlageret oppdatert når dokumentene endres. Neste gang ser vi på hvordan du lager effektive utvidede prompter som bruker hentet kontekst på en god måte.
Lær deg Python med en AI-veileder – gratis
Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.
- Kurs
- 30
- Leksjoner
- 120
Ofte stilte spørsmål
Er leksjonen «RAG-arkitekturen: indeksering og uthenting» gratis?
Ja – hele teksten i «RAG-arkitekturen: indeksering og uthenting» er gratis å lese her på nettet. For å øve interaktivt med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt, og for å låse opp resten av AI Engineering Academy-kurset, kan du oppgradere til CoddyKit PRO. Kurset i AI Engineering Academy inneholder totalt 4 leksjoner.
Hva lærer jeg i «RAG-arkitekturen: indeksering og uthenting»?
Kartlegg de to fasene i RAG: den offline-baserte indekseringsfasen, som deler opp, embedder og lagrer dokumenter, og den online-baserte uthentingsfasen, som finner relevant kontekst for hver spørring. Du øver på AI Engineering Academy med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.
Trenger jeg erfaring for å begynne med AI Engineering Academy?
Ingen tidligere erfaring er nødvendig. AI Engineering Academy på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 2 av 4.
Hvor lang tid tar leksjonen «RAG-arkitekturen: indeksering og uthenting»?
De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.
Kan jeg skrive og kjøre kode i denne AI Engineering Academy-leksjonen?
Ja. Alle AI Engineering Academy-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.
Alle leksjonene i dette kurset
- Problemet RAG løser
- RAG-arkitekturen: indeksering og uthenting
- Utforme den utvidede prompten
- RAG versus finjustering: når bør De bruke hva?