SSD Nodes Learn Hosting plans →
Przewodniki Matt ConnorAutor: Matt Connor · Zaktualizowano 2026-08-28

Własny system ewaluacji agentów AI: przewodnik

Stwórz własną pętlę ewaluacyjną dla agentów AI bez zewnętrznych narzędzi. Wykorzystaj testy deterministyczne, ocenę LLM oraz śledzenie wskaźnika zaliczeń dla każdego commita.

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 oraz 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 „teraz 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 po jednej sekcji na każdy z nich: zbieranie rzeczywistych śladów (traces), promowanie interesujących przypadków do zestawów testowych, ocenianie każdego przypadku przy każdej zmianie oraz zapisywanie wskaźnika zaliczeń obok commita, który go wygenerował. Ta sama pętla sprawdza się niezależnie od tego, na czym uruchamiasz agenta, a warstwy agentowe typu self-hosted, które warto uruchomić różnią się głównie ilością danych śledzenia, które 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 niegrzecznych odpowiedzi zmienia zachowanie w przypadku danych wejściowych, które nie zostały ponownie przetestowane. Ślady wykonania (traces) wyraźnie to pokazują: ślad z zeszłego tygodnia dla tego samego pytania 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 polegać na skrótach pamięciowych. Spadek wskaźnika poprawności w dniu zmiany modelu można zdiagnozować tylko wtedy, gdy nazwa modelu jest zapisana w logach.

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 kodu. Czwartą przyczyną jest pobieranie danych (retrieval): to samo pytanie trafia do indeksu, który został przebudowany w nocy, przez co odpowiedź opiera się na nowym dokumencie.

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

Nie należy tworzyć przypadków testowych od podstaw. Należy je wyodrębnić z rzeczywistego ruchu. Jeśli wdrożono już samodzielnie hostowane śledzenie Langfuse dla agenta, każde żądanie jest przechowywane wraz z danymi wejściowymi, wywołaniami narzędzi oraz danymi wyjściowymi. Jest to surowy materiał niezbędny do przygotowania przypadków testowych.

Należy wyeksportować okno czasowe obserwacji głównych (root observations) za pośrednictwem 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]'

Przed przystąpieniem do parsowania należy odczytać jeden rekord. Wiersze są zwracane w ramach data, jednak nazwy pól zawierających pytanie i odpowiedź zależą od sposobu instrumentacji spanów w agencie. Należy zmapować rzeczywiste dane, zamiast polegać na założeniach. Następnie należy ręcznie przygotować przypadki testowe, 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 testowego:

  • Od 40 do 80 przypadków to wystarczająca liczba na początek. Poniżej 20 przypadków jeden niestabilny test zmienia wskaźnik powodzenia o 5 punktów procentowych, co sprawia, że wyniki zmieniające się bez wyraźnego powodu są ignorowane.
  • Każdy naprawiony błąd produkcyjny staje się przypadkiem testowym w dniu jego naprawy. Ten nawyk pozwala na rozwój zestawu w odpowiednim kierunku.
  • Jeden przypadek testowy to jedno zachowanie. Przypadek sprawdzający jednocześnie kwotę zwrotu i ton wypowiedzi nie dostarcza użytecznych informacji w przypadku awarii.
  • Pole id nigdy nie ulega zmianie, ponieważ identyfikator służy do porównywania wyników bieżącego uruchomienia z wynikami z poprzedniego miesiąca.
  • Przed zatwierdzeniem zmian należy przeprowadzić redakcję danych. Plik ten trafia do repozytorium git, dlatego należy usunąć nazwiska klientów oraz wszelkie numery zamówień, które nie należą do środowiska testowego.

W pierwszej kolejności stosuj testy deterministyczne, ponieważ są one bezpłatne

Każdy przypadek posiadający jednoznaczną poprawną odpowiedź powinien być weryfikowany prostą asercją. Nie wymaga to wywołania modelu, nie generuje kosztów i eliminuje niejednoznaczność. Testy deterministyczne wykrywają regresje strukturalne, czyli błędy powodujące awarie systemów współpracujących z agentem: niepoprawny format JSON, brak wywołania narzędzia, pojawienie się zabronionej frazy lub brak cytowania źródeł w odpowiedzi.

