SSD Nodes Learn 🎉 VPS od $5.50/mies.
Przewodniki Matt ConnorAutor: Matt Connor · Zaktualizowano 2026-08-13

Jak wdrożyć własne ewaluacje dla agentów AI

Zbuduj system testowy dla agentów AI w oparciu o Python i SQLite. Dowiedz się, jak automatycznie śledzić spadek wskaźnika zaliczeń przy każdym commicie bez zewnętrznych usług.

Czym są samodzielnie hostowane ewaluacje dla agentów AI

Samodzielnie hostowane ewaluacje dla agentów AI to cztery elementy przechowywane we własnym repozytorium: plik z zapisanymi przypadkami testowymi, skrypt uruchamiający agenta dla tych przypadków, zestaw kontroli oceniających każdą odpowiedź oraz tabela wyników, którą można przeszukiwać. Żaden z tych elementów nie wymaga zewnętrznego dostawcy. Cała pętla to zaledwie kilkaset linii kodu w Python i jeden plik SQLite.

Agent działał w wersji demonstracyjnej, ponieważ samodzielnie wybrano pięć danych wejściowych. Przestał działać w drugim tygodniu, ponieważ zmieniła się linia promptu, model lub opis narzędzia, a żadna metryka tego nie wychwyciła. Pętla ewaluacyjna zmienia subiektywne odczucie „działa gorzej” na konkretną informację: „wskaźnik zaliczeń spadł z 58 na 60 do 51 na 60 w commicie 4f1c9ab”.

Pętla składa się z czterech kroków, a niniejszy przewodnik poświęca każdemu z nich jedną sekcję: zbieranie rzeczywistych śladów (traces), promowanie interesujących przypadków do zestawu testowego, ocenianie każdego przypadku przy każdej zmianie oraz zapisywanie wskaźnika zaliczeń obok commita, który go wygenerował. Ta sama pętla działa niezależnie od tego, na czym uruchamiasz agenta, a warstwy agentowe typu self-hosted warte uwagi różnią się głównie tym, jak dużą część śladu udostępniają automatycznie.

Dlaczego agent przestaje działać w drugim tygodniu

Agent to prompt, model, zestaw definicji narzędzi oraz kontekst pobierany w czasie wykonywania. Wszystkie cztery elementy mogą ulec zmianie bez modyfikacji kodu aplikacji, dlatego standardowy przegląd kodu nie wykazuje żadnych nieprawidłowości.

Najczęstszą przyczyną jest edycja promptu. Dodanie jednego zdania w celu wyeliminowania nieuprzejmych odpowiedzi zmienia zachowanie w przypadku danych wejściowych, które nie zostały ponownie przetestowane. Ślady (traces) wyraźnie to pokazują: ślad dla tego samego pytania z zeszłego tygodnia zawiera wywołanie narzędzia create_refund, natomiast w tym tygodniu go brakuje, a odpowiedź jest uprzejmą odmową. Żaden błąd nie został zgłoszony, więc alert nie został wyzwolony.

Drugą przyczyną jest model. Należy rejestrować dokładny ciąg znaków modelu wysyłany przy każdym uruchomieniu, claude-haiku-4-5-20251001, zamiast używać skrótów pamięciowych. Spadek wskaźnika poprawności w dniu zmiany modelu można zdiagnozować tylko wtedy, gdy nazwa modelu jest zapisana w wierszu danych.

Trzecią przyczyną są narzędzia. Zmiana opisu narzędzia wpływa na decyzję modelu o jego wywołaniu. Jeśli narzędzia są dostarczane przez serwery MCP działające na VPS, schemat znajduje się w innym procesie i może ulec zmianie bez żadnych różnic w repozytorium. Czwartą przyczyną jest pobieranie danych: to samo pytanie trafia do indeksu, który został przebudowany w nocy, a odpowiedź jest zgodna z nowym dokumentem.

Budowa złotego zestawu na podstawie zebranych śladów

Nie twórz przypadków testowych od zera. Pozyskaj je z ruchu sieciowego. Jeśli korzystasz już z własnej instancji Langfuse do śledzenia agenta, każde żądanie jest zapisywane wraz z danymi wejściowymi, wywołaniami narzędzi oraz danymi wyjściowymi. To dokładnie ten surowy materiał, którego potrzebuje przypadek testowy.

