Działa w testach, nie działa na produkcji

przez Łukasz | sie 24, 2026

Objawy

Na prezentacji zadziałało dziesięć razy z dziesięciu. Po tygodniu na produkcji zgłoszenia sypią się co drugi dzień.

Zgłoszonego błędu nie da się odtworzyć — ten sam przypadek uruchomiony u ciebie kończy się poprawnie. Działa u ciebie, nie działa u klienta. Pierwsze dni były dobre, potem zrobiło się gorzej, choć nikt niczego nie zmieniał.

Objaw, który odróżnia to od cichej regresji: nic się nie zepsuło. Agent działa dokładnie tak, jak działał od początku — tylko teraz to widać.

Mechanizm w trzech zdaniach

Odpowiedzi modelu są niedeterministyczne, więc pojedynczy udany przebieg nie mówi nic o dziewięciu kolejnych. Do tego testy z natury sprawdzają przypadki typowe, a produkcja żyje w ogonie rozkładu.

Podłoże mechaniczne: sampling i niedeterminizm. Konsekwencje dla pomiaru: co logować w pętli.

Rachunek, który warto zrobić przed wdrożeniem

Zanim przejdziemy do przyczyn — jedna liczba, która tłumaczy większość rozjazdów.

Załóżmy, że agent wykonuje pojedynczy krok poprawnie w dziewięćdziesięciu pięciu procentach przypadków. Brzmi dobrze. Zadanie dziesięciokrokowe wykona bezbłędnie w około sześćdziesięciu procentach.

Przy skuteczności dziewięćdziesięcioprocentowej na krok — trzydzieści pięć procent na dziesięć kroków.

Testujesz zwykle pojedyncze kroki albo krótkie ścieżki. Produkcja wykonuje długie. To nie jest degradacja, tylko arytmetyka — i warto ją policzyć, zanim ktoś obieca klientowi dziewięćdziesiąt pięć procent.

Diagnostyka różnicowa

1. Testowałeś raz

Jak rozpoznać: ile razy uruchomiłeś każdy przypadek przed wdrożeniem? Jeśli raz — masz przyczynę.

Test: weź pięć przypadków „działających” i uruchom każdy dziesięć razy. Policz, ile razy wynik był poprawny. Ta liczba, nie wrażenie z demo, jest twoją realną skutecznością.

2. Testowałeś przypadki typowe

Jak rozpoznać: zgłoszenia dotyczą sytuacji, o których nikt nie pomyślał — pustych pól, dwóch zamówień o podobnym numerze, klienta z dwoma kontami.

Dlaczego to boli: przypadki testowe pisze się z głowy, a głowa produkuje przypadki reprezentatywne. Produkcja produkuje brzegowe.

3. Kumulacja błędu na trajektorii

Jak rozpoznać: krótkie zadania działają dobrze, długie sypią się nieproporcjonalnie.

Test: zestaw skuteczność osobno dla zadań o różnej liczbie kroków. Jeśli krzywa opada zgodnie z rachunkiem powyżej, to nie usterka, tylko granica architektury — i rozwiązaniem jest skrócenie trajektorii, nie poprawianie promptu.

4. Dane produkcyjne są brudniejsze

Jak rozpoznać: błędy skupiają się wokół konkretnych źródeł albo formatów.

Dlaczego to boli: dane testowe są sformatowane, pełne i po polsku. Produkcyjne mają literówki, załączniki, wklejone tabele, mieszankę języków i pola wypełnione „—„.

5. Skala ujawnia to, czego nie widać przy jednym przebiegu

Jak rozpoznać: błędy korelują z porami największego ruchu.

Dlaczego to boli: limity zapytań, timeouty, ponowienia i kolizje na współdzielonym stanie nie występują, gdy testujesz sam.

6. Środowisko się różni

Jak rozpoznać: ten sam przypadek działa lokalnie, nie działa na produkcji.

Dlaczego to boli: inne wersje bibliotek, inne wartości domyślne parametrów, inne uprawnienia, inny model pod tym samym aliasem.

Test: wypisz faktycznie wysyłane parametry wywołania po obu stronach i porównaj. Zaskakująco często różnią się temperaturą albo limitem tokenów.

7. Użytkownicy piszą inaczej niż zespół

Jak rozpoznać: przeczytaj dwadzieścia realnych zapytań z produkcji i porównaj ze swoimi przypadkami testowymi.

Dlaczego to boli: zespół pisze pełnymi zdaniami, zna nazewnictwo systemu i wie, czego agent nie potrafi. Użytkownik pisze „gdzie moja paczka” i wkleja numer bez prefiksu.

8. Testujesz to, co zbudowałeś

Jak rozpoznać: to przyczyna, której nie da się rozpoznać samodzielnie — na tym polega.

Dlaczego to boli: przypadki testowe piszą ci sami ludzie, którzy projektowali agenta, więc dziedziczą te same założenia. Jedynym wyjściem jest zestaw budowany z realnego ruchu, a nie z wyobraźni.

Postępowanie

Natychmiast: przestań testować pojedynczymi przebiegami. Każdy przypadek uruchamiany dziesięć razy, wynik raportowany jako odsetek. To zmiana metodologiczna na jedno popołudnie, która urealnia wszystkie dalsze pomiary.

Zbuduj zestaw testowy z logów, nie z głowy. Kilkadziesiąt realnych przebiegów z dopisanym oczekiwanym wynikiem. To najlepszy dostępny materiał — realne pytania, realne dane, realne przypadki brzegowe. I jest wolny od kontaminacji, bo nigdzie nie był publikowany.

Mierz rozkład, nie średnią. Interesuje cię, ile kosztuje i jak długo trwa najgorsze pięć procent przebiegów, bo to one generują zgłoszenia.

Oceniaj trajektorię, nie tylko wynik. Agent, który doszedł do właściwej odpowiedzi przez dwanaście kroków zamiast trzech, jest awarią czekającą na swoją kolej — o czym więcej w artykule o ewaluacji trajektorii.

Wdrażaj stopniowo. Kilka procent ruchu przez tydzień powie ci więcej niż miesiąc testów, bo dostarczy przypadków, których nie wymyślisz.

Nie obiecuj skuteczności z demo. Jeśli masz podać liczbę, podaj tę z dziesięciokrotnych powtórzeń na realnych przypadkach — i osobno dla zadań krótkich i długich.

Profilaktyka

Zestaw testowy z produkcji, uruchamiany cyklicznie, z wynikiem raportowanym jako odsetek z powtórzeń. Próg akceptacji zdefiniowany na percentylu, nie na średniej.

Ślad przebiegu wystarczająco bogaty, żeby zgłoszony błąd dało się odtworzyć bez proszenia użytkownika o szczegóły.

I świadomość granicy z rachunku powyżej: jeśli zadanie wymaga dwudziestu kroków, żadna poprawa promptu nie da ci dziewięćdziesięciu procent. Rozwiązaniem jest skrócenie trajektorii albo rozbicie zadania.

Jak zdiagnozować u siebie

Dwa narzędzia: kalkulator kumulacji i miernik stabilności.

python
import statistics as st
from collections import Counter

def kumulacja(skutecznosc_kroku, kroki):
    print(f"skuteczność {skutecznosc_kroku:.0%} na krok:")
    for n in kroki:
        print(f"  {n:2} kroków → {skutecznosc_kroku ** n:.0%} bezbłędnych przebiegów")

def stabilnosc(zestaw, uruchom, n=10):
    """zestaw: [(pytanie, oczekiwane)]; uruchom: pytanie -> wynik"""
    raport, niestabilne = [], 0
    for pytanie, oczekiwane in zestaw:
        wyniki = [uruchom(pytanie) for _ in range(n)]
        trafienia = sum(oczekiwane in str(w) for w in wyniki)
        udzial = trafienia / n
        raport.append(udzial)
        if 0 < trafienia < n:
            niestabilne += 1
            print(f"NIESTABILNY {udzial:.0%}  {pytanie[:50]}")
            for w, ile in Counter(map(str, wyniki)).most_common(2):
                print(f"    {ile}x  {w[:60]}")
        elif trafienia == 0:
            print(f"ZAWSZE ŹLE     {pytanie[:50]}")

    print(f"\nśrednia skuteczność: {st.mean(raport):.0%}")
    print(f"przypadki niestabilne: {niestabilne}/{len(zestaw)}")
    print(f"najgorszy przypadek: {min(raport):.0%}")

kumulacja(0.95, [1, 3, 5, 10, 20])
print()
kumulacja(0.90, [1, 3, 5, 10, 20])

Kalkulator uruchom najpierw — zajmuje sekundę i zwykle kończy dyskusję o tym, czy „dziewięćdziesiąt pięć procent” wystarczy przy zadaniach dwudziestokrokowych.

Miernik stabilności rozdziela trzy różne stany, które w pojedynczym teście wyglądają tak samo: zawsze dobrze, zawsze źle i niestabilnie. Ta trzecia kategoria jest najważniejsza, bo to z niej biorą się zgłoszenia niemożliwe do odtworzenia — i jedyny sposób, żeby ją zobaczyć, to powtórzenia.

Ćwiczenie: weź dwadzieścia przypadków, na których agent „działa”, uruchom każdy dziesięć razy i policz, ile z nich jest niestabilnych. Ta liczba jest twoją realną liczbą zgłoszeń na najbliższy miesiąc.

Koniec serii

Dziesięć syndromów, każdy z objawem, diagnostyką różnicową i postępowaniem.

