spike(wissensbasis): on-device Embedding-Retrieval + Sync für mm-knowhow #258

Closed
opened 2026-05-14 16:14:10 +02:00 by admin-mrrm · 2 comments
Owner

Ziel

Machbarkeitsnachweis, dass eine persönliche Markdown-Wissensbasis (~/storage/dev/mm-knowhow/notes/) als App-Feature funktioniert: natürlichsprachige Frage → Top-N passende Notes, lokal auf dem Phone, mit Server-Sync. Generation/Chat bewusst draußen — Antwort = Liste der Note-Treffer.

Hintergrund

MM-knowhow ist eine wachsende Markdown-KB mit YAML-Frontmatter (id, title, tags, links, created, updated). Ziel ist eine App-Anbindung, die offline durchsuchbar ist und sich mit dem Server synchron hält.

Entscheidungen aus Vorgespräch:

  • Kein on-device LLM für Antwortgenerierung. Halluzinationsrisiko zu hoch, Qualität kleiner Modelle (1–3B) nicht ausreichend.
  • Embedding-Retrieval (multilinguales Modell via ONNX Runtime) statt extractive QA — passt zum Anspruch "Note finden statt Antwort generieren".
  • Sync: Markdown ist trivial syncbar, Konflikte via last-write-wins reichen für single-user.
  • Native-Module ok: Dev-Client-Workflow existiert bereits wegen Ollama-Kategorisierer.

Aufgaben

  • Embedding-Modell evaluieren: paraphrase-multilingual-MiniLM-L12-v2 vs. bge-m3 (small) — Größe, Qualität auf 5–10 echten Test-Queries gegen aktuelle Notes
  • ONNX Runtime React Native in Dev-Client integrieren und ersten Embedding-Run auf dem Phone laufen lassen, Inferenzzeit messen
  • Storage-Strategie entscheiden: SQLite mit sqlite-vec Extension vs. Vektoren als BLOB + Cosine in JS — Mini-Benchmark bei ~200 Notes
  • Sync-Endpoint im NestJS-Backend skizzieren (GET /notes, PUT /notes/:id, einfaches updated-Timestamp-Diff)
  • Konflikt-Strategie festlegen (Vorschlag: last-write-wins mit updated-Timestamp; Konflikt-Log für später)
  • Sicherheits-Check: Notes-Inhalte dürfen laut Globaler Anweisung NIE an externe Dienste — bestätigen, dass Embedding-Berechnung lokal bleibt
  • Spike-Bericht: gewähltes Modell, Inferenzzeit pro Query auf realem Phone, Speicher-Footprint, Sync-Skizze

Ergebnis

Spike-Bericht (als Wiki-Seite oder Issue-Kommentar) mit:

  • Modell- und Storage-Wahl mit Begründung
  • Gemessene Latenz: Embedding-Berechnung pro Note (Index-Build) und pro Query auf dem Zielgerät
  • Skizze des Sync-Protokolls
  • Go/No-Go-Entscheidung für KB-2 und KB-3

Akzeptanzkriterien

  • Embedding-Modell läuft auf dem Phone via Dev-Client, Inferenzzeit pro Query < 500 ms bei ~200 Notes
  • Test-Queries liefern manuell plausible Top-3-Treffer (qualitative Bewertung)
  • Sync-Protokoll-Skizze ist im Issue oder Wiki dokumentiert
  • Go/No-Go für die nachfolgenden Milestones (Wissensbasis — 2 / — 3) ist getroffen

Abhängigkeiten / nicht in diesem Issue

  • Suche-UI (web + mobile) → Wissensbasis — 2
  • Erfassung/Editor mit Templates + Outliner + optionalem AI-Cleanup → Wissensbasis — 3