Tylko jedna funkcja posiada wiedzę o agencie. 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

Utrzymuj 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 odpowiedź końcowa 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 potrafi czytać. Sędzia LLM to drugie wywołanie modelu: otrzymuje on 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 prawie wszystkiego, więc wynik się nie zmienia i niczego z niego nie wynika.
  • Jedno kryterium na wywołanie. Pytaj o kwotę zwrotu lub o ton wypowiedzi, nie o obie te rzeczy jednocześnie.
  • 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. Dla każdego z nich można przeprowadzić test jeszcze dziś. Wykonywanie tych testów jest kluczowe, ponieważ niesprawdzony sędzia generuje liczby, które wyglądają na precyzyjne, a nie znaczą nic.

Stronniczość długości (Length bias). 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 pewnego siebie 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 (Self-preference). 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 (Position bias). Jeśli używasz sędziego do porównania dwóch odpowiedzi, A i B, zamień je miejscami i uruchom ponownie. Werdykt, który zmienia się po zamianie, oznacza, że porównywanie parami nie jest jeszcze bezpieczne dla danej rubryki.

Dryf rubryki (Rubric drift). Niejasne kryteria tworzą uległych sędziów. "Czy odpowiedź jest pomocna" przepuszcza prawie wszystko. "Czy odpowiedź podaje kwotę zwrotu w dolarach" przepuszcza tylko to, o co chodziło. Przepisz każde kryterium tak, aby wskazywało konkretny sprawdzany fakt.

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 poprawności, który wygeneruje. Sędzia to kod, więc podlega wersjonowaniu i przeglądowi tak samo jak kod.

Klasyfikacja tania, eskalacja do modelu klasy frontier

Ocenianie każdego przypadku najdroższym modelem przy każdym commicie prowadzi do sytuacji, w której koszt ewaluacji przewyższa koszt działania testowanego agenta. Szereguj ewaluatorów według ceny i kończ proces, gdy odpowiedź jest jednoznaczna.

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 realistyczną wielkość dla jednego pytania, jednej odpowiedzi i jednego kryterium. Ocenienie 1000 przypadków kosztuje 1.80 USD 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, daje 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ą bazowej ceny wejściowej, a pięciominutowy zapis do pamięci podręcznej kosztuje 1,25 ceny bazowej, więc koszt cache zwraca się po pojedynczym trafieniu. Są to ceny katalogowe Anthropic na sierpień 2026, a Sonnet 5 jest objęty cenami promocyjnymi do 31 sierpnia 2026, więc trzeci słupek wzrośnie po tej dacie.

Drabinka, w kolejności:

  • Kontrole 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 kontrole.
  • Sędzia klasy frontier tylko wtedy, gdy mały model zgłosi błąd lub oceni wynik z niską pewnością.
  • Przegląd ludzki na małej próbie, 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ść ocen na niższy koszt, dlatego należy mierzyć tę zależność, zamiast zakładać ją a priori. Raz w miesiącu oceń cały zestaw również przy użyciu 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ć. Kontrola wydatków samego agenta to oddzielne zadanie, opisane w kontrola kosztów agenta AI na VPS.

Monitorowanie wskaźnika powodzenia w czasie w zarządzanym systemie

Wskaźnik powodzenia, 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;

Załaduj 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 testowych generuje około 22,000 wierszy, więc baza danych nigdy nie stanie się osobnym, złożonym projektem. Artykuł Uruchamianie SQLite w środowisku produkcyjnym na VPS omawia ustawienia, które stają się istotne, gdy plik ten jest współdzielony między wieloma maszynami.

Runner wyświetla te same informacje w formie czytelnej dla użytkownika:

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 być wykonywane według harmonogramu. Nocny serwis systemd oraz timer na VPS wykonuje pełny zestaw testów dla wdrożonego promptu, co pozwala wykryć zmiany pochodzące spoza repozytorium, takie jak aktualizacja zewnętrznego narzędzia, którego zachowanie uległo zmianie.

