← Eseje

Fable 5, Opus 4.8 i Sonnet 4.6: jak uczciwie porównać LLM na własnym kodzie

Kontrolowany eksperyment: Fable 5, Opus 4.8 i Sonnet 4.6 na jednym prompcie audytują rzeczywistą bazę kodu. Metodyka uczciwego porównania LLM na własnym projekcie.

7 min czytania
Fable 5, Opus 4.8 i Sonnet 4.6: jak uczciwie porównać LLM na własnym kodzie

Gdy wychodzi nowy model, zapowiedź odpowiada na pytanie „na ile jest lepszy na benchmarkach” — i nie odpowiada na jedyne pytanie, które mnie interesuje: co zmieni w mojej pracy. Przeprowadziłem kontrolowany eksperyment: trzy modele Claude — Fable 5, Opus 4.8 i Sonnet 4.6 — otrzymały dosłownie identyczne zadanie audytu bazy kodu tego bloga, każdy w izolowanej kopii repozytorium, z wcześniej uzgodnioną rubryką oceny. W artykule — sama metodyka, którą można powtórzyć na dowolnym projekcie, wyniki, a osobno — jak eksperyment dwa razy się zepsuł i czego to nauczyło.

Dlaczego benchmarki nie odpowiadają na moje pytanie

Publiczne benchmarki mają dwa problemy i oba są fundamentalne. Pierwszy — zanieczyszczenie danych: przykłady testowe przeciekają do zbiorów treningowych, a model częściowo „przypomina sobie” odpowiedzi zamiast rozwiązywać zadanie. To nie marginalne podejrzenie, lecz przedmiot całego kierunku badań: przegląd Xu i współautorów (2024) systematyzuje badania nad zanieczyszczeniem benchmarków, a przegląd EMNLP 2025 odnotowuje odpowiedź branży — przejście od testów statycznych do dynamicznie generowanych.

Drugi problem jest prostszy: benchmark mierzy nie moje zadanie. Nie potrzebuję modelu, który najlepiej rozwiązuje zadania olimpijskie. Potrzebuję modelu, który znajdzie rzeczywiste błędy w moim blogu na Laravelu, nie wymyśli nieistniejących i udowodni, że jego poprawka działa.

Z tego wynika prosta myśl: najlepszym stanowiskiem testowym do porównania modeli jest własny projekt. Jego kodu w takim zestawieniu nie ma w zbiorach treningowych, zadania na nim — to dokładnie te, za które płacę, a wyniki mogę sprawdzić ręcznie, bo znam ten kod.

Projekt eksperymentu: jeden prompt, trzy izolowane światy

Zadanie dla wszystkich trzech modeli było dosłownie identyczne — różniły się tylko nazwa gałęzi i folder wyników. Cztery fazy: audyt dwujęzycznego systemu artykułów bloga z dowodem każdego znaleziska w postaci файл:строка z cytatem kodu; wybór rozwiązań dla trzech głównych znalezisk z opisem kompromisów; implementacja jednej poprawki z autoweryfikacją; notatka o wynikach po rosyjsku i angielsku. Pełny cykl pracy inżynierskiej, a nie izolowane „pytanie-odpowiedź” — takie podejście zaleca również Anthropic: oceniać agentów na zadaniach z rzeczywistego produktu, według rubryki uzgodnionej przed uruchomieniem.

Trzy zasady uczyniły porównanie uczciwym:

Izolacja. Każdy model pracował w osobnym git worktree — własnej kopii katalogu roboczego z własną gałęzią. Modele fizycznie nie mogły zobaczyć wyników innych ani sobie przeszkodzić.

Ochrona przed halucynacjami — w samym prompcie. Kluczowa linia zadania: „wymyślone znalezisko (nieistniejący kod, błędna linia) jest gorsze niż brak znaleziska”. Bez tego bodźca model, którego prosi się o znalezienie problemów, ma skłonność, by je „znajdować” w każdym przypadku. Z nim — każde znalezisko musi przejść ręczną weryfikację.