Wyeksportuj okno czasowe obserwacji głównych (root observations) za pomocą publicznego API. Wykorzystuje ono uwierzytelnianie podstawowe (basic authentication), gdzie klucz publiczny pełni rolę nazwy użytkownika, a klucz tajny rolę hasła.

export LF_HOST="https://langfuse.example.com"
curl -sS -u "$LF_PUBLIC_KEY:$LF_SECRET_KEY" \
  "$LF_HOST/api/public/v2/observations?limit=50&isRootObservation=true&fromStartTime=2026-07-01T00:00:00Z" \
  | jq '.data[0]'

Odczytaj jeden rekord przed przystąpieniem do parsowania. Wiersze zwracane są wewnątrz data, jednak nazwy pól zawierające pytanie i odpowiedź zależą od sposobu instrumentacji spanów w agencie. Odwzoruj strukturę, którą faktycznie widzisz, zamiast polegać na założeniach. Następnie przygotuj przypadki ręcznie, umieszczając jeden obiekt JSON w każdym wierszu pliku evals/cases.jsonl:

{"id": "refund-double-charge", "tags": ["smoke"], "input": "I was charged twice for order 41822.", "must_call": ["lookup_order", "create_refund"], "must_not_include": ["I cannot help"], "rubric": "The reply confirms exactly one refund for order 41822 and states the amount."}

Pięć zasad zapewnia użyteczność zestawu:

  • Od 40 do 80 przypadków wystarczy na początek. Poniżej 20 przypadków jeden niestabilny test zmienia wskaźnik powodzenia o 5 punktów procentowych, co sprawia, że wynik skaczący bez wyraźnego powodu jest ignorowany.
  • Każdy naprawiony błąd produkcyjny staje się przypadkiem testowym w dniu naprawy. Ten nawyk sprawia, że zestaw rozwija się w odpowiednim kierunku.
  • Jedno zachowanie na przypadek. Przypadek sprawdzający jednocześnie kwotę zwrotu i ton wypowiedzi nie dostarcza użytecznych informacji w razie awarii.
  • Pole id nigdy nie ulega zmianie, ponieważ identyfikator służy do porównywania wyników dzisiejszego uruchomienia z wynikami z poprzedniego miesiąca.
  • Dokonaj redakcji przed zatwierdzeniem zmian. Plik ten trafia do repozytorium git, dlatego usuń nazwiska klientów oraz wszelkie numery zamówień, których nie jesteś właścicielem.

W pierwszej kolejności należy przeprowadzić testy deterministyczne, ponieważ są one bezpłatne

Wszystkie elementy posiadające jednoznaczną poprawną odpowiedź powinny być weryfikowane za pomocą prostych asercji. Eliminuje to potrzebę wywoływania modelu, generowania kosztów oraz usuwa niejednoznaczność. Testy deterministyczne wykrywają regresje strukturalne, które najczęściej powodują awarie systemów współpracujących z agentem: błędy parsowania JSON, brak wywołania narzędzia, pojawienie się zabronionej frazy lub brak cytowania źródeł w odpowiedzi.

Tylko jedna funkcja posiada wiedzę o strukturze agenta. Cała reszta środowiska testowego jest generyczna.

import json, os, urllib.request

def run_agent(case):
    req = urllib.request.Request(
        os.environ["AGENT_URL"],
        data=json.dumps({"input": case["input"]}).encode(),
        headers={"content-type": "application/json"},
    )
    with urllib.request.urlopen(req, timeout=120) as resp:
        return json.load(resp)


def deterministic(case, result):
    text = result.get("output", "")
    called = [c["name"] for c in result.get("tool_calls", [])]
    failures = []
    for tool in case.get("must_call", []):
        if tool not in called:
            failures.append(f"tool not called: {tool}")
    for phrase in case.get("must_not_include", []):
        if phrase.lower() in text.lower():
            failures.append(f"forbidden phrase: {phrase}")
    if len(called) > case.get("max_tool_calls", 12):
        failures.append(f"too many tool calls: {len(called)}")
    return failures

Należy uwzględnić budżet wywołań narzędzi w tej liście. Agent, który rozwiązuje sprawę w 3 wywołaniach dzisiaj, a w 11 jutro, wykazuje regresję nawet wtedy, gdy końcowa odpowiedź jest poprawna, ponieważ każde wywołanie generuje koszty.

