perf: Extractor-Prompt-Layout für Prefix-Cache (Messung ausstehend)#185
perf: Extractor-Prompt-Layout für Prefix-Cache (Messung ausstehend)#185TillQuandel wants to merge 2 commits into
Conversation
…es ans Ende (refs #147) Anthropic-Prompt-Caching matcht token-präfix-basiert. Bisher standen die source-sortierte Tag-Whitelist und die overlap-sortierte existing-Liste VOR dem statischen Instruktionsrest (inkl. komplettem Output-Format) — der cachebare Präfix endete dort, 41 % der Input-Seite war Cache-Neuanlage (Trace 2026-06-02, 129 Calls). - Template umsortiert: statischer Kern (Regeln + Output-Format) vorn, danach Quellen-Metadaten (lauf-konstant), dann alle call-variablen Blöcke (Whitelist, Konzepte, existing, background/related, task_hints, Chunk) — Blöcke inhaltlich unverändert, nur Position - Self-Refine-/Trunkierungs-Hinweise als task_hints ans variable Ende statt vorangestellt (Retry teilt jetzt den Präfix des Erst-Calls) - Layout-Wächter test_extractor_prompt_layout.py: Template-Ordnung, commonprefix zweier Fan-out-Prompts, Refine-Position, Retry-Präfix Messung (Vorher/Nachher am echten Lauf) folgt vor dem Merge.
Messläufe 2026-07-12 (Schlebbe 2022, je
|
| # | Stand | c= | Ergebnis | cache_report TOTAL |
|---|---|---|---|---|
| 1 | master (VORHER) | 2 | ✅ 490 s, 1 Konzept, 1 Extractor-Call | create 32,5 % |
| 2a | Branch | 2 | ❌ Planner-CLI-Timeout 300 s (fatal, timeout_retries=0) |
— |
| 2b | Branch (NACHHER) | 2 | ✅ 626 s, 2 Konzepte | create 37,3 % |
| 3 | Branch | 1 | ✅ 837 s, aber 1 von 2 Extractor-Calls starb am CLI-Timeout (non-fatal) | create 48,2 % |
Warum die Zahlen die Abnahme-Frage nicht beantworten:
- Schlebbe erzeugt keinen Fan-out. 1–2 geplante Konzepte → 1–2 Extractor-Calls. Der Umbau wirkt auf die Präfix-Wiederverwendung zwischen Fan-out-Calls — bei N≤2 gibt es strukturell keine zweite Welle, die profitieren könnte. (Der 41–47-%-Ausgangsbefund stammt vom 129-Call-Trace.)
MAX_CONCURRENT_CALLS=2erzeugt ein Cache-Race: In Lauf 2b starteten beide Extractor-Calls parallel — Call 2 las nur den Basis-Präfix (29.608 Tok) und legte den Extractor-Statikteil selbst neu an (create 46,2 %). Parallele Erst-Calls können einander per Design nicht cachen.- Lauf 3 (sequenziell) wurde vom CLI-Hänger entwertet: Call 1 = Timeout-Record (0 Tokens), Call 2 damit wieder Erste-Welle (create 45,9 %). Zwei 300-s-CLI-Timeouts in drei Läufen heute Nacht — transienter Umgebungsfaktor, auf master wie Branch unabhängig vom Diff.
- TOTAL-Werte zusätzlich verzerrt: Planner-Nichtdeterminismus (1 vs. 2 Konzepte) und Stage-8-Eval nur in den Branch-Läufen (eval_quality-Judges mit 49–61 % create ziehen den TOTAL hoch).
Einziger Like-for-Like-Punkt (Erste-Welle-Extractor-Call): master 18,9 % create vs. Branch 16,8 % — Richtung stimmt, N=1, nicht belastbar.
Label-Neutralität (Bedingung b): Branch-Läufe Hall 10,0 % / Cov 55,0 % (Lauf 2b) und Hall 9,1 % / Cov 77,3 % (Lauf 3) — im Rahmen der v0.3.140-Basiswerte (7,4 % / 77,8 %), aber je N=1; der VORHER-Lauf lieferte 0 Evals (Hash-Guard).
Vorschlag fürs Mess-Setup (Entscheidung Till): NACHHER-Lauf mit einem Fan-out-PDF (z. B. Porst-2014-Auszug: viele Konzepte → mehrere Wellen) bei c=2; ab Welle 2 muss create% pro Call einbrechen, wenn der Umbau wirkt. Als VORHER-Referenz kann der 129-Call-Alt-Trace (41–47 %) dienen — spart den teuren master-Lauf. Kein Merge-Vorschlag — Messpflicht bleibt offen.
(Läufe 1/2b/3: Traces 20260711-234656 / 20260712-000415 / 20260712-002220; RAM war 5,5–5,7 GB frei, kein RAM-Kill.)
Refs #147. DRAFT — Messpflicht vor Merge offen (2 Messläufe, siehe unten).
Was
task_hintsans variable Ende statt vorangestellt — der Retry teilt so den statischen Präfix des Erst-Calls (Cache-Read statt Neuanlage), Salienz bleibt (direkt vor dem Textabschnitt, „höchste Priorität"-Wortlaut unverändert).test_extractor_prompt_layout.py(4 Tests): Template-Ordnung aller 9 Platzhalter hinter dem statischen Kern;os.path.commonprefixzweier echter Fan-out-Prompts enthält den kompletten Kern; Refine-Hint-Position; Trunkierungs-Retry teilt den Präfix (End-to-End über den echten Retry-Pfad mit Capture-Fake).generative/tools/cache_report.py: aggregiert cache_read/cache_creation pro Agent aus einem Run-Trace.Warum
Anthropic-Prompt-Caching matcht token-präfix-basiert. Die zwei sortierten Blöcke vor dem statischen Rest beendeten den cachebaren Präfix früh — gemessen 41 % der Input-Seite als Cache-Neuanlage (Trace 2026-06-02, 129 Calls; per
cache_reportreproduziert: extractor 47,5 % im kleineren Schwester-Trace, TOTAL 44,6 %).Verifikation bisher
ruff format --check+ruff checkgrünAusstehend vor Merge (Messpflicht aus #147)
Zwei Messläufe waren heute Nacht zweimal RAM-gekillt (2 GB frei von 15,3 GB, bekanntes Muster: RAM-Commit-Druck stoppt ML-Hintergrundläufe; beide Läufe starben vor dem ersten LLM-Call — keine Quota verbraucht). Bei freiem RAM:
Gleiches PDF, gleiches Profil (Vorschlag: Schlebbe 2022). RAM-Vorbereitung (die zwei Kill-Ursachen): parallele Claude-Sessions vorher schließen (~2–2,5 GB je) und für die Läufe
ATOMIC_AGENT_MAX_CONCURRENT_CALLS=2setzen; Start erst bei > 4 GB frei — der ML-Load-Peak liegt bei ~1,5–2 GB (siehe #190). Abnahme: (a) extractor-create%deutlich runter (Erwartung: Creation nur noch ~erste Fan-out-Welle), (b) Eval-Stichprobe Label-Neutralität — Judge-Metriken (hallucination/coverage) des Nachher-Laufs im Rahmen des Vorher-Laufs (N=1-Stichprobe, kein A/B; Konzept-Nichtdeterminismus des Planners als Grenze dokumentiert).Nebenbefund
cache_reportam 06-02-Trace zeigt: critic (35,6 %), cross_reference (28,4 %), verifier (62,6 %) tragen dieselbe Prefix-Unordnung — Folge-Kandidat nach der Extractor-Abnahme, gleiche Umbau-Klasse.