Een vector-index onderhouden: embeddings opslaan, bijwerken en verwijderen

Gepubliceerd door LLMNet API Engineering • 950 woorden • Leestijd: ca. 6 minuten

Het effectief inrichten en onderhouden van een vector-index is de ruggengraat van elke robuuste Retrieval-Augmented Generation (RAG) pipeline. Waar het genereren van een initiële set embeddings vaak rechttoe rechtaan is, ontstaat de echte complexiteit in het operationele beheer: hoe handel je documentupdates af, hoe houd je de index synchroon met een relationele database, en hoe voorkom je dat verouderde semantische data irrelevante antwoorden genereert?

Architectuur-tip: Behandel de vector-index nooit als je primaire databron. Sla de brondocumenten en metadata altijd op in een transactionele database (zoals PostgreSQL), en gebruik de vector-database uitsluitend als geoptimaliseerde zoekindex.

1. Fundamenten van vector-opslag en metadata

Elk document in een RAG-architectuur wordt opgeknipt in kleinere tekstblokken (chunks) en omgezet naar numerieke vectoren met behulp van een embedding-model. Naast de vector zelf (bijvoorbeeld een array van 1536 dimensies) is de opslag van gekoppelde metadata cruciaal voor filtering en herleidbaarheid.

Bij het ontwerpen van je opslaglaag moet je rekening houden met:

2. Incrementele updates bij nieuwe documenten

Wanneer een gebruiker een nieuw document toevoegt of een bestaand document wijzigt, wil je niet de hele index opnieuw opbouwen. Dit vraagt om een incrementele update-strategie. Om te bepalen of een document gewijzigd is, vergelijk je de inhoudshash alvorens de API van het embedding-model aan te roepen.

Hieronder staat pseudocode die demonstreert hoe je gecontroleerd nieuwe of gewijzigde documenten verwerkt en toevoegt aan de index:

// Pseudocode: Incrementele update van de vector-index

Functie VerwerkDocumentWijziging(document_id, nieuwe_tekst, metadata):
    nieuwe_hash = BerekenSHA256(nieuwe_tekst)
    bestaande_metadata = Database.HaalMetadataOp(document_id)

    Als bestaande_metadata bestaat EN bestaande_metadata.hash == nieuwe_hash:
        Print("Geen wijziging gedetecteerd. Sla embedding over.")
        Retourneer Succes

    // Opschonen van oude chunks indien het een update betreft
    Als bestaande_metadata bestaat:
        VerwijderBestaandeVectorChunks(document_id)

    // Opsplitsen in hanteerbare chunks
    chunks = SplitsInChunks(nieuwe_tekst, max_tokens=500, overlap=50)
    nieuwe_vectoren = []

    Voor elke index, chunk inchunks:
        chunk_id = GenereerUniekeID(document_id, index)
        
        // Veilige API-aanroep zonder hardcoded sleutels (omgeving variabelen)
        vector = RoepEmbeddingAPI(chunk) 
        
        chunk_metadata = {
            "document_id": document_id,
            "chunk_index": index,
            "hash": nieuwe_hash,
            "tekst": chunk,
            ...metadata
        }
        
        nieuwe_vectoren.VoegToe({
            "id": chunk_id,
            "values": vector,
            "metadata": chunk_metadata
        })

    // Batch-upsert naar de vector-database
    VectorDB.Upsert(nieuwe_vectoren)
    Database.SlaMetadataOp(document_id, nieuwe_hash)
    Print("Document succesvol geïndexeerd of bijgewerkt.")

3. Opschonen en verwijderen van verouderde data

Wanneer documenten worden verwijderd uit het CMS of de brondatabase, blijven de bijbehorende vectoren vaak achter in de vector-index. Dit leidt tot 'hallucinaties' of verouderde citaties in gegenereerde antwoorden van het LLM.

Om dit te voorkomen implementeer je een van de volgende twee patronen:

4. Versiebeheer van embedding-modellen

Een vaak onderschat risico in productie is het upgraden van het embedding-model (bijv. van text-embedding-ada-002 naar text-embedding-3-small). Vectoren gegenereerd door verschillende modellen bevinden zich in andere wiskundige vectorruimten en kunnen niet met elkaar worden vergeleken.

Een robuust versiebeheerschema vereist:

  1. Naamgeving van indexen: Koppel het modelformaat direct aan de indexnaam (bijv. kb_docs_v3_embedding_3_small).
  2. Parallelle migratie: Bouw een schaduwindex op in de achtergrond met het nieuwe model terwijl de oude index operationeel blijft.
  3. Switchen: Schakel de routeringslaag pas om wanneer de schaduwindex 100% is gevuld en is gevalideerd op retrieval-kwaliteit.

Meer weten over geavanceerde architecturen? Bekijk onze uitgebreide documentatie en gidsen op het LLMNet Leren portaal voor diepgaande tutorials over RAG-optimalisatie en vector-databasen.