LLM jako sędzia i cztery sposoby, w jakie zawodzi

Wszystko, co przejdzie asercje, wymaga weryfikatora, który analizuje treść. Sędzia LLM to drugie wywołanie modelu: otrzymuje pytanie, odpowiedź agenta oraz jedno kryterium, a następnie zwraca werdykt. Jest to jedyny praktyczny sposób na ocenę, czy odpowiedź faktycznie odnosi się do tego, o co zapytał użytkownik.

Cztery zasady czynią sędziego użytecznym:

  • Werdykt binarny, nigdy skala od 1 do 10. Skala zwraca 7 lub 8 dla niemal wszystkiego, więc wynik się nie zmienia i niczego nie wnosi.
  • Jedno kryterium na wywołanie. Pytaj o kwotę zwrotu lub o ton wypowiedzi, nie o obie te rzeczy naraz.
  • Dostarcz sędziemu oczekiwaną odpowiedź, jeśli dany przypadek ją posiada. Ocenianie względem wzorca jest znacznie łatwiejsze niż ocenianie w sposób abstrakcyjny.
  • Wymuś format wyjściowy i analizuj go rygorystycznie.
from anthropic import Anthropic

client = Anthropic()  # reads ANTHROPIC_API_KEY from the environment


def judge_prompt(case, output):
    return (
        "You grade one answer against one criterion.\n"
        "Reply with JSON only, in this exact shape:\n"
        '{"verdict": "pass", "confidence": "high", "reason": "one short sentence"}\n'
        f"Criterion: {case['rubric']}\n"
        f"Question: {case['input']}\n"
        f"Answer: {output}\n"
        "Length is not a criterion. Judge only the criterion above."
    )


def judge(case, output, model):
    msg = client.messages.create(
        model=model,
        max_tokens=200,
        messages=[{"role": "user", "content": judge_prompt(case, output)}],
    )
    return json.loads(msg.content[0].text)

Oto tryby awarii. Każdy z nich posiada test, który można przeprowadzić jeszcze dziś. Wykonywanie tych testów jest istotne, ponieważ niesprawdzony sędzia generuje liczby, które wyglądają na precyzyjne, a w rzeczywistości nic nie znaczą.

Stronniczość długości. Dłuższe odpowiedzi przechodzą częściej. Przetestuj to: weź dziesięć odpowiedzi, które sędzia odrzucił, uzupełnij każdą z nich dwoma akapitami pewnie brzmiącego wypełniacza, który nie wnosi nowych faktów, i oceń je ponownie. Każdy werdykt, który zmieni się na pozytywny, oznacza stronniczość długości; należy wtedy poprawić rubrykę.

Preferencja własna. Sędzia często ocenia wyjście z własnej rodziny modeli łagodniej niż wyjście z innej. Przetestuj to: oceń te same 30 odpowiedzi sędziami z dwóch różnych rodzin i porównaj werdykty przypadek po przypadku. Tam, gdzie się nie zgadzają, oceń przypadek samodzielnie.

Stronniczość pozycji. Jeśli używasz sędziego do porównania dwóch odpowiedzi, A i B, zamień je miejscami i uruchom test ponownie. Werdykt, który zmienia się po zamianie, oznacza, że porównywanie parami nie jest jeszcze bezpieczne dla danej rubryki.

Dryf rubryki. Niejasne kryteria tworzą uległych sędziów. "Czy odpowiedź jest pomocna" przepuszcza niemal wszystko. "Czy odpowiedź podaje kwotę zwrotu w dolarach" przepuszcza tylko to, co zamierzałeś. Przepisz każde kryterium tak, aby wskazywało konkretny fakt, który jest sprawdzany.

Jeden mechanizm zabezpieczający obejmuje wszystkie cztery problemy. Zachowaj 30 przypadków, które oznaczyłeś ręcznie, i oceniaj sędziego względem swoich etykiet za każdym razem, gdy zmieniasz model sędziego lub jego prompt. Jeśli sędzia nie zgadza się z Tobą w więcej niż jednym przypadku na dziesięć, popraw rubrykę, zanim zaufasz jakiemukolwiek wskaźnikowi skuteczności, który wygeneruje. Sędzia to kod, więc podlega wersjonowaniu i przeglądowi tak samo jak kod.

