gwoe-antragspruefer/docs/adr/0006-embedding-model-migration-v3-to-v4.md

105 lines
4.2 KiB
Markdown
Raw Permalink Normal View History

# ADR 0006: Embedding-Modell-Migration text-embedding-v3 → v4
**Status:** accepted
**Datum:** 2026-04-11
**Issue:** #123
**Kontext:** #105 Clustering, #108 Empfehlungen
## Kontext
Bis 2026-04-11 wurden alle Wahlprogramm-Chunks (69 Programme, ~18k Chunks) mit
`text-embedding-v3` (1024 Dimensionen) indexiert. Für die geplanten Features
**#105 Antrag-Clustering** und **#108 Empfehlungen ähnlicher Anträge** brauchen
wir Embeddings für die Assessments selbst, nicht nur für Programm-Chunks.
Bei der Modellwahl stellte sich die Frage: dasselbe Modell für beide Seiten
oder darf eine Seite neuer sein?
**Kritisch:** v3- und v4-Embeddings liegen in unterschiedlichen Vektorräumen.
Cosine-Distance zwischen einem v3- und einem v4-Vektor ist mathematisch
gültig, aber semantisch Unsinn. Eine Vermischung macht die Citation-Binding-
Logik aus ADR 0001 kaputt und blockiert jede zukünftige Feature, die
Antrag-zu-Programm-Ähnlichkeit berechnet.
## Entscheidung
Vollständige Migration **beider Seiten** (Wahlprogramm-Chunks + Assessments)
auf `text-embedding-v4` (1024 Dimensionen, gleiches Default wie v3).
**Begründung:**
- Alibaba DashScope preist v3 und v4 **identisch** ($0.07 / 1M Tokens)
- v4 ist strikt besser auf MTEB (68.36 vs 63.39 overall, 59.30 vs 55.41 retrieval)
- v4 unterstützt 100+ Sprachen (v3: 50+), relevant für Zitate mit Fremdwörtern
- v4 bietet flexible Dimensionen 642048, wir bleiben aber auf 1024 (v3-kompatibel)
- Die einmaligen Reindex-Kosten belaufen sich auf **~$0.50** für alle Programme
- v3 wird vermutlich mittelfristig deprecated; wir vermeiden eine zweite Migration später
Die Alternative "v3 für Programme, v4 für Assessments" wurde verworfen, weil
sie die zukünftige Kompatibilität für Antrag-zu-Programm-Ähnlichkeit
permanent blockiert.
## Migrations-Strategie (Zero-Downtime)
**Zwei getrennte Settings** (`settings.embedding_model_write`,
`settings.embedding_model_read`) ermöglichen einen stufenweisen Switch ohne
Prod-Downtime:
| Phase | WRITE | READ | Zustand |
|---|---|---|---|
| 0 | v3 | v3 | Pre-Migration (alter Zustand) |
| 1 | **v4** | v3 | Code deployed, Reindex läuft im Hintergrund, Prod läuft weiter auf v3-Rows |
| 2 | v4 | **v4** | Reindex fertig, Flag geflippt, neue Queries nutzen v4-Rows |
| 3 | v4 | v4 | Cleanup: alte v3-Rows gelöscht |
**Schema-Änderungen:**
- `chunks`: neue Spalte `model TEXT NOT NULL DEFAULT 'text-embedding-v3'`
+ Index `idx_chunks_model`
- `assessments`: neue Spalten `summary_embedding BLOB`, `embedding_model TEXT`
**Reindex-Skript:** `app/reindex_embeddings.py` (Ausführung via
`docker exec gwoe-antragspruefer python -m app.reindex_embeddings`).
Schreibt v4-Rows parallel zu den v3-Rows, mit 100ms Rate-Limit zwischen
Calls (= max 10 req/sec). Bereits mit v4 indexierte Programme werden
übersprungen, damit das Skript idempotent ist und nach Abbruch nahtlos
fortgesetzt werden kann.
**Query-Pfad:** `find_relevant_chunks` filtert jetzt explizit
`WHERE model = ?` mit `EMBEDDING_MODEL_READ`. Query-Embeddings werden mit
demselben READ-Modell erzeugt (via neuer `model`-Parameter in
`create_embedding`), damit Query und Chunks im selben Vektorraum liegen.
## Konsequenzen
**Positiv:**
- Einheitlicher Vektorraum für Chunks und Assessments → #105, #108, und künftige
Ähnlichkeits-Features funktionieren out-of-the-box
- Bessere Retrieval-Qualität (MTEB +3.9 Punkte)
- Einmaliger Schritt, danach kein Mental-Load für Modell-Drift
**Negativ:**
- Reindex-Zeit: ~12h Wall-Time für alle 69 Programme (rate-limited)
- Kurzzeitig doppelter Storage (v3 + v4 Chunks parallel) bis Phase 3
- Assessment-Embedding-Generation adds ~100ms Latenz pro neuer Analyse (ein
zusätzlicher API-Call), der aber non-blocking fehlertolerant ist — Backfill
zieht später nach
**Neutral:**
- Die beiden Settings (`write` / `read`) bleiben langfristig im Code bestehen
als Infrastruktur für zukünftige Modell-Migrationen (v5, v6, …). Das Pattern
ist wiederverwendbar.
## Alternative: "v3 einfrieren"
Verworfen, weil v3 kein aktuell unterstütztes Flaggschiff mehr ist und
Deprecation wahrscheinlich ist. Besser jetzt migrieren, wenn noch beide
Modelle verfügbar sind, als später unter Zeitdruck.
## Alternative: "nur Assessments auf v4"
Verworfen wegen der Vektorraum-Fragmentierung (siehe Kontext).