## Ziel Machbarkeitsnachweis, dass eine persönliche Markdown-Wissensbasis (`~/storage/dev/mm-knowhow/notes/`) als App-Feature funktioniert: natürlichsprachige Frage → Top-N passende Notes, lokal auf dem Phone, mit Server-Sync. Generation/Chat bewusst draußen — Antwort = Liste der Note-Treffer. ## Hintergrund MM-knowhow ist eine wachsende Markdown-KB mit YAML-Frontmatter (`id, title, tags, links, created, updated`). Ziel ist eine App-Anbindung, die offline durchsuchbar ist und sich mit dem Server synchron hält. Entscheidungen aus Vorgespräch: - **Kein on-device LLM** für Antwortgenerierung. Halluzinationsrisiko zu hoch, Qualität kleiner Modelle (1–3B) nicht ausreichend. - **Embedding-Retrieval** (multilinguales Modell via ONNX Runtime) statt extractive QA — passt zum Anspruch "Note finden statt Antwort generieren". - **Sync**: Markdown ist trivial syncbar, Konflikte via last-write-wins reichen für single-user. - **Native-Module ok**: Dev-Client-Workflow existiert bereits wegen Ollama-Kategorisierer. ## Aufgaben - [ ] Embedding-Modell evaluieren: `paraphrase-multilingual-MiniLM-L12-v2` vs. `bge-m3` (small) — Größe, Qualität auf 5–10 echten Test-Queries gegen aktuelle Notes - [ ] ONNX Runtime React Native in Dev-Client integrieren und ersten Embedding-Run auf dem Phone laufen lassen, Inferenzzeit messen - [ ] Storage-Strategie entscheiden: SQLite mit `sqlite-vec` Extension vs. Vektoren als BLOB + Cosine in JS — Mini-Benchmark bei ~200 Notes - [ ] Sync-Endpoint im NestJS-Backend skizzieren (`GET /notes`, `PUT /notes/:id`, einfaches `updated`-Timestamp-Diff) - [ ] Konflikt-Strategie festlegen (Vorschlag: last-write-wins mit `updated`-Timestamp; Konflikt-Log für später) - [ ] Sicherheits-Check: Notes-Inhalte dürfen laut Globaler Anweisung NIE an externe Dienste — bestätigen, dass Embedding-Berechnung lokal bleibt - [ ] Spike-Bericht: gewähltes Modell, Inferenzzeit pro Query auf realem Phone, Speicher-Footprint, Sync-Skizze ## Ergebnis Spike-Bericht (als Wiki-Seite oder Issue-Kommentar) mit: - Modell- und Storage-Wahl mit Begründung - Gemessene Latenz: Embedding-Berechnung pro Note (Index-Build) und pro Query auf dem Zielgerät - Skizze des Sync-Protokolls - Go/No-Go-Entscheidung für KB-2 und KB-3 ## Akzeptanzkriterien - [ ] Embedding-Modell läuft auf dem Phone via Dev-Client, Inferenzzeit pro Query < 500 ms bei ~200 Notes - [ ] Test-Queries liefern manuell plausible Top-3-Treffer (qualitative Bewertung) - [ ] Sync-Protokoll-Skizze ist im Issue oder Wiki dokumentiert - [ ] Go/No-Go für die nachfolgenden Milestones (Wissensbasis — 2 / — 3) ist getroffen ## Abhängigkeiten / nicht in diesem Issue - Suche-UI (web + mobile) → Wissensbasis — 2 - Erfassung/Editor mit Templates + Outliner + optionalem AI-Cleanup → Wissensbasis — 3
Collaborator

PM-Refinement (2026-06-08) — Scope-Aktualisierung nach KI-Foundation rc16–rc19