Stopniowanie kosztów oceny, eskalacja do modelu klasy frontier

Ocenianie każdego przypadku za pomocą najdroższego modelu przy każdym commicie prowadzi do sytuacji, w której koszt ewaluacji przewyższa koszt utrzymania testowanego agenta. Szereguj oceniające modele według ceny i kończ proces, gdy wynik jest jednoznaczny.

ChartCost to judge 1,000 eval cases, list prices, August 2026
The data behind this chart
[
  {
    "label": "Haiku 4.5, Batch API",
    "usd_per_1000_judge_calls": "0.90"
  },
  {
    "label": "Haiku 4.5",
    "usd_per_1000_judge_calls": "1.80"
  },
  {
    "label": "Sonnet 5",
    "usd_per_1000_judge_calls": "3.60"
  },
  {
    "label": "Opus 5",
    "usd_per_1000_judge_calls": "9.00"
  }
]

Powyższe liczby zakładają około 1200 tokenów wejściowych i 120 tokenów wyjściowych na jedno wywołanie sędziego, co stanowi realistyczny rozmiar dla jednego pytania, jednej odpowiedzi i jednego kryterium. Ocena 1000 przypadków kosztuje 1.80 dolarów amerykańskich przy użyciu Claude Haiku 4.5 oraz 9.00 przy użyciu Claude Opus 5. Różnica wydaje się nieistotna, dopóki nie zostanie pomnożona. Zestaw 60 przypadków, oceniany przy każdym commicie, przy 40 commitach tygodniowo, generuje 2400 wywołań sędziego tygodniowo, zanim jeszcze uruchomione zostanie zadanie nocne.

W pracach ewaluacyjnych mają zastosowanie dwie zniżki, które się sumują. Uruchomienia ewaluacji nie są interaktywne, więc Batch API obniża ceny wejściowe i wyjściowe o połowę w zamian za asynchroniczne dostarczenie wyników, co przedstawia pierwszy wiersz tabeli. Rubryka i instrukcje są identyczne co do bajta w każdym wywołaniu, więc zastosowanie prompt caching jest zasadne: odczyt z pamięci podręcznej kosztuje jedną dziesiątą podstawowej ceny wejściowej, a zapis do pamięci podręcznej trwający pięć minut kosztuje 1,25 ceny podstawowej, więc koszt cache zwraca się po pojedynczym trafieniu. Są to ceny katalogowe Anthropic według stanu na sierpień 2026 roku, a Sonnet 5 jest objęty cenami promocyjnymi do 31 sierpnia 2026 roku, więc trzeci słupek wzrośnie po tej dacie.

Drabinka, w kolejności:

  • Sprawdzenia deterministyczne dla każdego przypadku. Brak kosztów API.
  • Sędzia w postaci małego modelu dla przypadków, które przeszły powyższe sprawdzenia.
  • Sędzia klasy frontier tylko wtedy, gdy mały model zgłosi błąd lub oceni wynik z niską pewnością.
  • Weryfikacja ludzka na małej próbce, raz w tygodniu.
CHEAP = "claude-haiku-4-5-20251001"
STRICT = "claude-opus-5"


def grade(case, result):
    hard = deterministic(case, result)
    if hard:
        return False, "deterministic", "; ".join(hard)
    first = judge(case, result["output"], CHEAP)
    if first["verdict"] == "pass" and first["confidence"] == "high":
        return True, CHEAP, first["reason"]
    second = judge(case, result["output"], STRICT)
    return second["verdict"] == "pass", STRICT, second["reason"]

Podejście to wymienia pewną dokładność oceny na niższy koszt, dlatego należy mierzyć tę różnicę, zamiast zakładać jej wielkość. Raz w miesiącu oceń cały zestaw za pomocą surowego sędziego i porównaj obie kolumny. Jeśli wyniki różnią się w więcej niż kilku przypadkach, rubryka jest zbyt luźna dla małego modelu i to rubrykę należy poprawić. Kontrolowanie wydatków samego agenta to oddzielne zadanie, omówione w kontrola kosztów agenta AI na VPS.

Śledzenie wskaźnika powodzeń w czasie w zarządzanym systemie

Wskaźnik powodzeń, którego nie można powiązać z konkretnym commitem, jest jedynie subiektywnym odczuciem. Należy przechowywać jeden wiersz na przypadek testowy dla każdego uruchomienia, uwzględniając w nim identyfikator commita oraz model.