Wyłączenie podpowiedzi z zaliczenia. W repozytorium leży CLAUDE.md, gdzie opisane są znane pułapki projektu — na przykład względne ścieżki do zasobów, które psują się na URL z prefiksem językowym. Wszystkie trzy modele czytają ten plik, więc takie znaleziska są „darmowe”: liczą się za staranność, ale nie za głębię.

Rubryka: oceniać tylko to, co można sprawdzić ręcznie

Przed uruchomieniem ustaliłem sześć osi po pięć punktów: dokładność audytu (ręczna weryfikacja próbki znalezisk według файл:строка), głębia (potwierdzone znaleziska, których nie ma w podpowiedziach), jakość rozumowania o kompromisach, kod i realność autoweryfikacji, jakość tekstu rosyjskiego i angielskiego, dyscyplina (zero pytań do człowieka, ani jedno naruszenie ograniczeń). Zasada ta sama co w dobrym code review: im mniej oś opiera się na guście, a więcej na weryfikowalnym fakcie, tym bardziej można jej ufać.

Jak wszystko zepsuło się za pierwszym razem

Pierwsze uruchomienie zrobiłem nieprawidłowo — i to okazało się najbardziej przenośną częścią eksperymentu. Otworzyłem trzy interaktywne sesje równolegle w tym samym folderze repozytorium. Po kilku minutach w drzewie roboczym leżały niezacommitowane zmiany, których nie dało się przypisać: wspólny checkout oznacza, że gdy jedna sesja robi git checkout -b, gałąź przełącza się u wszystkich trzech, a ich zmiany i commity się mieszają. Jedna z sesji dodatkowo zrobiła git stash i zgarnęła do niego wszystko po kolei — w tym moje własne pliki, niezwiązane z eksperymentem.

„Równoległe agenty AI w jednym folderze to nie równoległy eksperyment. To jeden wielki konflikt z trzema autorami.”

– wniosek, który kosztował mnie restart

Wyniki dwóch sesji trzeba było uznać za nieprzydatne: nawet gdyby dopracowali je do końca, nie mógłbym uczciwie powiedzieć, czyje poprawki oceniam. Drugie uruchomienie — już w izolowanych worktree — natrafiło na limity taryfy: dwa agenty padły na starcie, a trzeci zawiesił się, nadal wyglądając w interfejsie na „działający”. Diagnozę postawił system plików, a nie wskaźnik statusu: w ciągu dwudziestu minut w jego kopii roboczej nie pojawił się ani jeden plik. To druga przenośna lekcja: żywotność agenta sprawdza się po zmianach na dysku. Po restarcie wszystkie trzy modele przeszły pełny cykl w równych warunkach.

Wyniki: gdzie modele są takie same, a gdzie się różnią

Najważniejszy wynik — to, czego nie było: halucynacji nie ma u żadnego modelu. Ręcznie sprawdziłem po trzy i więcej znalezisk każdego — wszystkie cytaty i numery wierszy są dokładne co do znaku. Dla zadań audytu to główny próg zaufania i przeszli go wszyscy trzej.

Dalej zaczynają się różnice:

Fable 5 Opus 4.8 Sonnet 4.6
Potwierdzonych znalezisk 11 5 9
Nietrywialnych unikalnych 3 1 2
Samosprawdzenie poprawki render integracyjny na tymczasowej bazie, xmllint, atrybucja cudzego padniętego testu linter + render; złapał własny błąd tylko linter i lista tras
Tokeny / czas 164k / 21 min 101k / 12 min 131k / 12 min
Wynik według rubryki (z 30) 30 24 25,5

Różnice jakościowe są bardziej informatywne niż punkty. Opus 4.8 — jedyny, który nie zauważył zepsutego nagłówka Content-Type w sitemap (znaleźli go dwaj pozostali) i zostawił go we własnej poprawce; a do jego rosyjskiego tekstu przeciekło angielskie słowo — „и even путь к картинке”. Sonnet 4.6 zrobiła poprawną poprawkę, ale jej samosprawdzenie było deklaratywne: linter zamiast uruchomienia. Fable 5 wyróżniła się właśnie na samosprawdzeniu: odkryła, że php na mojej maszynie to nakładka na kontener docker zamontowany na katalog główny, przebudowała wszystkie sprawdzenia przez jednorazowe kontenery i przepuściła swoją poprawkę integracyjnie na tymczasowej bazie. Różnica między „zrobiłem” a „udowodniłem, że zrobiłem” — to właśnie najbardziej różnicująca oś dla zadań agentowych.

