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

4.2 KiB
Raw Permalink Blame 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).