CREATE TABLE IF NOT EXISTS results (
  run_id      TEXT NOT NULL,
  ran_at      TEXT NOT NULL,
  git_sha     TEXT NOT NULL,
  agent_model TEXT NOT NULL,
  case_id     TEXT NOT NULL,
  passed      INTEGER NOT NULL,
  graded_by   TEXT NOT NULL,
  reason      TEXT
);
SELECT run_id, git_sha, agent_model,
       count(*) AS cases,
       round(100.0 * sum(passed) / count(*), 1) AS pass_pct
FROM results
GROUP BY run_id
ORDER BY ran_at DESC
LIMIT 10;

Wczytaj schemat za pomocą sqlite3 evals/results.db < evals/schema.sql, a następnie odczytaj trend przy użyciu sqlite3 -box evals/results.db < evals/passrate.sql. Roczny cykl codziennych uruchomień dla 60 przypadków to około 22,000 wierszy, więc baza danych nie stanie się osobnym, złożonym projektem. Uruchamianie SQLite w środowisku produkcyjnym na VPS omawia ustawienia, które zyskują na znaczeniu, jeśli plik ten jest współdzielony między maszynami.

Narzędzie uruchomieniowe wyświetla te same informacje w czytelnej dla człowieka formie:

run 2026-08-05T09:14:22Z  sha 4f1c9ab  model claude-sonnet-5  58/60 pass (96.7%)
FAIL refund-double-charge  deterministic: tool not called: create_refund
FAIL pto-policy-question   judge(opus): reply gives no dollar amount

Uruchamiaj zestaw testów dla zmian, które mogą wpłynąć na działanie agenta, czyli edycji promptów, zmian modelu oraz modyfikacji narzędzi, zamiast dla każdego commita w repozytorium. Hook pre-push obsługuje szybki podzbiór testów:

cat > .git/hooks/pre-push <<'EOF'
#!/bin/sh
python3 evals/run.py --set smoke || exit 1
EOF
chmod +x .git/hooks/pre-push

Pełne uruchomienia są wolniejsze i powinny odbywać się według harmonogramu. Nocny serwis systemd oraz timer na VPS wykonuje pełny zestaw testów względem wdrożonego promptu, co pozwala wykryć zmiany pochodzące spoza repozytorium, na przykład modyfikacje zachowania zewnętrznego narzędzia.

Weryfikacja przez człowieka, próbkowana zamiast wyczerpującej

Sędzia jest kalibrowany na podstawie etykiet nadanych przez człowieka, więc ktoś musi je przygotować. Należy co tydzień sprawdzać próbkę: każdy przypadek, w którym sędzia zawiódł, oraz dziesięć losowo wybranych przypadków zaliczonych. Losowe przypadki zaliczone stanowią ważniejszą połowę, ponieważ sędzia, który po cichu zaczął zaliczać błędne odpowiedzi, wygląda na idealnego w każdym panelu kontrolnym zbudowanym na podstawie jego własnych werdyktów.

Piętnaście przypadków po trzy minuty każdy to 45 minut tygodniowo. Pozwala to na wprowadzanie poprawek do rubryki w miejscach, gdzie występuje rozbieżność między człowiekiem a sędzią, oraz na dodawanie nowych przypadków dla typów błędów, których nikt wcześniej nie przewidział. Należy wpisać werdykt człowieka do tej samej tabeli z graded_by ustawionym na human, dzięki czemu zgodność między sędzią a człowiekiem staje się zapytaniem, a nie kwestią pamięci.

Co ulega awarii w samym środowisku testowym

anthropic.RateLimitError podczas pierwszego pełnego uruchomienia. Równoległe uruchomienie 60 przypadków przekracza limit żądań lub tokenów dla danego poziomu dostępu. Należy ograniczyć współbieżność do czterech procesów roboczych i przenieść nocne uruchomienia na Batch API.

json.JSONDecodeError: Expecting value: line 1 column 1 (char 0) ze strony sędziego. Model odpowiedział tekstem ciągłym lub umieścił JSON w bloku kodu. Należy ponowić próbę raz, a następnie zarejestrować przypadek jako błąd. Nigdy nie należy traktować błędu parsowania jako zaliczenia, ponieważ zestaw testowy, który zamienia błędy na zaliczenia, zbliża się do 100% skuteczności, podczas gdy agent staje się coraz mniej efektywny.