Seit der Spike-Formulierung ist die Phase-1-KI-Foundation (Epic #122) auf Gerät validiert. Zwei zentrale Spike-Fragen sind dadurch implizit beantwortet und sollten den Scope verschlanken:

Bereits entschieden durch ausgeliefertes Phase-1-Stack

  • Embedding-Modell: Xenova/multilingual-e5-small (ONNX, dim=384) — läuft via onnxruntime-react-native (siehe apps/mobile/src/services/embedding-service.ts). Modell-Vergleich MiniLM vs. bge-m3 ist damit nicht mehr Spike-Scope — Baseline ist gesetzt; eine Re-Evaluation lohnt nur, falls die KB-Use-Case-Messung explizit Qualitätsprobleme zeigt.
  • Storage: sqlite-vec statisch gelinkt via @op-engineering/op-sqlite ("sqliteVec": true). Adapter unter apps/mobile/src/services/op-sqlite-vector-store-db.ts. Auch hier: kein BLOB+JS-Benchmark mehr nötig.
  • Inferenz auf Phone: läuft (rc16+). Die Modell-Shards (~120 MB) werden beim ersten Run heruntergeladen und gecacht.

Verbleibender Spike-Scope (geschärft)

  1. KB-Anbindung als IDataSource-Adapter — Markdown-Notes aus ~/storage/dev/mm-knowhow/notes/ als zusätzliche Quelle in das bestehende Index-/Such-Stack (analog zu Mail/Listen/Notes). Liefert das die gewünschte Such-Qualität für KB-Queries?
  2. Latenz-Messung im KB-Profil — Akzeptanzkriterium muss präzisiert werden:
    • Zielgerät: welches Phone? (z.B. aktuelles Test-Device User)
    • Build-Typ: Release-APK (nicht Dev-Client, weil dort Bundler-Overhead die Messung verfälscht)
    • Was wird gemessen: Query-Latenz (Embedding + sqlite-vec-KNN) oder auch Index-Build?
  3. Sync-Endpoint-Skizze — bleibt im Scope; GET /notes, PUT /notes/:id, updated-Diff. Bezug zum geplanten Day-Planner Source-Pattern (#360) prüfen.
  4. Konflikt-Strategie — last-write-wins bleibt vorgeschlagen; bestätigen oder revidieren.
  5. Sicherheits-Check — Notes-Inhalte verlassen das Gerät nie (außer beim Sync ans eigene API). Bestätigen, dass Embedding-Computation lokal bleibt — durch das ausgelieferte Stack bereits gegeben.

Geschärfte Akzeptanzkriterien (Vorschlag)

  • KB-IDataSource-Adapter geschrieben + lokal indexierbar (~200 Notes)
  • Latenz pro Query (Embedding + KNN) auf Zielgerät im Release-Build dokumentiert; harte Schwelle z.B. p95 < 500 ms
  • 5 manuelle Test-Queries gegen reale KB → Top-3-Treffer qualitativ plausibel (Spike-Bericht enthält die konkreten Queries + Treffer)
  • Sync-Protokoll-Skizze als Issue-Kommentar oder Wiki, mit Bezug zu #360-Source-Pattern
  • Go/No-Go-Entscheidung für KB-2/KB-3 mit Risiken (z.B. Cold-Start-Modell-Download UX, Sync-Konflikt-Edge-Cases)

PM-Vorbehalt: Ownership

Der Spike ist technische Investigation — Architekt/Dev-Arbeit, nicht PM. PM-Beitrag endet hier mit der Scope-Refinement. Ein Spike-Owner muss zugewiesen werden, bevor die Arbeit beginnt. Vorschlag: Same-Hands wie KI-Foundation rc16–rc19, damit das Stack-Kontext nicht verloren geht.

## PM-Refinement (2026-06-08) — Scope-Aktualisierung nach KI-Foundation rc16–rc19 Seit der Spike-Formulierung ist die Phase-1-KI-Foundation (Epic #122) auf Gerät validiert. Zwei zentrale Spike-Fragen sind dadurch *implizit beantwortet* und sollten den Scope verschlanken: ### Bereits entschieden durch ausgeliefertes Phase-1-Stack - **Embedding-Modell**: `Xenova/multilingual-e5-small` (ONNX, dim=384) — läuft via `onnxruntime-react-native` (siehe `apps/mobile/src/services/embedding-service.ts`). Modell-Vergleich `MiniLM` vs. `bge-m3` ist damit *nicht mehr Spike-Scope* — Baseline ist gesetzt; eine Re-Evaluation lohnt nur, falls die KB-Use-Case-Messung explizit Qualitätsprobleme zeigt. - **Storage**: `sqlite-vec` statisch gelinkt via `@op-engineering/op-sqlite` (`"sqliteVec": true`). Adapter unter `apps/mobile/src/services/op-sqlite-vector-store-db.ts`. Auch hier: kein BLOB+JS-Benchmark mehr nötig. - **Inferenz auf Phone**: läuft (rc16+). Die Modell-Shards (~120 MB) werden beim ersten Run heruntergeladen und gecacht. ### Verbleibender Spike-Scope (geschärft) 1. **KB-Anbindung als `IDataSource`-Adapter** — Markdown-Notes aus `~/storage/dev/mm-knowhow/notes/` als zusätzliche Quelle in das bestehende Index-/Such-Stack (analog zu Mail/Listen/Notes). Liefert das die gewünschte Such-Qualität für KB-Queries? 2. **Latenz-Messung im KB-Profil** — Akzeptanzkriterium muss präzisiert werden: - Zielgerät: **welches** Phone? (z.B. aktuelles Test-Device User) - Build-Typ: Release-APK (nicht Dev-Client, weil dort Bundler-Overhead die Messung verfälscht) - Was wird gemessen: Query-Latenz (Embedding + sqlite-vec-KNN) oder auch Index-Build? 3. **Sync-Endpoint-Skizze** — bleibt im Scope; `GET /notes`, `PUT /notes/:id`, `updated`-Diff. Bezug zum geplanten Day-Planner Source-Pattern (#360) prüfen. 4. **Konflikt-Strategie** — last-write-wins bleibt vorgeschlagen; bestätigen oder revidieren. 5. **Sicherheits-Check** — Notes-Inhalte verlassen das Gerät nie (außer beim Sync ans eigene API). Bestätigen, dass Embedding-Computation lokal bleibt — durch das ausgelieferte Stack bereits gegeben. ### Geschärfte Akzeptanzkriterien (Vorschlag) - [ ] KB-`IDataSource`-Adapter geschrieben + lokal indexierbar (~200 Notes) - [ ] Latenz pro Query (Embedding + KNN) auf Zielgerät **im Release-Build** dokumentiert; harte Schwelle z.B. p95 < 500 ms - [ ] 5 manuelle Test-Queries gegen reale KB → Top-3-Treffer qualitativ plausibel (Spike-Bericht enthält die konkreten Queries + Treffer) - [ ] Sync-Protokoll-Skizze als Issue-Kommentar oder Wiki, mit Bezug zu #360-Source-Pattern - [ ] Go/No-Go-Entscheidung für KB-2/KB-3 mit Risiken (z.B. Cold-Start-Modell-Download UX, Sync-Konflikt-Edge-Cases) ### PM-Vorbehalt: Ownership Der Spike ist *technische Investigation* — Architekt/Dev-Arbeit, nicht PM. PM-Beitrag endet hier mit der Scope-Refinement. Ein Spike-Owner muss zugewiesen werden, bevor die Arbeit beginnt. Vorschlag: Same-Hands wie KI-Foundation rc16–rc19, damit das Stack-Kontext nicht verloren geht.
Collaborator

Architekt-Beitrag: Spike-Execution-Plan auf bestehendem Stack

PM-Refinement (Comment 3173) hat das Stack korrekt benannt — hier der konkrete Plan, wie der Spike auf der ausgelieferten Infrastruktur umgesetzt wird. Das beantwortet auch das offene Ownership-Thema: Spike-Arbeit ist klein, ich (Architekt) skizziere die Schritte; Implementierung soll ein Dev übernehmen, weil sie hardware-spezifische Messung enthält.

Vorab geklärt durch ausgeliefertes Phase-1-Stack

Spike-Frage Antwort (heute)
Embedding-Modell Xenova/multilingual-e5-small (ONNX Q8, dim=384) — fix
Storage sqlite-vec via @op-engineering/op-sqlite (statisch gelinkt) — fix
ONNX-Runtime auf Phone onnxruntime-react-native läuft seit rc16 in Production
Chunking-Strategie Markdown-Sections (^#{1,3} ) mit Overlap, fertige Implementierung in apps/mobile/src/services/data-sources/note-data-source.ts:85 — direkt wiederverwendbar
Privacy Vollständig on-device (kein Outbound-Embedding-Call) — durch das Stack garantiert

Damit kollabieren 5 von 7 ursprünglichen Spike-Aufgaben auf „bereits beantwortet“. Verbleibender Scope ist auf zwei Aspekte konzentriert: KB-Source-Adapter + Sync-Endpoint.

Reduzierter Execution-Plan

1. KbDataSource als IDataSource-Implementierung

Pattern existiert (NoteDataSource, MailDataSource, ShoppingListDataSource — alle in apps/mobile/src/services/data-sources/). Neuer Adapter mit:

  • sourceType = 'kb-note'
  • extractChunks(sourceId) liest Markdown + YAML-Frontmatter aus lokalem KB-Mirror, splittet via splitMarkdownSections (recyceln von note-data-source.ts:85)
  • Frontmatter (title, tags, links) als Chunk-Metadata; Titel als Prefix vor jedem Chunk (analog Note-DataSource)
  • subscribeToUpdates/publish für Mutation-Observer-Hook (relevant erst, sobald Sync läuft)

2. Sync-Endpoint im API skizzieren (nicht implementieren)

  • GET /kb/notes?updatedSince=<iso> — Diff-Sync (Server liefert nur geänderte Notes)
  • PUT /kb/notes/:id mit ETag-Header für Konflikt-Erkennung
  • Konflikt-Strategie: last-write-wins (vorgeschlagen) + Konflikt-Log-Tabelle für Edge-Cases — DB-Migration in Phase 2, nicht im Spike
  • Storage server-side: Drizzle-Tabelle kb_notes (id, ownerSub, title, body, frontmatterJson, updated_at). Skizze als ADR-0002 in Spike-Bericht

3. Latenz-Messung — geschärft

PM-Comment hat Akzeptanzkriterien geschärft; ich konkretisiere die Methode:

  • Build: Release-APK, kein Dev-Client (Bundler-Overhead = Mess-Verzerrung)
  • Gerät: aktuelles Test-Phone (User-Hardware) + Vermerk im Bericht
  • Korpus: ~200 Notes aus echtem ~/storage/dev/mm-knowhow/notes/
  • Metrik: p50 + p95 für (a) Initial-Index (alle 200 Notes) und (b) Query-Latency (Embedding + sqlite-vec-KNN). Logcat-Filter [VectorStore]/[EmbeddingService]
  • Schwelle: p95 Query < 500 ms (PM-Vorgabe). Initial-Index ohne harte Schwelle — Background-Job.

4. Qualitäts-Sanity (klein gehalten)

  • 5 echte Test-Queries auf eigenem KB-Korpus
  • Top-3-Treffer manuell als „relevant“ / „mäßig“ / „daneben“ bewerten
  • Wenn ≥4 von 5 Queries einen relevanten Treffer im Top-3 haben → Go für KB-2

Out-of-Scope (bleibt für KB-2/KB-3)

  • Such-UI mit KB-Filter-Chip — KB-2
  • KB-Editor / Outliner in App — KB-3
  • Background-Sync-Trigger (expo-task-manager, analog #438) — KB-2

Ownership-Vorschlag

Spike-Arbeit ist jetzt linear:

  1. KbDataSource schreiben (Pair-Programming mit existierendem Pattern, ~½ Tag)
  2. Lokaler KB-Mirror in App-Sandbox (Mechanismus: simpler expo-file-system Read; Sync-Pfad ist Skizze, nicht Implementierung)
  3. Auf Phone messen (1–2 h)
  4. Spike-Bericht als Kommentar hier

Empfehlung: gleiche Hand wie rc16–rc19. Wenn keine Kapazität, kann das auch als kleine Story im nächsten Iterations-Block laufen — keine harte Deadline.

## Architekt-Beitrag: Spike-Execution-Plan auf bestehendem Stack PM-Refinement (Comment 3173) hat das Stack korrekt benannt — hier der konkrete Plan, wie der Spike auf der ausgelieferten Infrastruktur umgesetzt wird. Das beantwortet auch das offene Ownership-Thema: Spike-Arbeit ist klein, ich (Architekt) skizziere die Schritte; Implementierung soll ein Dev übernehmen, weil sie hardware-spezifische Messung enthält. ### Vorab geklärt durch ausgeliefertes Phase-1-Stack | Spike-Frage | Antwort (heute) | |---|---| | Embedding-Modell | `Xenova/multilingual-e5-small` (ONNX Q8, dim=384) — fix | | Storage | `sqlite-vec` via `@op-engineering/op-sqlite` (statisch gelinkt) — fix | | ONNX-Runtime auf Phone | `onnxruntime-react-native` läuft seit rc16 in Production | | Chunking-Strategie | Markdown-Sections (`^#{1,3} `) mit Overlap, fertige Implementierung in `apps/mobile/src/services/data-sources/note-data-source.ts:85` — direkt wiederverwendbar | | Privacy | Vollständig on-device (kein Outbound-Embedding-Call) — durch das Stack garantiert | Damit kollabieren 5 von 7 ursprünglichen Spike-Aufgaben auf „bereits beantwortet“. Verbleibender Scope ist auf zwei Aspekte konzentriert: **KB-Source-Adapter** + **Sync-Endpoint**. ### Reduzierter Execution-Plan #### 1. `KbDataSource` als `IDataSource`-Implementierung Pattern existiert (`NoteDataSource`, `MailDataSource`, `ShoppingListDataSource` — alle in `apps/mobile/src/services/data-sources/`). Neuer Adapter mit: - `sourceType = 'kb-note'` - `extractChunks(sourceId)` liest Markdown + YAML-Frontmatter aus lokalem KB-Mirror, splittet via `splitMarkdownSections` (recyceln von `note-data-source.ts:85`) - Frontmatter (`title`, `tags`, `links`) als Chunk-Metadata; Titel als Prefix vor jedem Chunk (analog Note-DataSource) - `subscribeToUpdates`/`publish` für Mutation-Observer-Hook (relevant erst, sobald Sync läuft) #### 2. Sync-Endpoint im API skizzieren (nicht implementieren) - `GET /kb/notes?updatedSince=<iso>` — Diff-Sync (Server liefert nur geänderte Notes) - `PUT /kb/notes/:id` mit ETag-Header für Konflikt-Erkennung - Konflikt-Strategie: last-write-wins (vorgeschlagen) + Konflikt-Log-Tabelle für Edge-Cases — DB-Migration in Phase 2, nicht im Spike - Storage server-side: Drizzle-Tabelle `kb_notes` (id, ownerSub, title, body, frontmatterJson, updated_at). Skizze als ADR-0002 in Spike-Bericht #### 3. Latenz-Messung — geschärft PM-Comment hat Akzeptanzkriterien geschärft; ich konkretisiere die Methode: - **Build**: Release-APK, kein Dev-Client (Bundler-Overhead = Mess-Verzerrung) - **Gerät**: aktuelles Test-Phone (User-Hardware) + Vermerk im Bericht - **Korpus**: ~200 Notes aus echtem `~/storage/dev/mm-knowhow/notes/` - **Metrik**: p50 + p95 für (a) Initial-Index (alle 200 Notes) und (b) Query-Latency (Embedding + sqlite-vec-KNN). Logcat-Filter `[VectorStore]`/`[EmbeddingService]` - **Schwelle**: p95 Query < 500 ms (PM-Vorgabe). Initial-Index ohne harte Schwelle — Background-Job. #### 4. Qualitäts-Sanity (klein gehalten) - 5 echte Test-Queries auf eigenem KB-Korpus - Top-3-Treffer manuell als „relevant“ / „mäßig“ / „daneben“ bewerten - Wenn ≥4 von 5 Queries einen relevanten Treffer im Top-3 haben → Go für KB-2 ### Out-of-Scope (bleibt für KB-2/KB-3) - Such-UI mit KB-Filter-Chip — KB-2 - KB-Editor / Outliner in App — KB-3 - Background-Sync-Trigger (`expo-task-manager`, analog #438) — KB-2 ### Ownership-Vorschlag Spike-Arbeit ist jetzt linear: 1. `KbDataSource` schreiben (Pair-Programming mit existierendem Pattern, ~½ Tag) 2. Lokaler KB-Mirror in App-Sandbox (Mechanismus: simpler `expo-file-system` Read; Sync-Pfad ist Skizze, nicht Implementierung) 3. Auf Phone messen (1–2 h) 4. Spike-Bericht als Kommentar hier Empfehlung: gleiche Hand wie rc16–rc19. Wenn keine Kapazität, kann das auch als kleine Story im nächsten Iterations-Block laufen — keine harte Deadline.
Sign in to join this conversation.
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
admin-mrrm/mrrmlabapp#258
No description provided.