homelab-codex-ws/jobs/documents-ingest/eval/queries.yaml

90 lines
3.7 KiB
YAML
Raw Normal View History

feat(kb): faza 3 krok 3 — kaskada retrieval summary→chunk, bramka PASS documents_ingest.retrieval: flat_query (baseline) i cascade_query (stage1 document_summary model='claude-haiku-4-5' -> stage2 document_chunk), jedno dzielone wywołanie embeddingu bge-m3 per zapytanie, tylko +1 SQL na kaskadę. Czyste query_text -> wyniki(dist, source) pod przyszłe kb-query fazy 4. 166/166 testów (10 nowych, mocki: stage1->stage2, koperta bez chunków, N > liczba kopert, no-summaries short-circuit). Eval-set utrwalony 1:1 z pilota (docs/kb/eval/retrieval-pilot-2026-07-16.md, nietknięty) w eval/queries.yaml + skrypt bramki eval/retrieval_eval.py (integracyjny, read-only, poza pytest). Wynik bramki (żywa baza, N=10 k=5): kryterium 1 (brak degradacji) PASS, kryterium 2 (hit@3 kaskada=5/5 vs płaski=5/5) PASS, kryterium 3 (kontrole negatywne 0.644/0.553 > 0.55 w obu torach) PASS. Sweep N∈{1,2,3,5,10,20}: N=5 to zmierzony próg bezpieczny (N<5 degraduje zapytania 3-4), N=10 ma 2x margines — potwierdza domyślną wartość z planu zamiast przyjmować ją z założenia. Kaskada nie poprawia jakości na 186-dok. korpusie (dystanse identyczne z płaskim przy N≥5) — zgodnie z przewidywaniem planu: to test architektury pod skalę mailową, nie optymalizacja pilota. Decyzja: kaskada (N=10, k=5, claude-haiku-4-5) = domyślna ścieżka retrievalu. Plan-doc §6.3 zaktualizowany wynikiem; §2 D3 zamknięte rozstrzygnięciem Oskara (tor kompilacyjny=claude-haiku-4-5, gemma3:12b w odwodzie, decyzja mailowa odłożona do reconu z flagą prywatności/kosztu). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-17 13:56:01 +02:00
# Eval-set for the retrieval quality gate (module 5, phase 3, plan §6.2,
# docs/kb/modules/05-faza3-plan.md). Transcribed 1:1 from the pilot baseline,
# docs/kb/eval/retrieval-pilot-2026-07-16.md (read-only source -- this file is the versioned
# copy the plan asked for, so the set stops living only in a session transcript).
#
# kind:
# hit -- pilot found a correct top-1 match (dist < 0.45)
# grey_zone -- pilot landed in the 0.45-0.55 band (on-topic, imprecise)
# negative_control -- pilot correctly found nothing (dist > 0.55)
# negative_control_borderline -- pilot correctly found nothing, but close to the 0.55 edge
#
# expected_envelope is null for both negative-control kinds: there is no document these
# queries should match, by design.
queries:
- id: "1"
text: "polisa ubezpieczeniowa PZU warunki odpowiedzialności"
kind: hit
expected_envelope: "paperless:14"
baseline_top1_dist: 0.3418
note: >
Pilot top-1 = paperless:14 (OWU PZU Auto); ujawnił duplikat paperless:14 ≡ paperless:74
(flagowany excluded_reason='duplicate' w kroku 1 fazy 3).
- id: "2"
text: "faktura za usługi telekomunikacyjne kwota do zapłaty"
kind: hit
expected_envelope: "paperless:192"
baseline_top1_dist: 0.3447
note: >
Pilot top-1 = paperless:192 (faktura P4); poz. 3/5 w pilocie był chunk z OCR-śmieciem
(kody kreskowe) -- powinien wypaść po excluded_reason='ocr_junk' z kroku 1.
- id: "3"
text: "zasady punktacji FLL Challenge robot game (PL)"
kind: grey_zone
expected_envelope: "paperless:5"
baseline_top1_dist: 0.4154
note: >
Pilot: szara strefa -- rodzina dokumentów OK, sedno (zasady punktacji) nie trafione
precyzyjnie. Kandydat na poprawę: czy pre-filtr po streszczeniu podnosi trafność?
- id: "4"
text: "FLL robot game mission scoring points table (EN)"
kind: hit
expected_envelope: "paperless:5"
baseline_top1_dist: 0.4114
note: >
Cross-lingual (EN zapytanie) trafia lepiej niż PL (zapytanie 3); poz. 2+ w pilocie =
paperless:119 (scoresheet, mojibake) -- mojibake nie jest śmieciem, niesie sygnał.
- id: "5"
text: "innovation project scoring"
kind: hit
expected_envelope: "paperless:3"
baseline_top1_dist: 0.3869
note: "Najlepszy wynik pilota: top-5 spójnie z jednego właściwego dokumentu (arkusz ocen IP)."
- id: "N"
text: "przepis na sernik z rodzynkami"
kind: negative_control
expected_envelope: null
baseline_top1_dist: 0.6210
note: "Poprawny brak w pilocie; separacja od trafień wyraźna."
- id: "N2"
text: "piaskownica plastikowa"
kind: negative_control_borderline
expected_envelope: null
baseline_top1_dist: 0.5533
note: >
Poprawnie na granicy "brak" w pilocie -- semantycznie sąsiednie dokumenty wspólnoty
mieszkaniowej, nie odpowiedź na zapytanie.
# Faza mailowa (docs/kb/modules/05-faza-mailowa-plan.md, §8, Krok 5) -- bramka jakościowa dla
# treści mailowej wprowadzonej w Etapie A (ostatnie 12 miesięcy, plan §7 Krok 4). PLACEHOLDER:
# operator ma dostarczyć 3-5 zapytań "wiem że to mam w mailach z ostatniego roku" +
# oczekiwany Message-ID (surowy, bez prefiksu "gmail:" -- envelope.id dla źródła gmail to
# bare Message-ID, np. "abc123@mail.gmail.com", inaczej niż "paperless:N" powyżej).
# Do czasu uzupełnienia ta lista jest pusta i retrieval_eval.py pomija kryterium hit@3 mailowe
# z jawną notatką w raporcie, zamiast fałszywie PASS/FAIL na braku danych.
#
# Format wpisu (identyczny co do pól z `queries:` powyżej):
# - id: "M1"
# text: "..."
# kind: hit
# expected_envelope: "<raw gmail Message-ID>"
# note: "..."
mail_queries: []