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>
4.2 KiB
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 64–2048, 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 Spaltemodel TEXT NOT NULL DEFAULT 'text-embedding-v3'- Index
idx_chunks_model
- Index
assessments: neue Spaltensummary_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: ~1–2h 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).