Przegląd ręczny, wyrywkowy zamiast pełnego

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

Piętnaście przypadków po trzy minuty każdy to 45 minut tygodniowo, co pozwala na wprowadzanie poprawek do rubryki w miejscach, w których występuje rozbieżność między oceną człowieka a sędziego, oraz na dodawanie nowych przypadków dla typów awarii, których nikt wcześniej nie przewidział. Należy wpisać werdykt człowieka do tej samej tabeli z ustawionym graded_by na human, aby zgodność między sędzią a człowiekiem stała 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ść uruchomienia nocne do 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. Błąd parsowania nigdy nie może być uznany za wynik pozytywny, ponieważ zestaw testowy zamieniający błędy w sukcesy zbliża się do 100% skuteczności, podczas gdy agent staje się coraz mniej sprawny.

Niestabilne przypadki (flaky cases). Ten sam zestaw danych wejściowych przechodzi w jednym uruchomieniu i zawodzi w kolejnym, ponieważ agent losuje swoje odpowiedzi. Należy uruchomić niestabilny przypadek trzy razy i zapisać ułamek sukcesów zamiast usuwać przypadek. Przypadek, który przechodzi dwa z trzech uruchomień, stanowi rzeczywisty błąd stabilności, który zostanie wykryty przez klienta.

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

Zestaw, który nigdy nie zawodzi. Wskaźnik sukcesu utrzymujący się na poziomie 100% przez miesiąc oznacza, że zestaw przestał odzwierciedlać stan produktu. Należy pobrać dziesięć ostatnich śladów (traces), znaleźć te, z którymi agent poradził sobie słabo, i dodać je do zestawu. Następnie należy celowo wprowadzić błąd i potwierdzić, że uruchomienie kończy się niepowodzeniem; jest to weryfikacja testowania mutacyjnego stosowanego do zestawu testów i jedyny sposób, aby upewnić się, że zestaw testowy nadal jest skuteczny.

FAQ

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

Należy zacząć od 40 do 80 przypadków i rozbudowywać 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żdy przebieg generuje realne koszty i zajmuje czas, podczas gdy marginalny przypadek wnosi niewielki wzrost pokrycia testami. Istotną miarą nie jest liczebność, 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 uprzednim zweryfikowaniu go względem własnych etykiet. Należy zachować 30 przypadków ocenionych ręcznie i sprawdzać sędziego względem nich za każdym razem, gdy zmieniany jest model sędziowski lub jego prompt. Sędziowie wykazują stronniczość względem długości odpowiedzi, gdzie bardziej rozbudowane odpowiedzi częściej przechodzą test, oraz preferencję własną, gdzie wyniki z tej samej rodziny modeli są oceniane łagodniej. Oba zjawiska można przetestować: należy wydłużyć nieudaną odpowiedź i poddać ją ponownej ocenie lub ocenić te same odpowiedzi sędzią z innej rodziny modeli. Jeśli sędzia nie zgadza się z etykietami w więcej niż jednym na dziesięć przypadków, rubryka jest zbyt nieprecyzyjna, aby ją stosować.

Który model powinien oceniać ewaluacje?

Należy oceniać tanio i eskalować w razie potrzeby. Deterministyczne asercje nie generują kosztów, więc są uruchamiane jako pierwsze w każdym przypadku. Mały model obsługuje oczywiste sukcesy. Tylko niepowodzenia i werdykty o niskim poziomie pewności trafiają 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, a ponieważ przebiegi ewaluacyjne są asynchroniczne, Batch API obniża obie te kwoty o połowę.

Czy ewaluacje zastępują monitoring produkcyjny?

Nie, ponieważ odpowiadają na inne pytania. Zestaw ewaluacyjny informuje, czy zmiana, która ma zostać wdrożona, poprawia lub pogarsza wyniki dla ustalonego zbioru przypadków. Śledzenie (tracing) i monitoring informują o tym, z czym mierzą się rzeczywiści 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 rozstrzyga, czy poprawka faktycznie zadziałała.