Ga naar inhoud

Sprint 2.1 — Database Migratie: ChromaDB → Weaviate

Versie: 1.0 | Datum: 15 maart 2026 | Auteur: Claude (projectleider) | Akkoord: Niels (architect)


Samenvatting

Migratie van ChromaDB (embedded, in-process) naar Weaviate (standalone, Docker) als primaire vector store voor het Buurts Ecosysteem. Doel: schaalbare basis voor meerdere Kenniswerkplaatsen (KWP's) vóór pilotstart.

Kernbeslissing: Eén database (Weaviate), geen dual-DB. ArangoDB wordt niet geïntroduceerd — de BNS Causal Engine (sidecar) krijgt eigen lichtgewicht opslag in BNS Sprint 0.


Motivatie

Waarom nu migreren?

  1. Schaalbaarheid vóór pilot. Na succesvolle pilot worden nieuwe KWP's (GGZ, LVB, Jeugd) snel ingericht. ChromaDB is embedded/single-process — geen concurrent writes, geen multi-tenancy.
  2. Operationele scheiding. Weaviate draait als standalone service: meerdere FastAPI workers kunnen er tegelijk tegenaan. Essentieel bij meerdere KWP's.
  3. Zone-isolatie versterken. Weaviate's native multi-tenancy biedt betere RED/YELLOW/GREEN isolatie dan fysiek gescheiden ChromaDB directories.
  4. Interactie-opslag. Gebruikersinteracties (queries + responses) worden een aparte collection in dezelfde Weaviate-instantie. Geen tweede database nodig.

Waarom géén ArangoDB?

  • BNS Causal Engine is een sidecar die gescheiden draait (Phantom Mode) totdat wiskundige betrouwbaarheid bewezen is.
  • pgmpy werkt met in-memory NetworkX DAGs + CPT-tabellen — geen graph database nodig.
  • ArangoDB's vector search is jong en scoort lager op recall dan gespecialiseerde vector stores.
  • Twee databases = dubbele operationele overhead voor een pilot-team.

Waarom gién embedding model switch?

Het huidige model paraphrase-multilingual-MiniLM-L12-v2 is bewust gekozen voor Nederlandse tekst. Grok's suggestie all-MiniLM-L6-v2 (384 dim) is Engels-geoptimaliseerd — een stap achteruit voor een Nederlandstalige zorgtoepassing.


Architectuurontwerp

Huidige architectuur (ChromaDB)

FastAPI → HubOrchestrator → ScoutAgent → VectorStore (ChromaDB in-process)
                                           └─ ZonedVectorStore
                                                ├─ buurts_red    (ChromaDB dir)
                                                ├─ buurts_yellow (ChromaDB dir)
                                                └─ buurts_green  (ChromaDB dir)

Doelarchitectuur (Weaviate)

FastAPI → HubOrchestrator → ScoutAgent → VectorStore (Weaviate HTTP client)
                                           └─ ZonedVectorStore
                                                ├─ BuurtsRed     (Weaviate collection)
                                                ├─ BuurtsYellow  (Weaviate collection)
                                                └─ BuurtsGreen   (Weaviate collection)
                                           └─ InteractionStore
                                                └─ BuurtsInteraction (Weaviate collection)

Docker: weaviate:1.27.6 (poort 8080)

Ontwerpprincipe: Interface blijft, implementatie wisselt

De ZonedVectorStore en VectorStore klassen in rag/vector_store.py behouden hun publieke interface:

  • add_chunk(chunk: DocumentChunk) → str
  • add_chunks(chunks: List[DocumentChunk]) → List[str]
  • query(request: RetrievalRequest) → RetrievalResponse
  • count(zone?) → int
  • count_by_zone() → Dict[str, int]
  • reset(zone?) → None

Alles wat tegen deze interface praat (ScoutAgent, SharePointIngestPipeline, tests) hoeft niet te veranderen. Alleen de interne implementatie schakelt van ChromaDB naar Weaviate.


Fasering

Fase 1: Infra + Weaviate Docker (dag 1)

Doel: Weaviate draait lokaal, schema's aangemaakt.

Taken:

  • docker-compose.yml uitbreiden met Weaviate service (1.27.6)
  • weaviate-client>=4.9.0 toevoegen aan requirements.txt
  • Config uitbreiden: WEAVIATE_HOST, WEAVIATE_PORT, VECTOR_BACKEND ("chromadb" | "weaviate")
  • Health check endpoint: GET /health/weaviate
  • 4 Weaviate collections aanmaken: BuurtsRed, BuurtsYellow, BuurtsGreen, BuurtsInteraction
  • Schema per collection met UDS V2 properties (domain_id, knowledge_domain, zone, ldf_level, etc.)

Oplevert: docker compose up weaviate werkt, collections bestaan.

Fase 2: WeaviateVectorStore implementatie (dag 2-3)

Doel: Drop-in vervanging voor ChromaDB backend achter bestaande interface.

Taken:

  • Nieuwe klasse WeaviateZonedVectorStore in rag/vector_store.py (of nieuw bestand rag/weaviate_store.py)
  • Implementeert exact dezelfde interface als ZonedVectorStore
  • Embedding: paraphrase-multilingual-MiniLM-L12-v2 behouden (Weaviate none vectorizer + client-side embeddings via sentence-transformers)
  • _serialize / _deserialize aanpassen voor Weaviate property-formaat
  • Factory functie: get_vector_store(backend: str) → retourneert ChromaDB of Weaviate variant
  • InteractionStore als aparte klasse (hergebruik Copilot PR #20 als basis)
  • Config: VECTOR_BACKEND switch in config.py

Oplevert: ZonedVectorStore interface werkt met Weaviate backend.

Fase 3: Integratie + migratiescript (dag 4)

Doel: Bestaande pipeline schakelt over naar Weaviate.

Taken:

  • agents/scout.py → gebruikt get_vector_store() factory i.p.v. directe VectorStore import
  • sharepoint/ingest_pipeline.py → idem
  • main.py → DI via factory
  • Migratiescript scripts/migrate_chromadb_to_weaviate.py: leest alle ChromaDB collections, schrijft naar Weaviate
  • Backwards-compat: VECTOR_BACKEND=chromadb blijft werken (geen breaking change)

Oplevert: volledige pipeline draait op Weaviate met één config-switch.

Fase 4: Tests + CI (dag 5)

Doel: Alle tests groen, CI aangepast.

Taken:

  • Nieuwe testsuite tests/test_sprint_2_1.py voor Weaviate-specifieke functionaliteit
  • Bestaande tests draaien ongewijzigd (interface is gelijk) — ChromaDB EphemeralClient als test-backend
  • Optionele integratietests met Weaviate Docker (CI: services: weaviate)
  • Bandit scan op nieuwe code
  • Ruff lint check
  • PR #20 branch opruimen (functionaliteit is geïntegreerd)

Oplevert: 321+ tests groen, CI pipeline aangepast.


Impact-analyse

Bestanden die veranderen (code)

Bestand Wijziging Risico
rag/vector_store.py Nieuwe WeaviateZonedVectorStore klasse + factory Hoog — kern van de migratie
config.py Weaviate settings toevoegen Laag
docker-compose.yml Weaviate service toevoegen Laag
requirements.txt weaviate-client>=4.9.0 toevoegen Laag
agents/scout.py Factory i.p.v. directe import Medium — type hint aanpassen
sharepoint/ingest_pipeline.py Factory i.p.v. directe import Medium
main.py DI via factory Medium — main.py is momenteel kapot (Copilot)
scripts/migrate_chromadb_to_weaviate.py Nieuw bestand Laag

Bestanden die NIET veranderen

Bestand Reden
src/domain/entities.py UDSMetadata, DataZone, enums — ongewijzigd
agents/hub.py Praat tegen ScoutAgent interface — ongewijzigd
agents/curator.py Geen vector store dependency
agents/synthesizer.py Geen vector store dependency
safety/policy.py Zone-logica ongewijzigd
mcp_server/server.py Praat tegen FastAPI endpoints
rag/chunker.py Onafhankelijk van storage backend

Test-impact

Testsuite Impact Actie
test_sprint_a.py (39 tests) ZonedVectorStore tests — draaien op ChromaDB EphemeralClient Geen wijziging nodig — testen interface
test_sprint5.py t/m test_sprint9.py VectorStore tests — idem Geen wijziging nodig
test_sprint_b.py (40 tests) SharePoint + ZonedVectorStore Geen wijziging nodig
test_rag.py, test_main.py Basis RAG + API tests Geen wijziging nodig
Nieuw: test_sprint_2_1.py Weaviate-specifieke tests Nieuw te schrijven

Cruciale garantie: Bestaande 321 tests worden NIET aangepast. Ze blijven draaien op ChromaDB EphemeralClient (in-memory) als test-backend. Nieuwe Weaviate-tests komen erbij.


Risico's en mitigatie

Risico Impact Kans Mitigatie
Weaviate Docker niet beschikbaar in CI CI breekt Laag GitHub Actions services: block + fallback naar ChromaDB
Embedding mismatch ChromaDB ↔ Weaviate Query recall daalt Medium Zelfde model behouden, migratiescript valideert recall
main.py is kapot (Copilot) Integratie geblokkeerd Hoog main.py eerst repareren (pre-sprint)
Performance regressie (netwerk-hop) Latency stijgt Laag Weaviate draait lokaal, benchmarks in testsuite
Copilot branches conflicteren Merge issues Medium Alle Copilot branches evalueren en opruimen vóór start

Pre-condities (vóór sprint start)

  1. main.py repareren — huidige staat is kapot door Copilot wijzigingen
  2. Copilot branches evalueren — welke mergen, welke sluiten
  3. Open GitHub Actions fixen — CI moet groen zijn vóór nieuwe sprint
  4. Akkoord Niels op dit sprintplan

Definition of Done

  • [ ] Weaviate 1.27.6 draait via docker compose up
  • [ ] WeaviateZonedVectorStore implementeert exact dezelfde interface als ZonedVectorStore
  • [ ] Zone-isolatie (RED/YELLOW/GREEN) werkt via Weaviate collections
  • [ ] Interactie-opslag werkt in aparte Weaviate collection
  • [ ] Embedding model paraphrase-multilingual-MiniLM-L12-v2 behouden
  • [ ] Config switch VECTOR_BACKEND = "chromadb" (default) | "weaviate"
  • [ ] Migratiescript migrate_chromadb_to_weaviate.py beschikbaar
  • [ ] Alle 321+ bestaande tests groen (ongewijzigd, op ChromaDB)
  • [ ] Nieuwe tests voor Weaviate-specifieke functionaliteit
  • [ ] Bandit security scan: geen medium/high findings
  • [ ] Ruff lint: geen errors
  • [ ] PR naar main met volledige CI groen
  • [ ] main.py is functioneel (pre-conditie opgelost)

Relatie tot BNS Roadmap

Sprint 2.1 bereidt de data-laag voor op schaalbaarheid. De BNS Causal Engine (Sprint 0, Q2 2026) blijft een gescheiden sidecar:

RAG Pipeline (Sprint 2.1)          BNS Sidecar (Sprint 0)
┌─────────────────────┐            ┌─────────────────────┐
│ Weaviate             │            │ pgmpy + NetworkX    │
│ ├─ BuurtsGreen      │            │ ├─ DAG (in-memory)  │
│ ├─ BuurtsYellow     │            │ ├─ CPT tabellen     │
│ ├─ BuurtsRed        │            │ └─ /causal/infer    │
│ └─ BuurtsInteraction│            │                     │
└─────────┬───────────┘            └──────────┬──────────┘
          │                                    │
          └──── Koppeling pas in BNS Sprint 2 (Q4 2026) ────┘
                    via LDF-filter + VERA

De twee systemen delen geen database. Pas in BNS Sprint 2 worden outputs gecombineerd via het LDF-filter, en alleen na Go/No-Go beslissing.


Openstaande beslissingen

# Beslissing Eigenaar Blokkeert
6 Weaviate multi-tenancy per KWP of collections per zone? Niels Fase 2
7 Copilot branches: welke sluiten, welke mergen? Niels Pre-conditie
8 main.py: herstellen vanuit git history of herschrijven? Claude Pre-conditie