Sektions-Konglomerat statt LLM-Reduce fuer Lang-Transkripte

- llm.js analyzeLong neu: 4.2k-Chunks (8k = namenloser Brei), Rolling Context,
  eigennamen-Extraktion, Echo-Guard mit Prompt-Variation (3 Versuche),
  Feld-Salvage, Titel-Mikro-Call ohne letzten Abschnitt, Konglomerat in Code
- LLM-Reduce entfernt: Cross-Section-Synthese nachweislich jenseits Gemma-3-4B
- server.js: Prompt-Lab-Endpoint nach Abschluss wieder entfernt
- Doku Kap. 05 (Mermaid, Marotten) + Changelog

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113vDKdSNtD3Dwcw4QMu9yV
This commit is contained in:
schakal00783
2026-07-16 17:47:14 +02:00
co-authored by Claude Fable 5
parent 2f00ddeec6
commit 8cfdcf5d56
3 changed files with 168 additions and 77 deletions
+22 -8
View File
@@ -26,17 +26,27 @@ flowchart TB
REPAIR --> WCHECK
WCHECK -- "weiterhin leer/Junk" --> LONG
WCHECK -- ja --> OUT
B -- nein --> LONG["analyzeLong (Map-Reduce):<br/>Chunks à 8 000 Zeichen"]
LONG --> MAP["MAP: pro Chunk Mini-JSON<br/>(zusammenfassung, teilnehmer, todos)<br/>bewusst minimaler Prompt — lange Regelwände<br/>kippen Gemma in englische Prosa<br/>1 RETRY bei Parse-Fehler (Sampling-Münzwurf)"]
MAP --> SALV{"JSON parsebar?"}
SALV -- ja --> COLLECT["einsammeln"]
SALV -- nein --> PROSE["Prosa retten:<br/>Code-Fences UND rohe {...}-Blobs entfernen<br/>(JSON-Leak-Fix), dann als Teil-Summary nutzen"]
PROSE --> COLLECT
COLLECT --> REDUCE["REDUCE: Teil-Summaries (je ≤ 800 Zeichen,<br/>gelabelt 'Abschnitt i von n')<br/>→ EIN JSON: titel, zusammenfassung,<br/>kernpunkte[], entscheidungen[]<br/>Gewichtung nach Abschnitts-Anteil,<br/>Schluss-Smalltalk nie in Titel/Überblick<br/>2 Parse-Versuche, Tail wird geloggt"]
REDUCE --> OUT["Ergebnis"]
B -- nein --> LONG["analyzeLong (Sektions-Konglomerat):<br/>Chunks à 4 200 Zeichen<br/>(bei 8k wird der Inhalt generisch/namenlos,<br/>bei 4k bleibt Gemma geerdet)"]
LONG --> MAP["MAP pro Chunk, sequenziell mit ROLLING CONTEXT<br/>(1-Satz-Kurzfassungen der vorherigen Abschnitte →<br/>Änderungen erkennbar: 'jetzt X, vorher Y'):<br/>Mini-JSON zusammenfassung + eigennamen[]<br/>(reine Namens-EXTRAKTION) + teilnehmer + todos<br/>bewusst minimaler Prompt"]
MAP --> SALV{"JSON parsebar +<br/>kein Feldbeschreibungs-Echo?"}
SALV -- nein --> RETRY["bis 3 Versuche, Prompt VARIIERT<br/>(2.: ohne Kontext, 3.: ohne Hint —<br/>manche Inhalte echoen sonst JEDES Mal)<br/>dann Feld-Salvage per Regex<br/>(zusammenfassung-String überlebt fast immer),<br/>zuletzt Prosa-Rettung (≥ 60 Zeichen, sonst verwerfen)"]
RETRY --> COLLECT
SALV -- ja --> COLLECT["Sektionen einsammeln"]
COLLECT --> TITLE["TITEL-Mikro-Call: 2-Satz-Kurzfassungen<br/>OHNE letzten Abschnitt (Schluss-Smalltalk-Filter)<br/>→ nur {titel} — kleines Input/Output = zuverlässig"]
TITLE --> ASSEMBLE["KONGLOMERAT baut CODE (kein LLM-Reduce mehr):<br/>'Gesprächsverlauf in n Teilen — genannte Namen: …'<br/>+ 'Teil i/n: Summary (Namen: …)' chronologisch<br/>→ deterministisch, keine Fehlgewichtung möglich"]
ASSEMBLE --> OUT["Ergebnis"]
SINGLE --> OUT
```
### Warum kein LLM-Reduce mehr (Prompt-Lab 2026-07-16)
Der alte Reduce (Teil-Summaries → LLM baut EINE Gesamt-Summary) war die Fehlgewichtungs-Quelle. Im
Prompt-Lab auf #70 (temporärer `/api/debug/ask`-Endpoint, ~15 Varianten) scheiterte JEDE Synthese-Form
reproduzierbar: Gewichtungsregeln ignoriert (Auto-Smalltalk blieb im Titel), Namen durch Rollen ersetzt
(„Personalwesen"), Themen-Tabellen mit 4× demselben Eintrag, Repetitionsschleifen. **Abschnittsübergreifende
Synthese liegt jenseits von Gemma-3-4B** — Verstehen einzelner 4k-Abschnitte dagegen funktioniert gut
(Com4Tec, René, Tobi+Niklas, 20 Bewerbungen alle korrekt extrahiert). Also: LLM versteht, Code führt zusammen.
### Warum die Whole-Pass-Grenze bei 20 000 Zeichen bleibt (Modellgrenze, 2026-07-16)
Aufnahme #70 (26 min, 22,6k Zeichen ≈ 6 900 Token) lag knapp über der Grenze. Versuch, sie per
@@ -88,6 +98,10 @@ hatte alle im Gespräch *erwähnten* Namen als Teilnehmer gelistet (11 statt 3 b
| Typografische Anführungszeichen (“”„) als JSON-Delimiter, trailing commas | `extractJson()`-Sanitizer: erst strikt parsen, bei Fehler Quotes/Kommas reparieren und nochmal |
| Whole-Pass > ~6k Token: englisches Geplauber, Recency-Bias, JSON-Zerfall | `WHOLE_MAX_CHARS` 20 000 hart; End-Instruktion; Repair-Call; Sanity-Check (Zusammenfassung ≥ 20 Zeichen) → sonst Chunk-Fallback |
| Kopiert `...`-Platzhalter aus Schema-Beispielen wörtlich | End-Instruktion nennt nur Feldnamen, nie ein Skelett mit Platzhaltern |
| 8k-Chunk: Inhalt wird generisches namenloses Blabla (JSON trotzdem valide!) | Chunks à 4 200 Zeichen — dort bleibt der Inhalt geerdet mit echten Eigennamen |
| Echot Feldbeschreibung INHALTS-abhängig bei JEDEM Versuch (Auto-Abschnitt #70, 2× identisch) | Echo-Guard + bis 3 Versuche mit VARIIERTEM Prompt (ohne Kontext / ohne Hint) |
| `eigennamen`-Array degeneriert (Punkte-Loops, Junk-Tails), String-Felder intakt | Feld-Salvage per Regex holt zusammenfassung + Namen einzeln raus |
| Cross-Section-Synthese: Regeln ignoriert, Namen→Rollen, Themen-Dubletten | LLM-Reduce ABGESCHAFFT — Konglomerat baut deterministischer Code |
## Eigennamen-Glossar (Whisper hört z. B. „Aime“ als „Amy“)
+21
View File
@@ -3,6 +3,27 @@
Chronik der Entwicklungsschritte. **Regel: jede zukünftige Änderung bekommt hier einen Eintrag** (Datum,
Was, Warum, betroffene Dateien/Backups).
## 2026-07-16 — Sektions-Konglomerat statt LLM-Reduce (Abend, `.bak-sectionsum`)
Auftrag: Lang-Transkript-Summary (> 20k Zeichen) inhaltlich retten. Prompt-Lab auf #70 mit temporärem
`/api/debug/ask`-Endpoint (nach Abschluss wieder entfernt), ~15 Reduce-/Chunk-Varianten in je ~2 min
statt 9-min-Vollanalysen.
- **Befund 1: Chunk-Größe ist der Fidelity-Hebel.** 8k-Chunks → generisches namenloses Blabla; 4k-Chunks →
geerdete Summaries mit echten Eigennamen (Com4Tec, René, Tobi+Niklas, 20 Bewerbungen). `CHUNK_CHARS` 8000 → **4200**.
- **Befund 2: Cross-Section-Synthese unmöglich auf Gemma-3-4B.** Jede LLM-Reduce-Variante (Gewichtungsregeln,
Abschnitts-Labels, Themen-Tabellen) → Regeln ignoriert, Namen durch Rollen ersetzt, Dubletten, Loops.
**LLM-Reduce abgeschafft.**
- **Neue `analyzeLong`-Pipeline** (`llm.js`): 4,2k-Chunks sequenziell mit **Rolling Context** (1-Satz-
Kurzfassungen der Vorgänger → erkennt geänderte Entscheidungen: „jetzt X, vorher Y") + **eigennamen-
Extraktionsfeld**; Echo-Guard (Feldbeschreibungs-Echo ist INHALTS-abhängig reproduzierbar → bis 3 Versuche
mit variiertem Prompt: ohne Kontext, ohne Hint) + Feld-Salvage per Regex + Prosa-Rettung (≥ 60 Zeichen);
**Titel-Mikro-Call** ohne letzten Abschnitt (Smalltalk-Filter); **Konglomerat baut Code**: „Gesprächsverlauf
in n Teilen — genannte Namen: …" + „Teil i/n: …" chronologisch. Kap. 05 (Mermaid + Marotten aktualisiert).
- **E2E #70 (3 Läufe):** Titel ohne Auto-Smalltalk ✅, alle Abschnitte mit echten Namen ✅, Auto nur noch in
Teil 7 ✅, 12-14 min für 26-min-Aufnahme. Restgrenze: Abschnitts-Summaries variieren pro Lauf in Schärfe
(Sampling), keine thematische Verdichtung ÜBER Abschnitte (4B-Decke). ≤ 20k Zeichen weiter Whole-Pass.
## 2026-07-16 — #70-Debug: Phantom-Sprecher, Summary-Fehlgewichtung, Thermal-Leck (Nachmittag)
Auslöser: Aufnahme #70 (26 min, 4 Personen) — 7 Sprecher erkannt, Titel/Summary aus Randthemen