Run — Icking Pipeline-Handoff 2026-05-18

Zweck

Drei Auslieferungen am gleichen Tag:

  1. Eval-Bilanz der neu aufgesetzten Pipeline auf 51 Architekten-Queries — PDF mit AV-Design, an Christoph + Nicole gegangen.
  2. Technische API-Doku für Florian Schubert (Smart Dach) — als PDF mit eingebettetem API-Key, ebenfalls AV-Design, separat per Mail.
  3. POST /batch-Endpoint im inference-service vorbereitet (committed, noch nicht deployed) — für Florians 10–20-Query-Workloads.

Stand danach

BereichResultat
Pipeline-Qualität (51 expandierte LV-Queries)R@1 74,5 %, R@3 86,3 %, R@5 96,1 %, R@10 96,1 %, 0 HTTP-Fehler
Median-Latenz10,1 s (durch 3-RPM-Quota, Service wartet aktiv statt 500)
Quota-AnträgeCohere Rerank 3→250 RPM, Amazon Rerank 2→200 RPM, Haiku 4.5 RPM 10→10.000 — Support-Case offen
MailsAn Florian gesendet, an Nicole + Christoph als Draft → Marvin sendet selbst
Code/batch + Tests live als Task-Def Rev 10, Image :d81c9a8 (PR #6 nach main gemergt 19:35, Deploy 19:46)

Deploy-Erweiterung 2026-05-18 19:33–19:46 (/batch-Release)

Nach Audit-Pass + Marvin-Greenlight wurde das /batch-Drift-Problem beseitigt:

SchrittZeitErgebnis
Commit 05d5589 (Phase-5-Prep + Retry-Wrapper + 5 untracked Files)19:31Branch in Sync mit live Container
Merge origin/main → Branch (10ae88a, Konflikt in main.py trivial gelöst)19:33252 Tests grün, ruff sauber
PR #6 geöffnet19:34CI test-job pass in 16s
PR-Merge nach main (d81c9a8)19:35CI build+deploy startet
CI fertig (Run 26049775805)19:43ARM64-Image :d81c9a8 + Tags :main + :latest in ECR
Task-Def Rev 10 registriert19:45Image-Tag :d81c9a8 statt :phase4-final-retry
Service-Update + stable19:46Container läuft, alle Checks grün
Smoke-Test /search + /batch19:47200 OK, plausible Treffer

CI-Workflow-Lücke aufgedeckt: Der GitHub-Actions-Workflow (inference-service.yml) macht nach ECR-Push nur aws ecs update-service --force-new-deployment. Das startet einen neuen Task — aber mit derselben Task-Def-Revision, die auf einen statischen Image-Tag zeigt. Wenn der CI-Build neue Tags pusht (:main, :latest, :<sha>), aber der Task-Def auf :phase4-final-retry (statischer Tag) zeigt, wird Force-Deploy genau dasselbe Image neu starten. Resultat heute: nach erfolgreichem Merge + CI-Build lief /batch noch nicht — manuelle Task-Def-Revision 10 mit :d81c9a8 war notwendig.

Backlog für später: CI-Workflow erweitern um automatische Task-Def-Revision mit Commit-SHA-Tag. Pattern wäre aws ecs register-task-definition + --task-definition flag im update-service. Alternativ: Task-Def auf :latest umstellen und force-new-deployment reicht. Für heute: Rev 10 statisch ist Audit-fester, aber dann braucht jeder Deploy manuell eine neue Task-Def. Beide Wege sind valide, aktuell ist Rev 10 ein Einzelfall.

Eval-Methodik — sehr wichtig zu wissen

Die 96,1 % wurden NICHT auf Florians Original-Stichwort-Set gemessen. Sondern auf einer LLM-expandierten Variante davon (florian_long.jsonl). Vergleich:

Florians Original (data/eval/eval_set.jsonl)florian_long.jsonl (für diesen Run verwendet)
Cases5151 (gleiche lvp_ids)
Query Ø-Länge39 Zeichen107 Zeichen
Query #1"Baustelleneinrichtung""Pauschale für Baustelleneinrichtung, Vorhaltung von Maschinen, Geräten und notwendigen Absperrmaßnahmen"
Recall@10 (Phase-4-final)54,9 %96,1 %

Die Long-Queries sind ausformulierte LV-Position-Texte, vermutlich via Haiku aus den Stichworten generiert (im Result-File ist query_original als Florians Stichwort plus query als Long-Variante hinterlegt). Die Long-Queries sind oft Paraphrasen des Ziel-Catalog-Eintrags — Beispiel: Long-Query #1 vs Catalog-Eintrag 83278 ("Baustelleneinrichtung: Pauschale für Baustelleneinrichtung") — was die hohe Recall-Zahl maßgeblich erklärt.

Was die 96,1 % korrekt messen: wenn ein Bauleiter einen kompletten LV-Position-Text in die Suche tippt, findet das System den richtigen Catalog-Eintrag mit hoher Wahrscheinlichkeit in den Top-5.

Was die 96,1 % NICHT messen: Florians eigentliches Stichwort-Use-Case-Pattern ("Baustelleneinrichtung" → Catalog). Auf Stichworten liegt die Pipeline laut Phase-4-Bilanz bei ~55 % R@10.

In der Mail an Nicole + Christoph wurde der Eval-Set-Hintergrund nicht explizit gemacht („51 realistische Architekten-Anfragen”). Das ist nicht falsch — Architekten arbeiten mit LV-Texten — aber der Unterschied zu Florians Original ist wichtig für die nächste Eval-Runde mit echtem Florian-Material.

Reproduzierbarkeit der 96,1 %

Der Bake-Off-Run am 18.05.2026 zwischen 10:43 und 10:48 UTC ist über CloudWatch nachweisbar (Log-Group /ecs/inference-service-prod/app, 51 Search-Audit-Events von key_id 7c0a5657, alle 200 OK). Vollständige Reproduktion über:

ArtefaktPfad
Eval-Runner-Scriptassets/eval/pipeline_full.py
Eval-Set verwendetassets/eval/florian_long.jsonl + S3: s3://av-production-terraform-state/inference-service/bootstrap/eval_set_long_florian.jsonl
Per-Query Ergebnisseassets/eval/florian_long_results.jsonl (rank + latency + top1_id pro Case)
Run-Output mit Summaryassets/eval/full_run_retry.log
Charts (Quell-PNGs)assets/eval/charts_v2/{1_recall,2_rank,3_latency}.png
Report-HTML (Quelle der PDF)assets/eval/charts_v2/report.html
Live-Service zum Test-Zeitpunktinference.agenticventures.de, Task-Def Rev 9, Image :phase4-final-retry (seit 19:46: Rev 10, Image :d81c9a8, inhaltsgleich + /batch)

Re-Run gegen Florians ORIGINAL-Stichwort-Set steht aus — wird die echte Stichwort-Recall-Zahl ergeben (~55 % R@10 erwartet).

Architektur-Entscheidung dieser Session

Sync /batch statt async Polling-API. Die alte Lambda-Pipeline akzeptierte {queries: [...]} und gab job_id plus Status-Endpoint zurück. Der Wiederaufbau dieses Patterns hätte Job-State in der DB, Background-Worker und Cleanup-Cron bedeutet — eine Woche Code für einen Workflow, der nach Quota-Lift in 1–10 Sekunden synchron durchläuft. Stattdessen:

  • /batch nimmt 1–50 Queries, läuft intern sequentiell durch, gibt Array zurück
  • Per-Query-Errors brechen den Batch nicht (jede Query hat eigenen status: "ok"|"error" + optional retry_after)
  • Hard-Limit 50 schützt vor HTTP-Timeouts
  • Progress baut Florian client-side via Chunks von 10–20 Queries — pro Chunk weiß er „20 von 200 fertig”

Detailbegründung im Mail-Verlauf der Session (Marvin-Vorschlag „Florian soll nur die URL ändern” → realisiert mit minimaler Code-Anpassung bei Florian: kein Polling mehr, Response-Shape direkt auspacken).

Artefakte

Alle Files in assets/ dieses Run-Verzeichnisses:

DateiZweck
assets/eval-report.htmlHTML-Quelle der Eval-Auswertung
assets/icking-pipeline-auswertung.pdfGerenderter Eval-Bericht (7 Seiten, weißer Hintergrund, transparente Wortmarke)
assets/florian-api-doku.htmlHTML-Quelle der API-Doku
assets/florian-api-doku.pdfGerenderte API-Doku (9 Seiten, mit eingebettetem Bearer-Token)
assets/eval/pipeline_full.pyEval-Runner gegen Live-Service
assets/eval/florian_long.jsonl51-Case Eval-Set (LLM-expandiert aus Florians Stichworten)
assets/eval/florian_long_results.jsonlPer-Query rank + latency + top1_id
assets/eval/full_run_retry.logRun-Output mit finaler Summary
assets/eval/charts_v2/Charts + HTML-Report-Quelle + render_pdf.py
next-session-prompt.mdUrsprünglicher Session-Brief (enthält Pfad-Drift, siehe Drift-Notiz unten)

S3-Drift-Notiz: Der next-session-prompt.md referenziert s3://av-icking-eval-data/reports/2026-05-18/ als Parallel-Storage — dieser Bucket liegt im av-icking-Sub-Account, auf den Marvin aktuell keinen SSO-Zugriff hat. Die im Run verwendeten Files lagen daher ausschließlich in /tmp/ auf Marvins Maschine. Nach diesem Run wurden sie in assets/eval/ gesichert und florian_long.jsonl zusätzlich nach s3://av-production-terraform-state/inference-service/bootstrap/eval_set_long_florian.jsonl hochgeladen (av-production, nicht av-icking) — das ist die einzige reproduzierbare Quelle des Eval-Sets.

Mails

Beide aus hello@marvinkuehlmann.com versendet bzw. als Draft abgelegt:

  • An Florian Schubert (f.schubert@leistungen-dach.de) — gesendet. Inhalt: neue Pipeline-Version, Trefferquoten, Architektur-Hinweis (Lambda+APIGW → ECS), neue URL, API-Doku als Anhang, Quota-Lage erklärt.
  • An Nicole + Christoph Icking (N.Icking@leistungen-dach.de, cc c.icking@leistungen-dach.de) — Draft, Marvin sendet selbst. Inhalt: Eval-Bilanz, Phase-5-Hinweis als Aufpreis-Ankündigung, Vorschlag Vertrieb-Feedback einzuholen, HeyJulia-Vertragsentwurf-Frage angetriggert.

Was noch offen ist — Findings + Status nach Kritik-Pass

Strukturiert nach Sprengkraft. Audit dieser Session am 2026-05-18 Abend gegen den Stand am Mittag.

Hoch — vor Florians erstem API-Test klären

  1. /batch ist 404 in Production. GELÖST 2026-05-18 19:46. PR #6 gemergt, CI-Build durch (Run 26049775805, ~8min), Task-Def Rev 10 mit Image :d81c9a8 deployed. Smoke-Test grün: /healthz, /readyz, /search, /batch (2/2 succeeded) — alle OK. Florian-Doku stimmt jetzt mit Production überein.
  2. Re-Run gegen Florians Original-Stichwort-Set (data/eval/eval_set.jsonl) für eine ehrliche Stichwort-Recall-Zahl. Vor Florian-Feedback hinlegen damit du beide Zahlen bei der Hand hast: 96,1 % auf LV-Texten, ~55 % auf Stichworten.
  3. Branch-Drift im inference-service. GELÖST 2026-05-18 19:33. Untracked Files (_retry.py, query_understanding.py, Migration 005, enrich-Script, generate_long_eval-Script) + 11 uncommittete Diffs in einem Commit zusammengefasst (05d5589), Merge mit origin/main aufgelöst (10ae88a), via PR #6 nach main. Branch ist jetzt in Sync mit Production.

Mittel — strukturell, hat heute keinen externen Effekt

  1. AWS-Quota-Lift — Support-Case läuft (Cohere Rerank 3→250 RPM, Amazon Rerank 2→200 RPM, Haiku 4.5 10→10.000 RPM), 24–48 h erwartet. Bis dahin ist die in der API-Doku versprochene Latenz „<1 s” eine Annahme, gemessen 10,1 s p50.
  2. Score-Fusion-Gewicht wgr_consistency_weight=0.04 ist binär, nicht weight-tunable (Phase-4-Bilanz schreibt das selbst: identische Recall-Zahlen bei W=0.04 und W=0.08). Sollte als bool-Flag oder feste Konstante refactoriert werden, damit keiner versucht den Wert zu tunen.
  3. L7-Hypothese „aktuellerer Catalog-Stand, kein Absorber” ist Eigeninspektion ohne Florian-Validierung. Wenn falsch, dann hat Production einen systematischen Bias zu VELUX/Roto-Detailpositionen. Beim ersten Florian-Telefonat verifizieren.
  4. Migration 004 (catalog_cleanup_archived) ist lokal modifiziert + WIP, der archived IS NOT TRUE-Filter in hybrid.py ist im aktuellen Branch aktiv. Klären ob Migration in Prod-DB läuft und welche Catalog-Cleanup-Diffs deployed sind.
  5. Phase 5 (Catalog-Anreicherung mit strukturierten Attributen) vorbereitet, aber bewusst nicht aktiviert. Aktivierung erst nach Florian-Feedback aus realen LV-Texten — sonst optimieren wir am Büro-Tisch. ✓ richtig so.

Niedrig — wirtschaftlich + organisatorisch

  1. Pricing Pipeline noch offen — Audit hatte 2.500 EUR Festpreis für Refactor vorgeschlagen, Rebuild war deutlich mehr Aufwand. Mail an Nicole/Christoph nennt Phase-5-Aufpreis ohne dass Phase 1–4 vergütungsmäßig geklärt ist. Beim HeyJulia-Telefonat Mi/Do mit auf die Agenda, getrennt von HeyJulia.
  2. Alte Lambdas im Icking-Account laufen weiter — ~119 EUR/Monat idle, Cutover blockt auf SSO. Niemand weiß ob noch jemand auf die alte URL pointet. Sobald SSO frei → abschalten.
  3. av-icking-Sub-Account ist im Vault nicht dokumentiertnext-session-prompt.md referenziert Account 376761748837 mit S3-Bucket av-icking-eval-data. Bestätigen, ob das tatsächlich angelegt wurde (laut Vault-Konvention erst bei konkretem Workload), und ggf. intern/capabilities/aws/accounts.md nachziehen.
  4. Two-Key-Rotation TTL=120s blockt Sofort-Revoke — bei API-Key-Compromise (Florian-Side) 2 min Wartezeit minimum. ce:review-Backlog-Eintrag, nicht heute wichtig.
  5. Latenz-Claim „p50 400–800ms nach Quota-Lift” ist Annahme, nicht gemessen. Nach Quota-Increase mit echter Last validieren.
  6. HeyJulia-Vertragsentwurf — telefonisches Follow-up Mi/Do mit Nicole + Christoph. Separat von Pipeline-Pricing halten.

Cross-Refs

  • Projekt: _index
  • Phase-4-Plan: ~/source/a-icking/docs/plans/2026-05-14-003-feat-bedrock-rebuild-plan.md
  • HeyJulia-Schwester-Projekt: _index
  • Kunde: icking