Skip to content

perf: Extractor-Prompt-Layout für Prefix-Cache (Messung ausstehend)#185

Draft
TillQuandel wants to merge 2 commits into
masterfrom
perf/147-extractor-prefix-cache
Draft

perf: Extractor-Prompt-Layout für Prefix-Cache (Messung ausstehend)#185
TillQuandel wants to merge 2 commits into
masterfrom
perf/147-extractor-prefix-cache

Conversation

@TillQuandel

@TillQuandel TillQuandel commented Jul 10, 2026

Copy link
Copy Markdown
Owner

Refs #147. DRAFT — Messpflicht vor Merge offen (2 Messläufe, siehe unten).

Was

  • Extractor-Prompt-Layout umsortiert: Statischer Instruktions-Kern (Regeln + komplettes Output-Format) vorn, danach Quellen-Metadaten (lauf-konstant), dann ALLE call-variablen Blöcke (source-sortierte Tag-Whitelist, Ziel-Konzepte, overlap-sortierte existing-Liste, background/related, task_hints, Chunk). Blöcke inhaltlich unverändert — nur Position; die F10-Tag-Regeln verweisen jetzt auf den Whitelist-Abschnitt unten.
  • Self-Refine- und Trunkierungs-Hinweise als task_hints ans 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).
  • Layout-Wächter test_extractor_prompt_layout.py (4 Tests): Template-Ordnung aller 9 Platzhalter hinter dem statischen Kern; os.path.commonprefix zweier 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).
  • Messwerkzeug 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_report reproduziert: extractor 47,5 % im kleineren Schwester-Trace, TOTAL 44,6 %).

Verifikation bisher

  • Kanonische Suite: 5650 passed, 3 skipped (Baseline 5646 + 4 Layout-Tests)
  • ruff format --check + ruff check grün
  • Layout deterministisch bewiesen (commonprefix-Tests) — unabhängig von der Live-Messung

Ausstehend 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:

# VORHER (auf master):
git checkout master
ATOMIC_AGENT_MAINTAINER=0 uv run python -m generative.orchestrator --source "<PDF>" --dry-run --fresh-run
uv run python -m generative.tools.cache_report   # neuester Trace

# NACHHER (auf diesem Branch):
git checkout perf/147-extractor-prefix-cache
ATOMIC_AGENT_MAINTAINER=0 uv run python -m generative.orchestrator --source "<PDF>" --dry-run --fresh-run
uv run python -m generative.tools.cache_report

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=2 setzen; 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_report am 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.

Tilltime added 2 commits July 11, 2026 00:55
…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.
…gent (refs #147)

Messwerkzeug für die #147-Abnahme. Validiert am Trace 2026-06-02:
extractor 47,5 % create-Anteil, TOTAL 44,6 % — Nebenbefund: critic/
verifier/cross_reference tragen dieselbe Prefix-Unordnung (Folge-Kandidat).
@TillQuandel

Copy link
Copy Markdown
Owner Author

Messläufe 2026-07-12 (Schlebbe 2022, je ATOMIC_AGENT_MAINTAINER=0) — Ergebnis: nicht abnahmefähig, Mess-Setup ungeeignet

Läufe:

# 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:

  1. 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.)
  2. MAX_CONCURRENT_CALLS=2 erzeugt 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.
  3. 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.
  4. 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.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants