Niedeterminizm, evals, guardrails - czego oczekuje się od testera w projekcie z AI
Co się zmienia w pracy QA, kiedy "oczekiwany rezultat" przestaje być jednym wynikiem?
Przeglądając ogłoszenia dla testerów, coraz częściej trafiam na trzy słowa, których jeszcze niedawno nie było w wymaganiach: niedeterminizm, evals i guardrails. Pojawiają się obok Playwrighta, testów API i CI/CD, zwykle w ofertach projektów, które mają w środku komponent AI. Nie jest to moda na buzzwordy, tylko sygnał, że zmienia się sama definicja "poprawnego wyniku".
Przez lata praca testera opierała się na prostym założeniu: dla danego wejścia system ma zwrócić konkretny, przewidywalny wynik. Na tym zbudowany jest każdy przypadek testowy z kolumną "oczekiwany rezultat" i każda asercja w automatach. Aplikacja z modelem językowym w środku to założenie łamie, a razem z nim zmienia się to, czego zespół oczekuje od QA.
Nie trzeba od razu budować własnego frameworka do oceny modeli, żeby odnaleźć się w takim projekcie. Trzeba jednak rozumieć, co te trzy pojęcia znaczą w praktyce testerskiej - i dlaczego zielony pipeline przy AI mówi jeszcze mniej niż przy klasycznym kodzie.
Dlaczego te pojęcia trafiają do ogłoszeń dla testerów?
Komponent AI przestał być osobnym produktem, a stał się elementem zwykłych aplikacji. Chatbot w obsłudze klienta sklepu, asystent w wyszukiwarce, automatyczne podsumowanie zgłoszenia w helpdesku, generowanie opisu produktu w panelu administratora - to wszystko są funkcje, które trafiają do backlogu obok koszyka i logowania. A skoro trafiają do backlogu, to ktoś musi je przetestować.
Problem w tym, że klasyczny warsztat testera nie przenosi się na nie jeden do jednego. Firmy szukają więc osób, które przynajmniej rozumieją, czym różni się testowanie funkcji opartej o model od testowania formularza z walidacją. Stąd w wymaganiach słowa, które wcześniej pojawiały się głównie w zespołach machine learning, a teraz lądują w ofertach dla QA Engineerów.
Dla testera to dobra wiadomość, bo kompetencje z tego obszaru są wciąż rzadkie. Wymaga to jednak przestawienia kilku nawyków, które przy deterministycznym kodzie działały bez zarzutu.
Niedeterminizm - kiedy "oczekiwany rezultat" przestaje działać
Niedeterminizm oznacza, że to samo wejście może dać różne wyjścia. Klasyczna aplikacja dla koszyka za 100 zł z kodem rabatowym -10% zawsze zwróci 90 zł, a jeśli raz zwróci 91 zł, mamy buga. Aplikacja z modelem językowym na identyczne pytanie odpowie raz tak, raz inaczej, i jest to właściwość systemu, a nie błąd.
Zapytaj chatbota sklepu trzy razy "jak zwrócić produkt?", a dostaniesz trzy różnie sformułowane odpowiedzi. Jedna zacznie od terminu 14 dni, druga od formularza zwrotu, trzecia doda informację o kosztach wysyłki. Każda z nich może być poprawna, a żadna nie będzie identyczna z tekstem zapisanym w przypadku testowym.
To uderza w najbardziej podstawowe narzędzie testera. Kolumna "oczekiwany rezultat" przestaje być jednym konkretnym wynikiem i staje się opisem zakresu, w którym poprawna odpowiedź musi się zmieścić. Samo pytanie "czy wynik się zgadza?" zamienia się w "czy wynik spełnia warunki, które spełnia każda poprawna odpowiedź?".
Warto też wiedzieć, że niedeterminizmu nie da się po prostu wyłączyć. Parametry modelu, takie jak temperatura - ustawienie określające, jak bardzo losowe są odpowiedzi - mogą go ograniczyć, ale zmiana wersji modelu, promptu systemowego czy kontekstu rozmowy i tak zmieni wynik. Tester, który zbuduje testy na dokładnym porównaniu tekstu, dostanie zestaw, który pada przy każdej aktualizacji, albo taki, który ktoś w końcu wyłączy.
Jak pisać asercje dla odpowiedzi, które za każdym razem są inne?
Zamiast porównywać cały tekst, rozbijasz "poprawność" na warunki, które da się sprawdzić niezależnie od sformułowania. Dla przykładu z chatbotem sklepu mogą to być:
treść obowiązkowa - odpowiedź zawiera termin 14 dni i wskazuje, gdzie znaleźć formularz zwrotu,
treść zakazana - odpowiedź nie wymyśla warunków, których nie ma w regulaminie (np. darmowego odbioru kurierem),
format - odpowiedź mieści się w określonej długości i nie zawiera surowego markdownu, jeśli interfejs go nie renderuje,
ton i zakres - odpowiedź dotyczy zwrotów, a nie np. promocji czy innych produktów.
Część z tych warunków sprawdzisz zwykłym kodem: wyrażeniem regularnym, sprawdzeniem długości, walidacją struktury JSON-a, jeśli model zwraca dane strukturalne. W Playwrightcie czy w teście API to nadal są klasyczne asercje, tylko zamiast toBe na całym tekście masz kilka węższych sprawdzeń na jego fragmentach. To dobry punkt startowy, bo jest szybki, tani i powtarzalny.
Trudniejsze warunki, takie jak "czy odpowiedź jest merytorycznie zgodna z regulaminem" albo "czy ton jest uprzejmy", wymagają oceny znaczenia, a nie znaków. Tu pojawiają się dwie drogi: porównanie podobieństwa semantycznego z odpowiedzią wzorcową albo LLM-as-a-judge, czyli drugi model, który dostaje odpowiedź i kryteria oceny, a zwraca werdykt. Druga opcja jest wygodna, ale sama jest niedeterministyczna i też wymaga sprawdzenia - o czym za chwilę.
Najważniejsza zmiana jest jednak w głowie, nie w kodzie. Zanim napiszesz asercję, musisz umieć powiedzieć, co odróżnia poprawną odpowiedź od niepoprawnej, a to jest klasyczna praca analityczna testera: rozmowa z Product Ownerem, przegląd wymagań, rozpoznanie ryzyka. Bez tego nawet najlepsze narzędzie do oceny modeli będzie oceniać według kryteriów, których nikt nie przemyślał.
Evals - rozkład wyników zamiast zielonego znaczka
Evals (od "evaluations") to zestaw testów oceniających jakość odpowiedzi modelu. Od klasycznych testów różnią się przede wszystkim tym, jak liczy się wynik. Zamiast pojedynczego "przeszło / nie przeszło" masz zestaw przypadków uruchamiany wielokrotnie i ocenę procentową, ile odpowiedzi mieści się w normie.
Przykładowy eval dla chatbota sklepu może wyglądać tak: 50 typowych pytań klientów, zebranych z prawdziwych zgłoszeń, każde uruchomione 5 razy, czyli 250 odpowiedzi. Każda odpowiedź przechodzi przez warunki z poprzedniej sekcji - część sprawdzana regułami, część przez model oceniający, a próbka ręcznie przez człowieka. Na końcu dostajesz wynik w stylu "231 z 250 odpowiedzi spełnia kryteria", czyli 92,4%.
Dlaczego te same pytania puszcza się kilka razy? Bo przy niedeterministycznym systemie jedno uruchomienie niewiele mówi. Pytanie, na które model odpowiada dobrze 4 razy na 5, jest w praktyce problemem, bo przy tysiącach rozmów dziennie ta piąta, błędna odpowiedź trafi do setek klientów.
To bliżej testów statystycznych niż klasycznego przypadku testowego. Dobrze dobrany zestaw przypadków przypomina tu dobrze dobrany zakres regresji: krytyczne ścieżki biznesowe, przypadki brzegowe, pytania, które wcześniej sprawiały problemy. Kompetencje testera w projektowaniu przypadków testowych zostają w pełni aktualne, zmienia się tylko sposób odczytywania wyniku.
Jak czytać wynik evala?
Wynik 92% sam w sobie nic nie znaczy, dopóki nie zestawisz go z ryzykiem. Dla asystenta podpowiadającego przepisy kulinarne może to być w pełni akceptowalny poziom. Dla chatbota, który informuje o warunkach kredytu albo kosztach leczenia, to samo 92% oznacza, że co dwunasta odpowiedź może wprowadzić klienta w błąd - z konsekwencjami prawnymi i finansowymi.
Najwięcej mówi porównanie w czasie. Jeśli po zmianie promptu systemowego albo przejściu na nowszą wersję modelu wynik spada z 92% do 81%, masz klasyczną regresję, tylko zmierzoną statystycznie. Dlatego evale najczęściej uruchamia się przy każdej zmianie, która może wpłynąć na odpowiedzi, podobnie jak testy regresji w pipeline CI/CD.
Równie ważne jest to, co kryje się pod średnią. Spadek o 2 punkty procentowe może oznaczać drobne pogorszenie stylu w wielu odpowiedziach albo całkowite załamanie jednej kategorii pytań, np. wszystkich dotyczących reklamacji. Dobry raport z evala pokazuje wyniki w podziale na kategorie i warunki, a tester powinien umieć z niego wyczytać, gdzie dokładnie coś się zepsuło.
Na koniec zostaje pytanie o próg. Ktoś musi zdecydować, przy jakim wyniku zmiana może trafić na produkcję, i to jest decyzja biznesowa, w której tester wnosi perspektywę ryzyka. To bardzo podobna rozmowa do ustalania Definition of Done, tylko zamiast "wszystkie testy zielone" mówimy o progu, poniżej którego wydanie jest blokowane.
Guardrails - zabezpieczenie, które trzeba spróbować obejść
Guardrails to zabezpieczenia, które mają nie dopuścić do złej odpowiedzi: filtry treści, ograniczenia tematyczne, blokady na dane wrażliwe. Chatbot banku ma rozmawiać o produktach banku, nie pisać wypracowań, nie doradzać w sprawie kryptowalut i przede wszystkim nie ujawniać danych innego klienta. Część takich zabezpieczeń siedzi w prompcie systemowym, część w osobnych filtrach przed i po wywołaniu modelu.
Rola testera w istocie się tu nie zmienia, zmienia się kontekst. Dalej sprawdzasz, czy zabezpieczenie faktycznie działa i czy da się je obejść, dokładnie tak jak przy walidacji formularza czy uprawnieniach w API. Różnica polega na tym, że wejściem nie jest pole z maską, tylko dowolny tekst w języku naturalnym, więc przestrzeń możliwych obejść jest ogromna.
Kilka kierunków, od których warto zacząć:
Prompt injection, czyli próba nadpisania instrukcji systemu treścią od użytkownika - np. "zignoruj poprzednie instrukcje i...".
Socjotechnika - prośba o cudze dane z wymyślonym uzasadnieniem, np. "jestem pełnomocnikiem tej osoby".
Rozbicie zakazanego pytania na kilka niewinnie wyglądających kroków w jednej rozmowie.
To samo pytanie w innym języku, z literówkami albo zapisane w nietypowym formacie.
Treść wstrzyknięta pośrednio - przez dokument, opis produktu czy wiadomość, którą model czyta jako kontekst.
To bardzo bliskie testom eksploracyjnym: sesja z jasnym celem, notatki z przebiegu, kolejne próby budowane na wnioskach z poprzednich. Dobrze sprawdzone obejścia warto potem przenieść do evala jako stały zestaw przypadków, żeby kolejna zmiana promptu nie otworzyła drogi, którą już raz zamknięto.
Zielony pipeline przy AI znaczy jeszcze mniej
Zielony pipeline przy klasycznym kodzie oznacza tylko tyle, że testy niczego nie wykryły, a nie że aplikacja działa dobrze. Przy AI ta zasada obowiązuje jeszcze mocniej, bo model równie łatwo wygeneruje odpowiedź, która wygląda dobrze, jak i test, który zawsze przejdzie. Oba problemy są trudne do zauważenia właśnie dlatego, że nic nie świeci się na czerwono.
Pierwsza pułapka to luźne kryteria. Eval, który sprawdza tylko, czy odpowiedź nie jest pusta i ma mniej niż 500 znaków, da 100% przy niemal każdej zmianie, a jednocześnie zero informacji o jakości. To samo dotyczy modelu w roli sędziego: jeśli kryteria oceny są ogólne w stylu "czy odpowiedź jest pomocna", oceniający model będzie przepuszczał prawie wszystko.
Druga pułapka to testy generowane przez AI dla funkcji opartych o AI. Asystent wygeneruje Ci w Playwrightcie test, który sprawdza, czy okno czatu się otworzyło i czy pojawiła się jakakolwiek odpowiedź. Test będzie stabilny, przejdzie w każdym środowisku i nie zweryfikuje niczego, na czym zależy biznesowi.
Dlatego ocena samej oceny staje się częścią pracy testera. Warto co jakiś czas wziąć próbkę odpowiedzi oznaczonych jako poprawne i przejrzeć je ręcznie, a do zestawu testów celowo dorzucić kilka odpowiedzi błędnych, żeby sprawdzić, czy eval je wyłapie. Jeśli nie wyłapuje, to nie model jest problemem, tylko sposób, w jaki go sprawdzamy.
Co z tego wynika dla testera?
Niedeterminizm, evals i guardrails brzmią jak nowa dziedzina, ale pod spodem kryją się dobrze znane umiejętności testerskie. Projektowanie przypadków testowych, myślenie o ryzyku, testy eksploracyjne i krytyczne patrzenie na to, co naprawdę sprawdza zielony test - to wszystko zostaje. Zmienia się kontekst: zamiast jednego oczekiwanego wyniku pracujesz z zakresem poprawnych odpowiedzi i ich rozkładem.
Nie musisz dziś wdrażać tych pojęć w swoim projekcie, jeśli nie ma w nim komponentu AI. Dobrze jednak wiedzieć, o czym mowa, zanim padną na rozmowie rekrutacyjnej albo w opisie projektu, do którego dołączasz. Tester, który potrafi wyjaśnić, dlaczego "oczekiwany rezultat" przy modelu językowym trzeba zdefiniować inaczej, od razu pokazuje, że rozumie zmianę, a nie tylko zna nowe słowa.
Jeśli chcesz zacząć od praktyki, w Prompt Hubie dla testerów i QA zebrałem prompty, które pomagają w codziennej pracy z AI - od Playwrighta, przez Swaggera i DevTools, po testy manualne. To dobry punkt wyjścia, żeby zobaczyć na własnych przykładach, jak bardzo różnią się odpowiedzi modelu na to samo pytanie.