Wracając do tego, od czego zaczynaliśmy: żaden z nich nie jest usterką, którą ktoś kiedyś załata. Wszystkie są przewidywalnymi trybami awarii systemów zbudowanych na modelach językowych — i wszystkie mieszczą się w warstwie, którą kontrolujesz.

Powtarzalne wnioski z całej dziesiątki są trzy. Mocniejszy model nie leczy przyczyny — maskuje objaw, który wróci przy trudniejszym przypadku. Prompt nie jest bramką — przesuwa prawdopodobieństwo, nie gwarantuje niczego. Nie ufaj deklaracjom, ufaj śladowi — źródłem prawdy o tym, co się wydarzyło, są wywołania, nie zdania w odpowiedzi.

Mechanizmy stojące za tymi awariami opisują dwie pozostałe serie: Anatomia LLM — co robi model i dlaczego akurat tak, oraz Maszyneria agenta — jak zbudować pętlę, która tego nie dopuszcza. Z czego agent składa się jako całość: Anatomia agenta AI.

A jeśli po lekturze dziesięciu trybów awarii nachodzi cię myśl, że w twoim przypadku wystarczyłby zwykły skrypt — to jest dobry wniosek i ma swój tekst: Kiedy nie budować agenta.

Agent kończy, ale zadania nie wykonał

Agent kończy, ale zadania nie wykonał

Objawy Agent odpowiada: „Przygotowałem i wysłałem potwierdzenie do klienta." Potwierdzenie nie zostało wysłane. Albo: „Zaktualizowałem wszystkie rekordy" — zaktualizował trzy z dwunastu. Albo: „Nie znalazłem żadnych zamówień" — bo narzędzie zwróciło błąd, którego nikt...

Agent zrobił coś, o co nikt nie prosił

Agent zrobił coś, o co nikt nie prosił

Objawy Operacja, której nikt nie zlecił. Dane wysłane pod adres, którego nie ma w żadnej konfiguracji. Rekord zmieniony poza zakresem zadania. Odpowiedź, z której wynika, że agent dostał instrukcje od kogoś innego niż ty. Cecha wspólna: technicznie wszystko zadziałało...

Agent zrobił to samo dwa razy

Agent zrobił to samo dwa razy

Objawy Ten syndrom różni się od pozostałych jedną rzeczą: objaw widzi klient, nie ty. Trzy identyczne wiadomości w skrzynce. Dwa zamówienia zamiast jednego. Podwójne obciążenie. Duplikaty rekordów, które ktoś zauważa tydzień później. W twoim dzienniku wszystko wygląda...

Agent gubi wątek w długim zadaniu

Agent gubi wątek w długim zadaniu

Objawy Pierwsze kroki idą wzorowo. Po kilkunastu agent zaczyna się rozjeżdżać. Przestaje przestrzegać reguły z promptu systemowego, której trzymał się na początku. Zmienia format odpowiedzi w połowie zadania. Wraca do czegoś, co już ustalił, i ustala to inaczej....

Agent podaje dane, których nie ma

Agent podaje dane, których nie ma

Objawy Numer zamówienia w idealnym formacie, którego nie ma w bazie. Kwota, której w dokumencie nie ma. Nazwa pola API, które nigdy nie istniało. Cytat z regulaminu, brzmiący dokładnie jak reszta regulaminu i w nim nieobecny. Cecha wspólna wszystkich tych przypadków:...

Działał wczoraj, dziś nie działa

Działał wczoraj, dziś nie działa

Objawy Nic się nie wywala. Nie ma wyjątków, nie ma timeoutów, dziennik wygląda tak samo jak zawsze. Po prostu odpowiedzi są gorsze. Postacie, w jakich to się objawia: Jakość. Agent zaczyna pomijać kroki, które wcześniej wykonywał, albo odpowiada ogólniej. Format....

Agent wybiera złe narzędzie

Agent wybiera złe narzędzie

Objawy Agent odpowiada nie na to pytanie. Pobiera listę zamówień, gdy pytano o jedno konkretne. Odpowiada z pamięci, choć miał sprawdzić w bazie. Albo sięga po właściwe narzędzie i wpisuje w argumenty coś, czego nie da się użyć. Sygnał, który odróżnia ten syndrom od...

Agent kręci się w kółko

Agent kręci się w kółko

Objawy Agent wykonuje kolejne obroty pętli, nie zbliżając się do zakończenia zadania. W dzienniku widać jedną z trzech postaci. Powtórzenie. To samo narzędzie, te same argumenty, raz za razem — czasem dziesiątki razy pod rząd. Oscylacja. Agent wywołuje na przemian dwa...

Co logować w pętli agenta

Co logować w pętli agenta

W drugim artykule padło, że pętla powinna zwracać nie samą odpowiedź, lecz odpowiedź razem z powodem zakończenia, liczbą kroków i zużytym budżetem. To był zalążek. Tu jest pełna wersja. Typowy dziennik agenta zapisuje pytanie i odpowiedź. To akurat najmniej użyteczna...