Embedding-Modell: Migration text-embedding-v3 → v4 (einheitlicher Vektorraum) #123

Closed
opened 2026-04-11 21:11:39 +02:00 by tobias · 1 comment
Owner

Kontext

Diskussion aus #105 Clustering: für Antrag-Clustering und #108 Empfehlungen brauchen wir Assessment-Embeddings. Die bereits indexierten Wahlprogramm-Chunks nutzen text-embedding-v3. Bei gleichem Preis ($0.07/1M Tokens) bietet text-embedding-v4:

  • MTEB Overall 68.36 vs 63.39 (+5.0)
  • MTEB Retrieval 59.30 vs 55.41 (+3.9)
  • 100+ Sprachen (v3: 50+)
  • Flexible Dimensionen 64–2048 (default 1024, kompatibel zu v3)

Kritischer Punkt: v3- und v4-Embeddings sind nicht vergleichbar (unterschiedliche Vektorräume). Wenn Assessments auf v4 gehen und Wahlprogramme auf v3 bleiben, können wir nie Cosine-Distance zwischen Antrag und Programm berechnen — genau das Feature, das #47 Citation-Binding inhaltlich stützt und #108 Empfehlungen ermöglicht.

Entscheidung

Vollständige Migration auf text-embedding-v4 für beide Seiten (Wahlprogramm-Chunks und neue Assessment-Embeddings). Einmaliger Reindex-Kosten ~$0.50 (69 Programme × ~200 Chunks × ~500 Tokens ≈ 7M Tokens).

Implementierung

1. Schema-Migration

  • chunks Tabelle: neue Spalte model TEXT DEFAULT 'text-embedding-v3'
  • assessments Tabelle: neue Spalten summary_embedding BLOB und embedding_model TEXT
  • Index auf chunks.model für schnellen Filter während Migration

