gwoe-antragspruefer/docs/adr/0006-embedding-model-migration-v3-to-v4.md
Dotty Dotter 2dec009b5c docs+ops: ADRs 0006/0008, DDD-Bewertung, Zugriffsrechte, Smoke-Test, Cron-Scripts
ADRs:
- 0006 Embedding-Modell-Migration v3->v4 (#123)
- 0008 DDD-Lightweight-Migration (#136)

Analysen:
- ddd-bewertung.md (1237 Zeilen) — vollstaendige DDD-Analyse mit Tages-Roadmap
- protokoll-parser-v6-machbarkeit.md (418 Zeilen) — #106 Phase 2 Vorbereitung

Reference:
- zugriffsrechte.md — 63 Routes x 3 User-Status, UI-Sichtbarkeits-Matrix

Ops:
- scripts/deploy.sh — mit Uptime-Kuma-Wartungsmodus (#149)
- scripts/run-digest.sh — taeglicher Mail-Digest-Cron
- scripts/run-monitoring-scan.sh — Monitoring-Scan-Cron (noch nicht aktiv)
- scripts/smoke-test.sh — Gesamt-Funktionspruefung
- pytest.ini: integration/slow/e2e Markers, addopts not-integration

Tests/integration/: Live-Adapter-Tests + Frontend-XRef + Citation-Substring
                    + Wahlprogramm-Indexed (4 Live-Test-Suites, marker-opt-in)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:57 +02:00

105 lines
4.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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).