Jeszcze jeden użyteczny sygnał — konwergencja: wszystkie trzy modele niezależnie nazwały głównym znaleziskiem ten sam problem z sitemap. Kiedy niezależni audytorzy zbiegają się w znalezisku numer jeden, to tani odpowiednik zgodności międzyeksperckiej: problem prawie na pewno jest realny.

Sędzia spośród uczestników

Ocenę według rubryki przeprowadziła Fable 5 — ten sam model, który brał udział w porównaniu. To metodologiczna dziura i trzeba o niej mówić wprost: sędziowie LLM systematycznie zawyżają oceny własnym tekstom, przy czym skłonność jest tym silniejsza, im lepiej model rozpoznaje swoje teksty — pokazano to w pracy Panickssery i współautorów na NeurIPS 2024. Złagodzić obciążenie można na dwa sposoby i użyłem obu: po pierwsze, maksymalnie przesunąć rubrykę od osi gustu ku sprawdzalnym faktom — dokładność wierszy, kompletność poprawki, przeciekłe obcojęzyczne słowo nie zależą od sympatii sędziego; po drugie, wyraźnie zadeklarować konflikt i oddać sporne osie do krzyżowej weryfikacji innemu modelowi lub człowiekowi. Subiektywne osie mojego wyniku — jakość tekstu, jakość rozumowania — warto czytać z tą poprawką.

Ograniczenia uczciwości

Jeden przebieg na model — to n=1: różnice w jeden-dwa punkty nic nie znaczą, wierzyć warto tylko jakościowym przepaściom — przeoczonemu bugowi, głębi samosprawdzenia. Eksperyment mierzy trzy modele na jednym zadaniu w jednej domenie; „Fable 5 jest lepszy w ogóle” z niego nie wynika. I warto pamiętać o cenie: topowy model zużył 1,6 razy więcej tokenów i prawie dwa razy więcej czasu niż najbardziej oszczędny uczestnik, a jego token według cennika jest jeszcze droższy sam w sobie — dla regularnych zadań to ważki argument na rzecz prostszych modeli.

Co zabieram dla siebie

Metodyka sprowadziła się do krótkiej listy kontrolnej, która działa dla każdego projektu i każdych modeli:

  • Zadanie testowe — pełny cykl realnej pracy na własnym kodzie, a nie syntetyczna łamigłówka.
  • Jeden prompt dla wszystkich, izolacja przez osobne worktree, wyniki — w osobnych gałęziach.
  • W prompcie — wyraźna cena halucynacji: wymyślone znalezisko jest gorsze niż brak znaleziska.
  • Podpowiedzi dostępne wszystkim (dokumentacja, notatki w repozytorium) wyłącza się z zaliczenia głębi.
  • Rubryka jest ustalana przed uruchomieniem i opiera się na sprawdzalnych faktach, a nie na wrażeniu.
  • Próbkę znalezisk sprawdzać ręcznie; zgodność znalezisk numer jeden u niezależnych modeli — sygnał ich realności.
  • Sędzia-uczestnik — zadeklarowany konflikt: sporne osie oddawać do oceny krzyżowej.
  • Żywotność agenta sprawdzać po dysku, a nie po wskaźniku w interfejsie.

Bonus, którego nie było w planie: eksperyment zwrócił się sam. Trzy niezależne audyty znalazły w blogu realne problemy — od sitemap bez angielskich stron po martwe zapytania w kontrolerze — i dwie gotowe poprawki już leżą w gałęziach, czekając na przeniesienie do produkcji. Porównanie modeli na własnym kodzie, w odróżnieniu od czytania benchmarków, zostawia po sobie nie tylko opinię.

Źródła i punkty odniesienia