Niestabilne przypadki (flaky cases). Ten sam zestaw danych wejściowych przechodzi w jednym uruchomieniu i kończy się niepowodzeniem w kolejnym, ponieważ agent losuje swoje wyjście. Należy uruchomić niestabilny przypadek trzy razy i zapisać ułamek sukcesów zamiast usuwać przypadek. Przypadek, który przechodzi dwa na trzy uruchomienia, jest rzeczywistym błędem odporności, który zostanie wykryty przez klienta.

Degradacja zbioru wzorcowego (golden set rot). Ktoś edytuje oczekiwaną odpowiedź, aby zestaw testowy wyświetlał status pozytywny. Należy przeglądać zmiany w evals/cases.jsonl równie uważnie, co zmiany w kodzie agenta, ponieważ ten plik stanowi pisemną definicję poprawności.

Zestaw, który nigdy nie wykazuje błędów. Wskaźnik zaliczeń utrzymujący się na poziomie 100% przez miesiąc oznacza, że zestaw przestał odzwierciedlać stan produktu. Należy pobrać dziesięć ostatnich śladów (traces), zidentyfikować te, z którymi agent poradził sobie słabo, i dodać je do zestawu.

FAQ

Ile przypadków testowych powinien zawierać zestaw ewaluacyjny agenta AI?

Należy rozpocząć od 40 do 80 przypadków i rozszerzać zestaw w oparciu o rzeczywiste awarie. Poniżej 20 przypadków jeden niestabilny wynik zmienia wskaźnik poprawności o 5 punktów procentowych, przez co liczba ta przestaje być miarodajna. Powyżej kilkuset przypadków każde uruchomienie generuje realne koszty i zajmuje czas, podczas gdy marginalne przypadki wnoszą znikome pokrycie testowe. Istotną miarą nie jest liczba przypadków, lecz udział znanych typów awarii produkcyjnych, które występują w zestawie przynajmniej raz.

Czy można ufać sędziemu LLM przy ocenianiu agenta?

Tylko po zweryfikowaniu jego działania względem własnych etykiet. Należy zachować 30 przypadków ocenionych ręcznie i sprawdzać wynik sędziego za każdym razem, gdy zmieniany jest model sędziowski lub jego prompt. Sędziowie wykazują tendencję do faworyzowania dłuższych odpowiedzi oraz preferowania własnej rodziny modeli, oceniając je łagodniej. Oba zjawiska można przetestować: należy uzupełnić nieudaną odpowiedź i poddać ją ponownej ocenie lub ocenić te same odpowiedzi przy użyciu sędziego z innej rodziny modeli. Jeśli sędzia nie zgadza się z etykietami w więcej niż jednym przypadku na dziesięć, rubryka oceny jest zbyt nieprecyzyjna.

Który model powinien oceniać ewaluacje?

Należy oceniać tanio i eskalować w razie potrzeby. Asercje deterministyczne nie generują kosztów, więc powinny być uruchamiane jako pierwsze dla każdego przypadku. Mały model obsłuży oczywiste sukcesy. Tylko niepowodzenia i werdykty o niskim poziomie pewności powinny trafiać do modelu klasy frontier. Według cen katalogowych z sierpnia 2026 roku, ocena 1 000 przypadków kosztuje około 1.80 USD przy użyciu Claude Haiku 4.5 oraz około 9.00 przy użyciu Claude Opus 5. Ponieważ uruchomienia ewaluacji są asynchroniczne, Batch API pozwala obniżyć obie te kwoty o połowę.

Czy ewaluacje zastępują monitorowanie produkcji?

Nie, ponieważ odpowiadają na inne pytania. Zestaw ewaluacyjny informuje, czy zmiana przeznaczona do wdrożenia poprawia lub pogarsza wyniki dla ustalonego zbioru przypadków. Śledzenie i monitorowanie informują o tym, z czym mierzą się użytkownicy w czasie rzeczywistym, w tym o danych wejściowych, których nie obejmuje żaden przypadek testowy. Mechanizmy te uzupełniają się: ślady dostarczają nowych przypadków, a zestaw ewaluacyjny weryfikuje, czy wprowadzona poprawka faktycznie zadziałała.