Kalibracja i ewaluacja routingu Codexa#
English version: CODEX_EVAL_HOWTO_EN.md.
1. Co właściwie kalibrujesz#
Ta instrukcja dotyczy przede wszystkim agentic_routing_codex i implementacji w tym repozytorium opisanej podczas weryfikacji z 6–7 października 2026 r. Wartości i wyniki przytoczone poniżej są punktem odniesienia z tego przeglądu, nie gwarancją aktualności po kolejnych zmianach konfiguracji lub kodu.
Cel: poprawnie rozpoznać bieżący tryb pracy, a dopiero potem wybrać przypisany do niego model. Nie stroisz routingu pod nazwę konkretnego modelu generującego odpowiedź.
Są trzy niezależne mechanizmy:
- Reguły strukturalne i faza pracy — jawny tryb, Plan Mode, tytuł, kompaktowanie, wykonane narzędzia i ich wyniki.
- Heurystyki — punktacja słów, fraz i wyrażeń regularnych.
- Semantyka — podobieństwo embeddingów aktualnej czynności do opisów i przykładów trybów.
Do tego dochodzi opcjonalna pamięć fazy w Redisie.
Kolejność rozstrzygania:
jawny tryb
→ klasa żądania: tytuł / kompaktowanie
→ deklaracja Plan Mode
→ aktualna faza / wiarygodna pamięć fazy
→ heurystyki
→ embeddingi
→ fallback
→ mapowanie trybu na model
Ważne: jeśli zła decyzja zapadnie już w heurystykach, obniżenie progu embeddingów jej nie naprawi. Semantyka nie jest wtedy pytana.
Kalibracja w obecnym systemie nie oznacza trenowania ani fine-tuningu modelu embeddingowego. Oznacza dobór modelu embeddingowego, opisów, przykładów, parametrów indeksowania i progów akceptacji.
2. Do czego służą poszczególne konfiguracje i pliki#
| Plik / ustawienie | Rola |
|---|---|
llm_router_plugins/resources/routing/agentic_routing_codex.json |
Tryby Codexa, reguły, przykłady semantyczne, progi i mapowanie trybów na modele. |
tests/data/codex_routing_quality.json |
Zbiór żądań z oczekiwanymi trybami. Służy do pomiaru, nie jest automatycznie dodawany do indeksu embeddingów. |
tests/data/codex_routing_baseline.json |
Zamrożone wcześniejsze predykcje do porównań na wspólnych przypadkach. |
codex-routing-holdout-verification.json |
Zapisany wynik konkretnego replayu. To raport, nie konfiguracja. |
LLM_ROUTER_MODELS_CONFIG |
Konfiguracja modeli po stronie aplikacji routera: dostępność, dostawca, parametry obsługi itd. Nie definiuje przykładów do klasyfikowania trybów. |
simple_semantic.json |
Konfiguracja osobnego pluginu heurystycznego. Mimo nazwy nie wymaga embeddingów. |
semantic_biencoder.json |
Konfiguracja osobnego pluginu embeddingowego do ogólnego routingu. Nie zastępuje konfiguracji Codexa. |
agentic_routing_claude_code.json |
Konfiguracja innego pluginu, dla Claude Code. |
Zmiana semantic_biencoder.json nie kalibruje automatycznie Codexa. Współdzielony jest silnik embeddingowy, ale konfiguracje i warstwy decyzyjne są osobne.
Najważniejsze pola konfiguracji Codexa#
| Pole | Znaczenie |
|---|---|
embedding_model |
Model tworzący wektory; ścieżka lokalna lub identyfikator modelu. To nie model odpowiadający użytkownikowi. |
settings.trigger_model |
Alias uruchamiający plugin, domyślnie auto_codex. |
settings.fallback_mode |
Tryb wybierany, gdy żaden mechanizm nie rozstrzygnie, obecnie implement. |
codex_modes[].name |
Nazwa trybu, np. review. |
codex_modes[].model_name |
Model używany po wybraniu tego trybu. |
codex_modes[].description |
Opis znaczenia trybu, indeksowany semantycznie. |
codex_modes[].examples |
Przykłady czynności należących do trybu, indeksowane semantycznie. |
keywords, phrases, patterns, weights |
Sygnały dla heurystyk, a nie przykłady embeddingowe. |
settings.phase |
Reguły interpretacji czynności: komendy, narzędzia, ścieżki testów, zapowiedzi itd. |
settings.semantic |
Parametry indeksowania i akceptacji odpowiedzi semantycznej. |
settings.vector_store_path |
Opcjonalny katalog trwałego indeksu semantycznego. To nie pamięć sesji. |
Redis jest osobnym mechanizmem. Jego połączenie konfigurujesz niezależnymi zmiennymi ENV, nie dopisujesz danych połączenia do konfiguracji embeddingów ani nie korzystasz automatycznie z ustawień Redis dla auth.
3. Jak rozumieć score i similarity#
Punktacja heurystyczna#
Aktualne domyślne wagi:
keyword = 1
phrase = 2
pattern = 3
Można je zmieniać przez settings.heuristic_weights, a także nadpisywać wagę konkretnego słowa lub frazy.
Przykład składni pól pojedynczego trybu:
{
"keywords": ["pytest"],
"weights": {"pytest": 3},
"phrases": ["uruchom testy jednostkowe:4"],
"patterns": ["\\buruchom\\s+testy\\b"]
}
Nakładające się trafienia są deduplikowane: nie zakładaj, że wszystkie pasujące reguły zawsze się zsumują. Powtarzanie jednego słowa również nie nabija punktacji bez końca.
Akceptacja wymaga:
najlepszy score > 0
najlepszy score >= heuristic_min_score
najlepszy score > drugi score
najlepszy score - drugi score >= heuristic_min_margin
Aktualnie w konfiguracji:
heuristic_min_score = 3.0
heuristic_min_margin = 1.0
Dla heurystyk pole routing.similarity jest przeliczeniem:
similarity = score / (score + 1)
score = 3 → similarity = 0.75
To nie znaczy „75% szans, że tryb jest poprawny”.
Wynik embeddingowy#
Opisy i przykłady są zamieniane na znormalizowane wektory. Silnik porównuje je z wektorem żądania za pomocą podobieństwa kosinusowego.
Przy aggregation: "per_target_top_k":
- Wyszukiwane są podobieństwa wszystkich fragmentów indeksu.
- Dla każdego trybu wybierana jest taka sama liczba najlepszych fragmentów.
- Ich podobieństwa są uśredniane.
- Powstaje ranking trybów
all_scores.
Efektywna liczba fragmentów na tryb wynosi:
min(top_k, liczba fragmentów w najmniejszej klasie)
Dlatego top_k: 4 nie oznacza czterech trybów w wyniku. Oznacza do czterech najlepszych fragmentów na każdy tryb.
Akceptacja wymaga:
s1 >= threshold
s1 > s2
s1 - s2 >= min_margin
Gdzie s1 to wynik najlepszego trybu, a s2 — drugiego.
Obecne ustawienia:
{
"threshold": 0.44,
"min_margin": 0.005,
"aggregation": "per_target_top_k"
}
Przykłady:
| Najlepszy wynik | Drugi wynik | Decyzja przy obecnych progach |
|---|---|---|
0.62 |
0.54 |
Akceptacja: wystarczający wynik i przewaga. |
0.62 |
0.615 |
Odrzucenie: za mała przewaga. |
0.40 |
0.35 |
Odrzucenie: za niski wynik. |
0.62 |
0.62 |
Odrzucenie: remis. |
Kosinus 0.62 też nie oznacza 62% prawdopodobieństwa poprawności. Nie porównuj go bezpośrednio z heurystycznym 0.75 ani strukturalnym 1.0.
4. Co rzeczywiście trafia do embeddingów#
Indeks trybów zawiera:
- nazwę trybu i jego
description; - teksty z
examples.
Nazwy przypisanych modeli generujących nie są dowodem semantycznym. aux_title i compaction są rozstrzygane strukturalnie i nie uczestniczą w semantycznym rankingu głównych trybów.
Zapytanie semantyczne obejmuje osobno:
- intencję obecnego polecenia użytkownika;
- kontekst aktualnej fazy: ostatnią wypowiedź agenta i strukturalny opis czynności narzędzia.
Surowa treść odczytanego pliku albo wyniku narzędzia nie jest dodawana jako opis fazy. Dzięki temu temat pliku nie powinien zastępować informacji, co agent robi.
Sekcje intencji i fazy są embedowane oddzielnie, następnie ich wektory są uśredniane i normalizowane.
| Parametr | Co kontroluje |
|---|---|
intent_max_chars |
Limit znaków sekcji intencji; obecnie 2000. |
phase_max_chars |
Limit znaków sekcji fazy; obecnie 2000. |
classify_max_chars |
Osobny budżet parsera historii; nie jest wagą intencji względem fazy. |
chunk_size |
Rozmiar fragmentów indeksowanych opisów/przykładów; obecnie 256. |
chunk_overlap |
Nakładanie fragmentów; obecnie 64. |
top_k |
Liczba najlepszych fragmentów uwzględnianych na tryb; obecnie 4. |
Zwiększenie phase_max_chars nie jest bezpośrednim ustawieniem „daj fazie dwa razy większą wagę”. Zmienia ilość dostępnego tekstu.
5. Jak przygotować dobry zbiór do kalibracji#
Masz już tests/data/codex_routing_quality.json. Możesz użyć go jako punktu wyjścia, ale do mocniejszego pomiaru potrzebujesz większej liczby niezależnych sesji.
Minimalny przykład osobnego datasetu:
{
"schema_version": 1,
"cases": [
{
"id": "cal-review-001",
"split": "calibration",
"source_session": "session-cal-001",
"expected_mode": "review",
"ambiguous": false,
"input": [
{
"type": "message",
"role": "user",
"content": [
{
"type": "input_text",
"text": "Przejrzyj obsługę błędów tego modułu i opisz problemy. Nie zmieniaj plików."
}
]
}
]
},
{
"id": "holdout-review-001",
"split": "holdout",
"source_session": "session-holdout-001",
"expected_mode": "review",
"ambiguous": false,
"input": [
{
"type": "message",
"role": "user",
"content": [
{
"type": "input_text",
"text": "Oceń poprawność walidatora i wskaż ryzyka, bez przygotowywania poprawki."
}
]
}
]
}
]
}
Dla sekwencji faz dodajesz:
- wspólną wartość
sequence; - metadane
session_id,thread_id,agent_name,turn_idw polu przypadkumetadata; - rzeczywiste prefiksy historii: wywołania narzędzi, identyfikatory i wyniki;
- opcjonalne
payloaddla pozostałych pól żądania, np.tools, formatu odpowiedzi i metadanych Codexa.
Uwaga: pole przypadku metadata jest w replayu dokładane do client_metadata żądania. Jawny override trybu można zachować w payload.
Zasady etykietowania:
- Oczekiwany tryb wynika wyłącznie z informacji dostępnych przed decyzją.
- Etykieta opisuje bieżącą czynność, nie cały temat zadania.
- Historyczna decyzja routera nie jest automatycznie prawidłową etykietą.
- Pełna sesja należy albo do
calibration, albo doholdout— nie dziel prawie identycznych prefiksów między oba zbiory. - Rzeczywiście nierozstrzygalne przypadki oznaczaj
ambiguous: true; nie używaj tego do ukrywania błędów. - Usuń sekrety, ale zachowaj strukturę potrzebną do rozpoznania fazy.
Uwzględniaj trudne kontrasty, np.:
- dodanie mocka w kodzie produkcyjnym kontra pisanie testów;
- integracja z GitHub kontra analiza historii Git;
- opracowanie strategii testowania kontra uruchamianie testów;
- ocena kodu kontra przygotowanie poprawki;
- neutralny odczyt pliku po uruchomieniu testów;
- zmiana fazy
implement → test → debug → implement.
6. Jak uruchamiać evaluate#
Automatyczne strojenie i eval#
Skrypt Bash uruchamia całą procedurę (wymaga jq, Pythona z projektem i zależnościami [ml]):
bash scripts/codex-tune-eval.sh \
--python /sciezka/do/venv/bin/python \
--thresholds "0.40 0.44 0.48 0.52 0.56" \
--margins "0.001 0.005 0.02 0.05" \
--output-dir ./workdir/codex-tuning-01
Opcje --config, --dataset i --baseline pozwalają wskazać własne pliki; --help opisuje wszystkie opcje. Katalog wynikowy musi być nowy. Bez --output-dir powstaje nowy katalog codex-eval-* w repozytorium. Ścieżki podane przez użytkownika są względne do katalogu uruchomienia; skrypt można uruchomić z dowolnego katalogu.
Skrypt najpierw ocenia konfigurację wyjściową, potem każdą parę threshold/min_margin tylko na calibration. Wybiera najwyższą cascade.main_mode_accuracy, następnie mniej pominiętych i zbędnych przełączeń trybów, następnie wyższą mode_accuracy. Pełny remis zachowuje konfigurację wyjściową. Dopiero po zamrożeniu wyboru uruchamia holdout dla wyjściowej i wybranej konfiguracji. Nie trenuje embeddingów, nie poprawia przykładów ani nie stroi heurystyk.
Wyniki: selection.json (ranking kandydatów), selected-config.json, holdout-comparison.json, pełne raporty i osobne logi dla każdego replayu. Zachowuje kopie źródłowej konfiguracji i datasetu. Nie nadpisuje produkcyjnej konfiguracji ani nie wdraża zwycięzcy — przed wdrożeniem sprawdź także precision/recall, specjalne przypadki i regresje na holdout.
Każdy kandydat wykonuje rzeczywisty replay i ponownie ładuje model embeddingowy, więc domyślna siatka może być kosztowna. Błąd przerywa procedurę; log i częściowy raport pozostają do diagnozy. Do samej ewaluacji bez embeddingów użyj --no-semantic: pomija strojenie i raportuje warianty deterministyczne na obu zbiorach. Skrypt nie instaluje zależności i nie korzysta z produkcyjnego Redisa.
Poniższe komendy uruchamiasz z katalogu głównego repozytorium. python powinien wskazywać stabilny interpreter środowiska projektu w PyCharm.
Dla semantyki potrzebne są opcjonalne zależności:
python -m pip install -e '.[ml]'
To instrukcja instalacji dla Ciebie, nie zapis wykonanej instalacji. Wcześniejsza weryfikacja semantyki była zablokowana przez środowisko z Pythonem 3.11.0rc1; do tych pomiarów użyj kompatybilnego, stabilnego interpretera.
A. Punkt odniesienia bez embeddingów#
python -m llm_router_plugins.utils.routing.agentic_routing.codex.evaluation \
--config llm_router_plugins/resources/routing/agentic_routing_codex.json \
--dataset tests/data/codex_routing_quality.json \
--split calibration \
--no-semantic \
> codex-calibration-deterministic.json
Dostaniesz warianty deterministic i stateful.
B. Pomiar embeddingów na kalibracji#
python -m llm_router_plugins.utils.routing.agentic_routing.codex.evaluation \
--config llm_router_plugins/resources/routing/agentic_routing_codex.json \
--dataset tests/data/codex_routing_quality.json \
--split calibration \
> codex-calibration-semantic.json
Ten pomiar dodaje cascade i semantic_only.
C. Końcowy pomiar na holdout#
Po zakończeniu strojenia:
python -m llm_router_plugins.utils.routing.agentic_routing.codex.evaluation \
--config llm_router_plugins/resources/routing/agentic_routing_codex.json \
--dataset tests/data/codex_routing_quality.json \
--split holdout \
--baseline tests/data/codex_routing_baseline.json \
> codex-holdout-semantic.json
--split holdout jest domyślne, ale warto podawać je jawnie. --split all służy do diagnostyki całości, nie do wybierania progów na zbiorze kontrolnym.
Ważne zachowania evaluate#
- Czyta wskazany plik
JSON; nie stosuje normalnych override’ów konfiguracji routingu zENV. - Buduje świeży indeks w pamięci; nie korzysta z produkcyjnego trwałego indeksu.
- Nie wywołuje modeli generujących odpowiedzi.
- Nie korzysta z produkcyjnego Redisa. Pamięć odtwarza w izolowanym magazynie lokalnym na sekwencję.
- Bez
--no-semanticwymaga włączonej semantyki iaggregation: "per_target_top_k". - Błąd ładowania embeddingów lub lookupu ma przerwać pomiar, zamiast udawać poprawną ewaluację fallbacku.
Dlatego ustawienie progu przez ENV nie zmienia wyniku tego CLI. Do eksperymentu zapisujesz próg w pliku przekazanym przez --config.
7. Jak czytać warianty raportu#
| Wariant | Co mierzy |
|---|---|
deterministic |
Kaskadę bez embeddingów i bez pamięci sesji. |
stateful |
Kaskadę deterministyczną z odtwarzaniem pamięci fazy. |
cascade |
Kaskadę z embeddingami, ale bez pamięci sesji. |
semantic_only |
Embeddingi dla głównych żądań; dla tytułów i kompaktowania nadal routing strukturalny. |
Obecny evaluator nie raportuje osobnego wariantu „pamięć + semantyka”. Nie traktuj cascade jako kompletnej symulacji produkcji z włączonym Redisem.
semantic_only pomaga zobaczyć jakość samego rankingu. Nie jest „maksymalnym możliwym wynikiem”, bo celowo pomija część mocniejszych sygnałów strukturalnych.
Najważniejsze metryki#
| Metryka | Interpretacja |
|---|---|
mode_accuracy |
Udział poprawnych trybów w oznaczonych przypadkach. |
main_mode_accuracy |
Trafność dla głównej pracy, bez tytułów i kompaktowania. |
per_mode.precision |
Spośród wskazań danego trybu: ile było poprawnych? |
per_mode.recall |
Spośród przypadków wymagających danego trybu: ile wykryto? |
mode_confusion |
Wiersz: tryb oczekiwany; kolumna: tryb przewidziany. |
sources |
Która warstwa podejmowała decyzje. |
fallback_reasons |
Powody decyzji fallbackowych zapisane przez wariant. |
semantic_acceptance_rate |
Udział oznaczonych przypadków zakończonych przez źródło semantic; nie precision semantyki i nie udział akceptacji tylko wśród lookupów. |
special_cases |
Osobny wynik tytułów i kompaktowania. |
ambiguous_count |
Przypadki wyłączone z trafności z powodu niejednoznaczności. |
mean_routing_ms |
Średni czas replayu danego wariantu, nie pełna latencja produkcji. |
Przykładowo: wysoki recall test i niska precision test oznaczają, że testy są wykrywane, ale tryb przechwytuje też niepasujące zadania.
Dla sekwencji szczególnie ważne są:
unnecessary_switches— zmiana trybu, gdy oczekiwana faza się nie zmieniła;missed_switches— brak zmiany przy oczekiwanym przejściu;mean_switch_delay— opóźnienie wykrycia nowej fazy liczone w kolejnych żądaniach, nie w milisekundach;censored_switches— przejścia, dla których poprawnej fazy nie osiągnięto przed końcem dostępnego fragmentu.
Same poprawne liczby przełączeń nie dowodzą poprawnego wyboru trybów. Zawsze czytaj je razem z trafnością i macierzą pomyłek.
Nie wybieraj konfiguracji według model_accuracy. Jeżeli kilka trybów ma ten sam model, błędny tryb może wyglądać jak poprawny wybór modelu.
8. Praktyczna procedura kalibracji embeddingów#
Krok 1: zamroź punkt odniesienia#
Zapisz raport dla obecnej konfiguracji na calibration. Zachowaj konfigurację i dataset użyte w pomiarze.
Raport zawiera m.in. ich hashe w metadata. Dodatkowo zanotuj wersję kodu, rewizję wag embeddingowych i wersje zależności — hash konfiguracji nie wykryje podmiany plików modelu pod tą samą ścieżką.
Krok 2: sprawdź, gdzie powstały błędy#
Najpierw porównaj deterministic z cascade.
- Błąd ze źródła
heuristic→ poprawiaj heurystykę. - Błąd ze źródła
phase→ sprawdzaj reguły czynności i parser. - Błąd ze źródła
memory→ sprawdzaj metadane i cykl życia fazy. - Błąd semantyczny albo nierozstrzygnięty fallback → oglądaj ranking embeddingowy.
Przykład odczytu rankingów, jeśli masz jq:
jq '.records[]
| select(.ambiguous == false)
| select(.semantic_only.all_scores != null)
| {
id,
expected: .expected_mode,
selected: .semantic_only.mode,
source: .semantic_only.source,
margin: .semantic_only.margin,
ranking: .semantic_only.all_scores
}' codex-calibration-semantic.json
Nie oceniaj tylko końcowego trybu: implement może zostać poprawnie wskazany jako fallback, mimo że semantyka nie zaakceptowała żadnej klasy.
Krok 3: poprawiaj opisy i przykłady#
Dobre przykłady opisują czynność i granice trybu, a nie temat repozytorium.
Przykładowa różnica:
plan:
„Opracuj strategię testowania; na razie nie pisz testów.”
test:
„Dodaj testy jednostkowe walidatora i uruchom je.”
review:
„Oceń poprawność walidatora i opisz problemy bez edycji.”
implement:
„Dodaj walidację danych wejściowych w istniejącym module.”
Zalecenia:
- używaj reprezentatywnych sformułowań polskich i angielskich;
- dodawaj różne parafrazy, nie dziesiątki prawie identycznych zdań;
- opisuj rozróżnienia w
description; - nie wpisuj nazw preferowanych modeli jako wskazówek klasyfikacji;
- nie kopiuj przypadków
holdoutdoexamples; - unikaj dosłownego kopiowania promptów ewaluacyjnych także z kalibracji — używaj ich do identyfikacji brakujących kategorii sformułowań.
Jeżeli poprawna klasa regularnie jest druga w rankingu, samo obniżenie threshold zazwyczaj nie pomoże: nadal wygra zła klasa.
Krok 4: dobierz threshold i margin#
Po ustabilizowaniu opisów przetestuj niewielką siatkę wartości, np.:
threshold: 0.40, 0.44, 0.48, 0.52, 0.56
min_margin: 0.001, 0.005, 0.02, 0.05
To przykładowy zakres eksperymentu, nie zalecane optimum. Dla innego modelu embeddingowego sensowny zakres może być inny.
- Wyższy
threshold: zwykle mniej akceptacji, więcej fallbacków. - Niższy
threshold: więcej akceptacji, ale możliwe błędne pewne decyzje. - Wyższy
min_margin: odrzuca konkurujące klasy o podobnym wyniku. - Niższy
min_margin: akceptuje więcej przypadków granicznych.
Przykład utworzenia konfiguracji kandydującej:
jq '.settings.semantic.threshold = 0.55
| .settings.semantic.min_margin = 0.08' \
llm_router_plugins/resources/routing/agentic_routing_codex.json \
> codex-candidate.json
Następnie:
python -m llm_router_plugins.utils.routing.agentic_routing.codex.evaluation \
--config codex-candidate.json \
--dataset tests/data/codex_routing_quality.json \
--split calibration \
> codex-candidate-calibration.json
CLI nie ma osobnych opcji --threshold, --min-margin ani automatycznego strojenia. Parametry podajesz przez konfigurację.
Optymalizacja kosztu: gdy zmieniasz wyłącznie progi, ranking all_scores pozostaje ten sam. Możesz przesiewać pary progów offline na zapisanych rankingach, zamiast za każdym razem ładować model. Wybraną konfigurację potwierdź jednak rzeczywistym replayem całej kaskady.
Krok 5: dopiero potem strojenie pozostałych parametrów#
Sprawdzaj oddzielnie:
top_k, np.1,3,5;- długości sekcji intencji i fazy;
chunk_sizeichunk_overlap;- inne modele embeddingowe.
Nie zmieniaj wszystkiego naraz — utracisz informację, co przyniosło poprawę.
Po zmianie modelu embeddingowego ponownie dobierz progi. Ten sam kosinus nie musi mieć takiej samej wartości diagnostycznej dla różnych modeli.
Krok 6: wybierz konfigurację według jakości, nie liczby akceptacji#
Priorytety:
- Mniej błędnych trybów w głównej pracy.
- Mniej zbędnych i pominiętych przełączeń.
- Brak pogorszenia klas szczególnie istotnych.
- Brak regresji jawnych override’ów, Plan Mode, tytułów i kompaktowania.
- Akceptowalny koszt i czas routingu.
Mniej fallbacków nie oznacza automatycznie lepszego routingu. Zła decyzja semantyczna może być gorsza niż ostrożny fallback.
9. Jak kalibrować heurystyki#
Heurystyki stroisz osobno, zaczynając od raportu z --no-semantic.
Najczęstsze działania:
- usuń zbyt ogólne słowa przechwytujące niepasujące czynności;
- dodaj bardziej jednoznaczne frazy;
- zmniejsz wagę sygnału wieloznacznego;
- zwiększ
heuristic_min_margin, jeżeli konkurujące klasy mają podobne wyniki; - sprawdź lokalne negacje, np. „nie uruchamiaj testów”;
- uwzględnij pisownię z polskimi znakami i bez nich.
CodexModeScorer.rank_modes() udostępnia ranking z surowymi punktami i dopasowaniami SignalMatch. To właściwe miejsce do analizy „które słowo dodało punkty”. Raport CLI nie zawiera pełnego rankingu heurystyk.
Nie wszystkie tryby z konfiguracji są kandydatami heurystycznymi. W szczególności samo dopisywanie słów do plan nie zmienia go w heurystycznego zwycięzcę obecnej kaskady; planowanie ma sygnały strukturalne i ścieżkę semantyczną.
Po poprawce heurystyk ponów także pomiar z embeddingami — zmiana wcześniejszej warstwy zmienia zestaw żądań, które docierają do semantyki.
10. Jak potwierdzić wynik i wdrożyć konfigurację#
Po wyborze kandydata na calibration uruchom stary i nowy config na tym samym, niezależnym holdout. Porównuj nie tylko podsumowania, ale też konkretne utracone i odzyskane przypadki.
Jeżeli po obejrzeniu błędów z holdout zmieniasz konfigurację pod te błędy, zbiór przestaje być niezależnym sprawdzianem. Zachowaj go jako regresje i przygotuj nowy holdout.
Obecny korpus jest mały i był już analizowany podczas poprawek. Nadaje się do regresji, ale nie jest mocnym dowodem jakości na nowych sesjach.
Wdrożenie#
Przykład wyboru gotowego pliku konfiguracji:
export LLM_ROUTER_ROUTING_SEMANTIC_AGENTIC_CODEX_CONFIG=/sciezka/codex-candidate.json
Wybrane override’y produkcyjne:
export LLM_ROUTER_ROUTING_SEMANTIC_AGENTIC_CODEX_SEMANTIC_ENABLED=true
export LLM_ROUTER_ROUTING_SEMANTIC_AGENTIC_CODEX_SIMILARITY_THRESHOLD=0.55
export LLM_ROUTER_ROUTING_SEMANTIC_AGENTIC_CODEX_MODEL=/sciezka/do/modelu-embeddingowego
MODEL oznacza tu model embeddingowy. MODEL_TEST, MODEL_REVIEW itd. oznaczają modele generujące przypisane do trybów.
semantic.min_margin, aggregation oraz budżety sekcji nie mają obecnie osobnych override’ów ENV; ustawiasz je w JSON.
Zmiany są ładowane przy tworzeniu pluginu, więc wymagają jego ponownego utworzenia / restartu workerów.
Trwały indeks#
Jeśli używasz vector_store_path albo PERSIST_DIR, po zmianie:
- modelu embeddingowego;
- zestawu trybów;
- opisów lub przykładów;
- parametrów dzielenia tekstu na fragmenty;
zbuduj nowy indeks. Najbezpieczniej wskaż nowy, wersjonowany katalog. Aktualny silnik nie gwarantuje automatycznej invalidacji indeksu po każdej zmianie konfiguracji.
Sama zmiana threshold, min_margin, top_k lub budżetów zapytania nie wymaga ponownego embedowania opisów.
Indeks FAISS i pamięć w Redisie są niezależne. Nie czyść całego Redisa podczas kalibracji embeddingów.
11. Co mówi obecny raport#
W raporcie codex-routing-holdout-verification.json z wcześniejszej weryfikacji:
| Metryka | deterministic |
stateful |
|---|---|---|
| Trafność trybów | 26/35 = 74,3% |
29/35 = 82,9% |
| Trafność głównej pracy | 23/32 = 71,9% |
26/32 = 81,25% |
| Zbędne przełączenia | 2 |
0 |
| Pominięte przełączenia | 1 |
0 |
Recall review |
25% |
25% |
Recall plan |
33,3% |
33,3% |
To pokazuje poprawę dzięki pamięci na tych przypadkach. Nie pokazuje jakości embeddingów — w tych dwóch wariantach ich nie ma, a semantic_acceptance_rate wynosi 0.
Niski recall review i plan wskazuje obszary do diagnozy, nie automatycznie nakaz obniżenia progu. Najpierw sprawdź, czy błędny tryb pochodzi z heurystyki, czy poprawny tryb jest wysoko w rankingu semantycznym.
Dodatkowo obecny baseline ma niezweryfikowane historyczne pochodzenie. Używaj go jako zamrożonego snapshotu regresyjnego, nie jako dowodu wyniku „przed całą implementacją”. --baseline porównuje tylko wspólne, zgodnie oznaczone przypadki.
12. Skrócona kolejność pracy#
1. Sprawdź działający interpreter i model embeddingowy.
2. Przygotuj rozdzielone sesjami calibration i holdout.
3. Zapisz wynik obecnej konfiguracji bez semantyki.
4. Zapisz wynik obecnej konfiguracji z semantyką.
5. Ustal warstwę odpowiedzialną za błędy.
6. Popraw opisy / przykłady albo reguły właściwej warstwy.
7. Dobierz threshold i min_margin na calibration.
8. Sprawdź błędne tryby, precision/recall i przełączenia.
9. Potwierdź wybranego kandydata na niezależnym holdout.
10. Wdróż config i świeży indeks, sprawdź logi produkcyjne.
Najważniejsza zasada: stroisz poprawność bieżącego trybu pracy, nie wysoki similarity, niski fallback ani trafność nazwy modelu.