Anthillo /blog

Dwie AI, jeden dokument: jak recenzja adwersarska złapała błąd 45× w naszej analizie CDR

Anthillo Team

Sto stron dokumentu analizy, piąta rewizja, dwa tygodnie do telekonferencji z klientem — to moment, w którym najłatwiej przeoczyć błąd, bo czytasz własny tekst, nie kod. Dlatego przed wysyłką ostatniej wersji nie poprosiliśmy o recenzję kolegi z zespołu, tylko dwa niezależne modele AI — i oba, pracując osobno, wskazały te same dwie poważne usterki.

Kontekst: pipeline, który analizowaliśmy

Chodzi o prywatną sieć LTE450 obsługującą głównie urządzenia IoT/SCADA — liczniki energii, sterowniki, koncentratory telemetryczne — u spółki z grupy energetycznej. Pipeline odbiera z bram sieciowych binarne pliki „chargingowe”, dekoduje rekordy ASN.1/BER własnym parserem w C (zero-copy, zero-malloc, ~800 linii kodu), ładuje je do kolumnowej bazy analitycznej i utrzymuje kaskadę agregacji — godzinowe, dobowe, tygodniowe/miesięczne — orkiestrowaną w Apache NiFi. Docelowy wolumen rośnie z ok. 14 mln rekordów/dobę dziś do ok. 300 mln/dobę w perspektywie kilku lat.

Jedna liczba warta zapamiętania: nasz parser C osiągnął w benchmarku ok. 298 tys. rekordów/s, przy 75 tys. dla najszybszej alternatywy (Java z biblioteką jasn1) oraz 71 tys. i 54 tys. dla pozostałych dwóch wariantów (C z asn1c i ręcznie pisany parser Java). Decyzja architektoniczna zapadła na liczbach, nie na przeczuciu.

Dlaczego prosimy AI o recenzję własnej pracy

Faza analizy w projekcie tego typu kończy się dokumentem na ok. 100 stron, który przechodzi kilka rewizji z klientem — u nas pięć, w ciągu około pięciu miesięcy. Przy piątej rewizji tego samego tekstu inżynier czyta go inaczej niż za pierwszym razem: zna go na pamięć i przestaje kwestionować założenia z wersji pierwszej. Zamiast polegać wyłącznie na code review między ludźmi (który też robimy), przed wysyłką finalnej wersji poprosiliśmy dwa niezależne modele — Claude i Codex — o krytyczną recenzję tego samego dokumentu, z tym samym poleceniem: znajdź błędy i niespójności. Każdy dostał tekst osobno, bez wglądu w wynik drugiego, a wyniki zapisano w dwóch niezależnych raportach.

Ten sam błąd, znaleziony dwa razy

Obie AI, pracując niezależnie, trafiły na tę samą sprzeczność: w jednym miejscu dokumentu retencja tabeli agregatów dobowych była opisana jako 48 godzin, w innym — jako 3 miesiące. Wyglądało to jak literówka, ale przekładało się bezpośrednio na szacowanie zajętości dysku — parametr kluczowy dla działu infrastruktury klienta, bo licencja bazy analitycznej i budżet storage planowane są na lata do przodu. Przy założeniu 48h szacowany rozmiar tabeli pod koniec 2029 wychodził na ok. 1,7 GB. Przy realnej retencji 3 miesięcy — ok. 74–80 GB. Błąd rzędu 45× w jedną stronę.

Druga usterka, wskazana przez obie AI niezależnie, dotyczyła operacji MERGE ładującej dane wsadowe. Opis procesu w dokumencie deklarował idempotentność — ponowne uruchomienie tego samego zadania nie powinno zmieniać wyniku. Sam SQL robił coś innego:

merge_daily_aggregates.sql
MERGE INTO cdr_sessions_daily AS t
USING staging_hourly AS s
ON t.session_date = s.session_date
   AND t.apn_id = s.apn_id
WHEN MATCHED THEN UPDATE SET
    -- błąd: dodawanie do istniejącej wartości, nie nadpisanie
    record_count = t.record_count + s.record_count
WHEN NOT MATCHED THEN INSERT (session_date, apn_id, record_count)
VALUES (s.session_date, s.apn_id, s.record_count);

Przy jednorazowym uruchomieniu wynik jest poprawny. Przy powtórce — po awarii, po ręcznym re-runie, po catch-upie po przestoju transferu plików — liczba rekordów w agregacie się podwaja. To dokładne przeciwieństwo właściwości, którą dokument deklarował jako cechę systemu.

Wniosek. Dwa różne modele, uruchomione niezależnie na tym samym materiale, bez wglądu w swoje odpowiedzi, wskazały dokładnie te same dwie usterki. To nie dowód, że AI „rozumie” system — to dowód, że pewne klasy błędów (sprzeczność między dwoma fragmentami dokumentu, deklaracja właściwości niezgodna z kodem) są na tyle mechaniczne, że warto oddać je maszynie, zanim inżynier straci do nich dystans.

Codex poszedł głębiej: błąd logiki biznesowej

Poza dwiema wspólnymi usterkami Codex znalazł coś, czego Claude nie wskazał — błąd semantyczny w warunku zamykającym sesję. Dokument filtrował rekordy warunkiem causeForRecClosing = 17 (dokładne dopasowanie do jednej wartości), podczas gdy specyfikacja klienta sugerowała >= 17 — zakres kodów przyczyn, nie pojedynczą wartość. Różnica nie była kosmetyczna: w przykładowych danych zmieniała raportowaną liczbę zamknięć typu normalRelease z 4 na 2. To błąd, który nie objawia się jako literówka ani sprzeczność w tekście — trzeba było zestawić regułę biznesową z konkretną specyfikacją domenową, żeby go zauważyć. Wymagał więcej kontekstu niż porównanie dwóch akapitów i tylko jeden z dwóch modeli go złapał.

Co zostaje po stronie inżyniera

Żadna z dwóch AI nie zaproponowała priorytetu napraw ani nie oceniła ryzyka biznesowego względem terminu wysyłki do klienta — to wciąż decyzja zespołu. Obie recenzje trzeba było zweryfikować ręcznie: część uwag była kosmetyczna albo wynikała z niezrozumienia kontekstu dokumentu, nie z realnego błędu. Wdrożenie poprawek — zmiana MERGE-a na nadpisujący, ujednolicenie retencji, korekta warunku na >= 17 z dopisanym uzasadnieniem w dokumencie — zajęło zespołowi cztery dni i przeszło zwykły ludzki review przed wysyłką. Efekt: adwersarska recenzja dwóch modeli AI nie zastąpiła inżyniera, ale złapała dokładnie to, co najłatwiej przeoczyć przy piątej rewizji własnego tekstu — i zrobiła to, zanim zobaczył go klient.