2. Code-Änderungen

  • app/embeddings.py: EMBEDDING_MODEL = "text-embedding-v4", Dimension-Check
  • app/embeddings.py: Reindex-Funktion schreibt neue Rows mit model='text-embedding-v4' parallel zu bestehenden (zero-downtime)
  • app/analyzer.py: nach erfolgreicher Analyse Assessment-Embedding erzeugen (Titel + Kurzfassung + Themen als gemeinsamer String)
  • Query-Pfad (#47 Citation-Binding, spätere Clustering): filtert WHERE model = <active_model> via Settings-Flag

3. Reindex

  • Script-Lauf im Hintergrund, Rate-Limit 10 req/sec
  • Fortschritt-Logging pro Programm
  • Atomarer Switch: Settings-Flag EMBEDDING_MODEL_ACTIVE flippt von v3 auf v4, alte v3-Rows werden gelöscht
  • Backfill Assessment-Embeddings für Bestands-DB (~1000 Anträge, ~0.5M Tokens, ~$0.04)

4. Cleanup & Doku

  • templates/methodik.html: v3 → v4 (2 Stellen)
  • ADR 0005: "Embedding-Modell-Migration v3 → v4, einheitlicher Vektorraum"
  • Smoke-Test #47 Citation-Binding nach Switch (funktioniert immer noch?)

Akzeptanzkriterien

  • Alle 69 Wahlprogramme re-indexiert mit v4
  • Alle bestehenden Assessments haben summary_embedding IS NOT NULL
  • Neue Analysen schreiben v4-Embedding automatisch
  • #47 Citation-Binding liefert weiterhin plausible Treffer
  • /api/assessment liefert Embeddings nicht zurück (sind intern, zu groß für Response)

Follow-ups nach Merge

  • #105 Clustering kann starten (unblocked)
  • #108 Empfehlungen teilweise unblocked (Merkliste-Tabelle + Ähnliche-Anträge-API)
## Kontext Diskussion aus #105 Clustering: für Antrag-Clustering und #108 Empfehlungen brauchen wir Assessment-Embeddings. Die bereits indexierten Wahlprogramm-Chunks nutzen `text-embedding-v3`. Bei gleichem Preis ($0.07/1M Tokens) bietet `text-embedding-v4`: - MTEB Overall 68.36 vs 63.39 (+5.0) - MTEB Retrieval 59.30 vs 55.41 (+3.9) - 100+ Sprachen (v3: 50+) - Flexible Dimensionen 64–2048 (default 1024, kompatibel zu v3) **Kritischer Punkt:** v3- und v4-Embeddings sind nicht vergleichbar (unterschiedliche Vektorräume). Wenn Assessments auf v4 gehen und Wahlprogramme auf v3 bleiben, können wir nie Cosine-Distance zwischen Antrag und Programm berechnen — genau das Feature, das #47 Citation-Binding inhaltlich stützt und #108 Empfehlungen ermöglicht. ## Entscheidung Vollständige Migration auf `text-embedding-v4` für beide Seiten (Wahlprogramm-Chunks **und** neue Assessment-Embeddings). Einmaliger Reindex-Kosten ~$0.50 (69 Programme × ~200 Chunks × ~500 Tokens ≈ 7M Tokens). ## Implementierung ### 1. Schema-Migration - [ ] `chunks` Tabelle: neue Spalte `model TEXT DEFAULT 'text-embedding-v3'` - [ ] `assessments` Tabelle: neue Spalten `summary_embedding BLOB` und `embedding_model TEXT` - [ ] Index auf `chunks.model` für schnellen Filter während Migration ### 2. Code-Änderungen - [ ] `app/embeddings.py`: `EMBEDDING_MODEL = "text-embedding-v4"`, Dimension-Check - [ ] `app/embeddings.py`: Reindex-Funktion schreibt neue Rows mit `model='text-embedding-v4'` parallel zu bestehenden (zero-downtime) - [ ] `app/analyzer.py`: nach erfolgreicher Analyse Assessment-Embedding erzeugen (Titel + Kurzfassung + Themen als gemeinsamer String) - [ ] Query-Pfad (#47 Citation-Binding, spätere Clustering): filtert `WHERE model = <active_model>` via Settings-Flag ### 3. Reindex - [ ] Script-Lauf im Hintergrund, Rate-Limit 10 req/sec - [ ] Fortschritt-Logging pro Programm - [ ] Atomarer Switch: Settings-Flag `EMBEDDING_MODEL_ACTIVE` flippt von v3 auf v4, alte v3-Rows werden gelöscht - [ ] Backfill Assessment-Embeddings für Bestands-DB (~1000 Anträge, ~0.5M Tokens, ~$0.04) ### 4. Cleanup & Doku - [ ] `templates/methodik.html`: v3 → v4 (2 Stellen) - [ ] ADR 0005: "Embedding-Modell-Migration v3 → v4, einheitlicher Vektorraum" - [ ] Smoke-Test #47 Citation-Binding nach Switch (funktioniert immer noch?) ## Akzeptanzkriterien - Alle 69 Wahlprogramme re-indexiert mit v4 - Alle bestehenden Assessments haben `summary_embedding IS NOT NULL` - Neue Analysen schreiben v4-Embedding automatisch - #47 Citation-Binding liefert weiterhin plausible Treffer - `/api/assessment` liefert Embeddings nicht zurück (sind intern, zu groß für Response) ## Follow-ups nach Merge - #105 Clustering kann starten (unblocked) - #108 Empfehlungen teilweise unblocked (Merkliste-Tabelle + Ähnliche-Anträge-API)
Author
Owner

#123 abgeschlossen

Reindex komplett (2026-04-11 20:40 UTC):

  • 66 Wahlprogramme neu indexiert mit text-embedding-v4, 9231 Chunks hinzugefügt (bereits indexierte 19 Programme vom ersten Lauf wurden übersprungen)
  • 57 Assessments backfilled (alle, 0 failed) — jeder Antrag hat jetzt ein Summary-Embedding
  • Gesamt: 11681 v4-Chunks (exakt gleiche Anzahl wie v3, als Sanity-Check)

Post-Reindex:

  • docker-compose.yml + .env auf EMBEDDING_MODEL_READ=text-embedding-v4 geflippt
  • Container force-recreated, pydantic-Settings verifiziert: read=write=v4
  • Smoke-Tests grün: /methodik zeigt v4, /api/feed.xml OK, /api/assessments OK
  • v3-Cleanup: DELETE FROM chunks WHERE model='text-embedding-v3' + VACUUM
  • End-State: 11681 v4-Chunks, 0 v3-Chunks

Performance-Note: Mitten im Lauf habe ich auf Batch-Embedding umgestellt (10 Texte pro API-Call statt 1). Messbarer Speedup: ~7× von ~2.75 min/Programm auf ~23 sec. Gesamter Reindex-Lauf für 66 Programme: ~35 min (nach Umstellung).

Kosten: geschätzt ~$0.50 (11681 chunks × ~500 tokens × $0.07/1M = $0.41, plus 57 assessment-embeddings = vernachlässigbar).

Damit ist #105 (Clustering) und #108 Teil B (Ähnliche Anträge) unblocked. Schließe.

## #123 abgeschlossen ✅ **Reindex komplett (2026-04-11 20:40 UTC):** - 66 Wahlprogramme neu indexiert mit text-embedding-v4, 9231 Chunks hinzugefügt (bereits indexierte 19 Programme vom ersten Lauf wurden übersprungen) - 57 Assessments backfilled (alle, 0 failed) — jeder Antrag hat jetzt ein Summary-Embedding - Gesamt: 11681 v4-Chunks (exakt gleiche Anzahl wie v3, als Sanity-Check) **Post-Reindex:** - `docker-compose.yml` + `.env` auf `EMBEDDING_MODEL_READ=text-embedding-v4` geflippt - Container force-recreated, pydantic-Settings verifiziert: `read=write=v4` - Smoke-Tests grün: `/methodik` zeigt v4, `/api/feed.xml` OK, `/api/assessments` OK - v3-Cleanup: `DELETE FROM chunks WHERE model='text-embedding-v3'` + VACUUM - End-State: 11681 v4-Chunks, 0 v3-Chunks **Performance-Note:** Mitten im Lauf habe ich auf Batch-Embedding umgestellt (10 Texte pro API-Call statt 1). Messbarer Speedup: ~7× von ~2.75 min/Programm auf ~23 sec. Gesamter Reindex-Lauf für 66 Programme: ~35 min (nach Umstellung). **Kosten:** geschätzt ~$0.50 (11681 chunks × ~500 tokens × $0.07/1M = $0.41, plus 57 assessment-embeddings = vernachlässigbar). Damit ist #105 (Clustering) und #108 Teil B (Ähnliche Anträge) unblocked. Schließe.
Sign in to join this conversation.
No description provided.