- Je bewaart bij iedere passage het document, de versie en de oorspronkelijke tekenposities.
- Je meet dekking en duplicatie bij verschillende chunkgroottes en overlap.
Probeer ook echte tekstvectoren in het embedding-lab.
Een antwoord citeert “Lamp aan”, maar de handleiding is inmiddels veranderd naar “Lamp uit”. Het document-ID bleef gelijk. Zonder bronversie kun je niet meer vaststellen bij welke tekst het oude citaat hoorde.
Retrieval-augmented generation (RAG) haalt informatie op en geeft die als context aan een antwoordmodel. We bouwen eerst de zoekkant: bronnen vastleggen, passages maken en hun herkomst bewaren. De oorspronkelijke RAG-publicatie koppelde een dense retriever aan een generatief model; onze route onderzoekt de onderdelen afzonderlijk.
1. Leg de exacte bron vast
Een snapshot bewaart id, title en de oorspronkelijke text. Bereken revision als SHA-256 over de UTF-8-bytes van die tekst. Ook witruimte, hoofdletters en regeleinden horen bij de versie waarnaar een citaat verwijst.
source = ' A B\nC D E F G H '
raw = [dict(id='d',title='Demo',
text=source)]
doc = document_snapshots(raw)[0]
import hashlib
digest = hashlib.sha256(
source.encode('utf-8')).hexdigest()
print(doc['revision'] == digest) # True
print(doc['text'] == source) # True
print(len(doc['revision'])) # 64
changed = document_snapshots([
{**raw[0],'text':source+'!'}])[0]
print(changed['revision'] ==
doc['revision']) # False
Maak document_snapshots met nieuwe dictionaries. Accepteer 1–32 documenten, unieke begrensde IDs, een niet-lege titel en maximaal 20000 Python-tekens brontekst. Normaliseer de tekst niet voordat je de hash of offsets maakt.
Een versiehash is een vingerafdruk van bytes. Hij bewijst geen waarheid, auteur of toegangsrecht. Verandert een bron, dan moet je afgeleide passages en vectoren opnieuw op de juiste versie afstemmen.
012. Maak woord- en tekenposities zichtbaar
Onze eerste chunker telt niet-witruimtereeksen met regex \S+. Dat zijn oefenwoorden en geen modeltokens. Met re.finditer krijg je behalve de woorden ook hun exacte tekenposities.
import re
words = list(re.finditer(r'\S+',source))
print(words[0].span()) # (2, 3)
print(source[2:3]) # A
Het eerste woord heeft woordindex nul, maar begint op tekenindex twee door de voorloopspaties. Een einde is exclusief: source[2:3] neemt teken twee mee en stopt vóór teken drie. De tekst van een passage is altijd dezelfde uitsnede uit de oorspronkelijke bron.
Neem venster W=4 en overlap O=1. Iedere nieuwe passage begint W−O=3 woorden verder: intervallen [0,4), [3,7) en [6,8). Stop zodra het laatste woord is opgenomen, zodat je geen extra staart met alleen overlap maakt.
chunks = word_chunks(doc,4,1)
for chunk in chunks:
print(chunk['id'],
chunk['start'],chunk['end'])
# d:0 2 10
# d:3 9 16
# d:6 15 18
Maak word_chunks met IDs document-ID:woordstart. Bewaar daarnaast document_id, revision, woordgrenzen, tekengrenzen en de exacte tekst. In de eerste passage blijft de dubbele spatie en interne newline behouden; witruimte buiten de gekozen woorden valt buiten de passage.
De grenzen zijn Python-tekenindices. Een JavaScript-client moet Unicode-posities expliciet omzetten. Zins- en paragraafgrenzen kunnen later nuttiger zijn, maar ook die keuze moet je op echte zoekvragen beoordelen.
Vensters tellen hier woorden, geen modeltokens. Kies een passage om haar exacte bronbereik te zien.
De lamp brandt groen na reset.
Bron: eigen-lamp · tekenbereik [0, 30) in deze vaste tekst.
3. Meet dekking en extra opslag afzonderlijk
De drie passages bewaren 4+4+2=10 woordvoorkomens. Ze dekken acht unieke oorspronkelijke posities. Noem het oorspronkelijke aantal N, het aantal unieke gedekte posities U en de opgeslagen voorkomens S.
Hier is coverage 8/8=1 en de duplicatiefactor 10/8=1.25. Meer overlap kan samenhang bewaren, maar kost opslag en embeddingwerk. Het garandeert geen betere relevante passages.
r = chunk_coverage(doc,chunks)
print(r['word_occurrences']) # 10
print(r['covered_words']) # 8
print(r['duplication_factor']) # 1.25
empty = chunk_coverage(doc,[])
print(empty['coverage'],
empty['duplication_factor'])
# 0.0 None
Maak chunk_coverage als onafhankelijke audit van versie, IDs, offsets en tekst. Rapporteer ook ontbrekende woordindices. Zonder chunks is coverage nul en de duplicatiefactor None, omdat er geen gedekte woorden zijn.
03Wat neem je mee?
- Versie en offsets verbinden een passage met concrete brontekst.
- Woordindices, tekenindices en modeltokens zijn verschillende eenheden.
- Coverage meet dekking; duplicatie meet extra opgeslagen voorkomens.
Hierna zet je passages en vragen om in vergelijkbare vectoren.