Strona główna / Artykuły

Ocena GenAI i agentów: testowanie jednoetapowe vs wieloetapowe w CI

Porównaj oceny jednoetapowe oparte na śladach z ocenami wieloetapowymi sterowanymi symulatorem, obejmując standardy złote, sędziów typu LLM, metryki agentów, bramy CI oraz siedem praktyk pracy.

Wydawca: REACTAPP.TOP8 min czytania1800 słów

Źródła: End-to-End Evals for Gen AI and Agentic AI: A Practitioner’s Guide to Single-Turn and Multi-Turn Evaluation

"Działa przy moim promptzie" nie jest standardem inżynieryjnym. Tradycyjny test jednostkowy albo się udaje, albo nie w sposób deterministyczny, natomiast systemy generatywne dają otwarte, probabilistyczne odpowiedzi. Pipeline RAG może być w większości poprawny, a agent może sfinalizować zadanie w sposób, który na papierze uznawany jest za sukces, ale w praktyce jest niebezpieczny. Dlatego właśnie oceny, w odróżnieniu od intuicji lub kanału czatowego pełnego stwierdzeń typu "wygląda dobrze", stanowią obecnie podstawę poważnej inżynierii ML w obszarze sztucznej inteligencji generatywnej i systemów agentowych. Poniżej omówiono, co należy mierzyć, w czym różnią się oceny jednoetapowe i wieloetapowe, jakie są ich wady oraz wzorce w Pythonie pasujące do pipeline CI.

Dlaczego oceny nie są opcjonalne

Trzy cechy aplikacji opartych na LLM sprawiają, że są one konieczne:

  1. Niedeterminizm. Identyczne prompty mogą dawać różne wyniki w zależności od kolejnych uruchomień, wersji modelu lub wartości temperatury.
  2. Kumulowanie błędów u agentów. Podczas gdy zwykły chatbot ma tylko jedną szansę na popełnienie błędu, agent łączy ze sobą od 10 do 50 wywołań modelu, wywołań narzędzi oraz decyzji. Niewielki wskaźnik błędów na krok przeradza się w częste problemy na całym etapie.
  3. Ciche regresje. Niewielka modyfikacja promptu, aktualizacja modelu lub ponowne indeksowanie magazynu wektorowego może pogorszyć jakość bez wywołania żadnego wyjątku.

Ewaluacja przekształca stwierdzenie „wydaje się lepsze” w liczbę, którą można śledzić z biegiem czasu, wykorzystywać do decyzji o wdrożeniu oraz porównywać pomiędzy różnymi wersjami.

Dwie formy ewaluacji

Prawie każda platforma, w tym DeepEval, Ragas, LangSmith, Braintrust i OpenAI Evals, opiera się na jednym z dwóch wzorców.

Jednoetapowe, oparte na śladach

Pętla jest prosta: bierze się każdy przykład, uruchamia aplikację raz i ocenia ślad.

Open a test run with trace-level metrics
  for each golden:
    yield golden
    call app with golden.input
    capture trace
    build a test case from the trace
    score test case with metrics
  upload test run (traces + scores)

Złoty przykład to etykietowany zbiór danych: dane wejściowe, odpowiedź, którą powinien wygenerować, a często także kontekst lub wywołania narzędzi, które powinien uwzględnić. Ślad rejestruje całą historię jednego przebiegu, w tym które fragmenty zostały pobraane, jakie narzędzia zostały uruchomione, tok rozumowania pomiędzy nimi, opóźnienia i liczbę tokenów, a nie tylko tekst końcowy. Ocena tego zapisu zamiast samej odpowiedzi pozwala określić etap, w którym wystąpił błąd – czy to przy pobieraniu danych, generowaniu tekstu, czy przy wywołaniu narzędzia?

Wieloetapowy, oparty na symulatorze

To trudniejszy i bardziej realistyczny wzorzec dla agentów i asystentów czatowych.

def simulate(conversational goldens)
  for each golden:
    loop until expected outcome OR max turns:
      simulator model generates a user turn
      ask app for next reply
      capture assistant turn
    build a ConversationalTestCase from the full transcript
  evaluate(test cases, metrics)   # metrics run concurrently
    -> pass/fail + reason per metric

Tutaj nie ma ustalonej pary wejścia i wyjścia. Model symulatora odgrywa rolę użytkownika z konkretnym celem, np. anulowania subskrypcji lub otrzymania zwrotu pieniędzy za określony zamówienie, i dostosowuje każdą wiadomość do odpowiedzi asystenta, podobnie jak robiłoby to człowiek. System oceniany jest na podstawie całej ścieżki działania. Czy trzymał się założonego zadania? Czy prawidłowo używał narzędzi w poszczególnych rundach? Czy ostatecznie osiągnął swój cel? Czy już po trzech rundach wymyślił szczegóły związane z zasadami?

Agenci, asystenci wieloetapowi oraz wszystko, co posiada pamięć lub stan, wymagają takiego podejścia. Ocena w ramach jednej rundy nie może wykryć sytuacji, gdy agent sprzeciwia się samemu sobie w czwartej rundzie lub używa jednego narzędzia pięć razy w pętli.

Wybór metryk

Metryki dzielą się na cztery grupy, a ich łączenie jest rozsądne, ponieważ żadna z nich nie przedstawia pełnego obrazu.

Praktyczny model mentalny: metryki jednoetapowe oceniają chwilowy stan, natomiast metryki oparte na agencji oceniają całokształt rozwoju.

LLM jako sędzia

Większość dzisiejszych metryk bez odniesień do zewnętrznych danych funkcjonuje według zasady „LLM jako sędzia”. Silny model, często inny i bardziej zdolny niż model testowany, ocenia wynik według określonych kryteriów i wyjaśnia uzyskany wynik.

from dataclasses import dataclass

JUDGE_PROMPT = """
You are evaluating an AI assistant's response for FAITHFULNESS.
A response is faithful if every factual claim it makes is supported
by the provided context. It is unfaithful if it adds unsupported
claims, contradicts the context, or fabricates details.
Context:
{context}
Response:
{response}
Return JSON: {{"score": <0.0-1.0>, "reason": "<short explanation>"}}
"""

@dataclass
class TestCase:
    input: str
    actual_output: str
    retrieval_context: list[str]

def faithfulness_metric(test_case: TestCase, judge_llm) -> dict:
    prompt = JUDGE_PROMPT.format(
        context="\n".join(test_case.retrieval_context),
        response=test_case.actual_output,
    )
    result = judge_llm.generate(prompt, response_format="json")
    return {"score": result["score"], "reason": result["reason"], "passed": result["score"] >= 0.7}

Sędziowie mają swoje wady:

  • Uprzedzenie na rzecz siebie. Modele oceniają swój własny wynik lub wynik w swoim stylu bardziej przychylnie. Gdzie to możliwe, używaj sędziego z innej rodziny modeli.
  • Czułość na prompty. Małe zmiany w sformułowaniach kryteriów wpływają na oceny. Trzymaj prompty sędziów pod kontrolą wersji, tak jak kod.
  • Koszt i opóźnienie. Korzystanie z sędziów również wiąże się z kosztami. Gdy budżet jest ograniczony, przetestuj ruch w warunkach rzeczywistych i nie oceniaj wszystkiego.
  • Uprzedzenie na rzecz dłuższych odpowiedzi. Sędziowie skłaniają się ku dłuższym, bardziej pewnym siebie odpowiedziom, niezależnie od tego, czy są one poprawne. Od czasu do czasu kalibruj ich oceny na małej grupie danych oznaczonych przez ludzi.

Jedno kroku w praktyce

Złota baza może składać się z tak małej listy słowników zawierających dane wejściowe i oczekiwany wynik.

goldens = [
    {
        "input": "What's our refund policy for digital products?",
        "expected_output": "Digital products are refundable within 14 days if unused.",
        "expected_tools": [],
    },
    {
        "input": "Cancel order #48213",
        "expected_output": None,  # open-ended, judged not matched
        "expected_tools": ["lookup_order", "cancel_order"],
    },
]

Program uruchamia się zgodnie z opisanym powyżej schematem: otwiera próbne uruchomienie, przechodzi przez każdy element typu „golden”, wywołuje aplikację, zapisuje ślady działania, ocenia wynik i przesyła go.

from deepeval import evaluate
from deepeval.metrics import FaithfulnessMetric, AnswerRelevancyMetric
from deepeval.test_case import LLMTestCase

def run_eval_suite(goldens, app_callback, metrics):
    test_cases = []
    for golden in goldens:
        trace = app_callback(golden["input"])   # your traced LLM/RAG app
        test_case = LLMTestCase(
            input=golden["input"],
            actual_output=trace.final_output,
            retrieval_context=trace.retrieved_chunks,
            expected_output=golden.get("expected_output"),
        )
        test_cases.append(test_case)
    results = evaluate(test_cases, metrics)  # runs metrics concurrently
    return results
metrics = [FaithfulnessMetric(threshold=0.7), AnswerRelevancyMetric(threshold=0.7)]
results = run_eval_suite(goldens, my_rag_app, metrics)

Stwierdzenie przekształca wyniki w bramkę.

def assert_eval_gate(results, min_pass_rate=0.9):
    passed = sum(1 for r in results if r.success)
    pass_rate = passed / len(results)
    assert pass_rate >= min_pass_rate, f"Eval pass rate {pass_rate:.2%}
    below gate {min_pass_rate:.0%}"

Podłącz to do pipeline’u PR w taki sam sposób, jak podłączony jest pytest. Jeśli zmiana w promptzie lub procesie pozyskiwania danych obniży poziom wierności poniżej ustalonego progu, fuzja powinna zostać zablokowana i nic nie powinno zostać wydane bez żadnych ostrzeżeń.

Multi-turn w praktyce

Zamiast stałego wprowadzenia danych, symulator otrzymuje profil użytkownika oraz cel, a następnie kieruje rozmową.

class ConversationSimulator:
    def __init__(self, simulator_model, max_turns=8):
        self.simulator_model = simulator_model
        self.max_turns = max_turns

    def simulate(self, golden, chatbot_callback):
        transcript = []
        user_turn = self.simulator_model.generate_opening(golden["scenario"])
        for _ in range(self.max_turns):
            transcript.append({"role": "user", "content": user_turn})
            assistant_turn = chatbot_callback(transcript)
            transcript.append({"role": "assistant", "content": assistant_turn})
            if self.simulator_model.is_goal_met(golden["expected_outcome"], transcript):
                break
            user_turn = self.simulator_model.generate_next_turn(transcript, golden)
        return transcript

Następnie rozmowa otrzymana w wyniku jest oceniana za pomocą metryk agentowych.

from deepeval.test_case import ConversationalTestCase, Turn
from deepeval.metrics import (
    TaskCompletionMetric,
    ToolCorrectnessMetric,
    ConversationCompletenessMetric,
)

def build_conversational_test_case(transcript, tools_called):
    turns = [Turn(role=t["role"], content=t["content"]) for t in transcript]
    return ConversationalTestCase(turns=turns, tools_called=tools_called)
    metrics = [
    TaskCompletionMetric(threshold=0.8),          # did it accomplish the user's goal?
    ToolCorrectnessMetric(threshold=1.0),          # right tools, right args, right order
    ConversationCompletenessMetric(threshold=0.7), # did it address everything raised?
    ]
    test_case = build_conversational_test_case(transcript, tools_called=agent_trace.tool_calls)
    result = evaluate([test_case], metrics)

Typowe sprawdzenia na poziomie agenta obejmują:

  • Prawidłowość wywołania narzędzia: właściwe narzędzie, z odpowiednimi argumentami, w właściwej kolejności – to więcej niż tylko „jakieś narzędzie zostało wywołane”.
  • Efektywność kroków i wykrywanie pętli: powtarzane wywołania tego samego narzędzia bez żadnego postępu.
  • Przestrzeganie roli i zasad: zachowywanie się zgodnie z zdefiniowaną postacią i ograniczeniami przez całą rozmowę, a nie tylko w pierwszym kroku.
  • Odbudowa po błędzie: rozsądna próba ponownego wywołania po nieudanym wywołaniu narzędzia, zamiast wymyślonego wyniku.
  • Przenoszenie kontekstu: pamiętanie tego, co użytkownik powiedział trzy kroki wcześniej.

Wzajemne porównanie zalet i wad

Jeden krok Wielokrotne kroki
Koszt Jedno wywołanie na każdy krok, tanie i szybkie
Każda sesja to rozmowa z wieloma wywołaniami, pomnożona o kolejne etapy i metryki Zbiór danych Duże zbiory referencyjne są proste, pochodzące z logów lub generowane syntetycznie Symulatory obejmują przypadki skrajne oraz wrogich użytkowników, których nikt nie napisałby ręcznie Sygnał Jasno oddziela błędy w wyszukiwaniu od błędów w generowaniu, jest niemal deterministyczny dla mechanizmów kontroli w CI Rozpoznaje kumulujące się awarie powodujące rzeczywiste incydenty oraz testuje cały system, włączając narzędzia, orkiestrację, stan i zasady bezpieczeństwa Słabe strony Pomija zmiany trendów, sprzeczności oraz utratę pamięci między etapami i sprzyja nadfitowaniu na podstawie zbioru referencyjnego Większa wariancja ze względu na dodanie losowości przez symulator, trudniejsze debugowanie, ponieważ awaria w 6. etapie może mieć początek już w 2. etapie, oraz problemy przy analizie długich transkryptów

Ponieważ wyniki z wielu rund są zanieczyszczone, należy je interpretować statystycznie. Wykonaj zestaw testów N razy i analizuj rozkłady, a nie pojedynczą ocenę.

Praktyki, które się sprawdzają

  1. Zacznij od małego, czystego zbioru „złotych” przykładów liczącego od 30 do 100 egzemplarzy. Zanieczyszczony zbiór liczący 1000 przykładów jest gorszy od uporządkowanego zbioru 50 przykładów, ponieważ błędne etykiety psują jakość sygnału.
  2. Oceniaj funkcję wyszukiwania i generowanie oddzielnie w RAG. Dokładność oraz pamięć kontekstowa odpowiadają na różne pytania, a ich łączenie ukrywa prawdziwy problem.
  3. Oceniaj za pomocą silniejszego, niezależnego modelu i od czasu do czasu sprawdzaj jego wyniki w porównaniu z ocenami ludzkich ekspertów. Już 20 do 30 przykładów miesięcznie może ujawnić zmiany w sposobie oceny.
  • Zapisuj wszystko. Oceniaj wyniki na podstawie zebranych śladów (pobranych dokumentów, wywołań narzędzi, kroków pośrednich), a nie tylko końcowego tekstu. Dlatego zapisywanie śladów następuje przed tworzeniem przypadku testowego.
  • Symuluj agenty przed wdrożeniem. Przeprowadzaj rozmowy z użyciem realistycznych postaci i celów przeciwnikowych, takich jak zły użytkownik, niejednoznaczna prośba lub specyficzny przypadek związany z polityką, przed wypuszczeniem produktu, a nie po incydencie.
  • Traktuj oceny jako żywe zasoby. Ponawiaj pełny zestaw testów po każdej zmianie promptu, aktualizacji modelu lub odbudowie indeksu, oraz ustaw w CI progi skuteczności podobnie jak progi pokrycia.
  • Obserwuj rozkłady z biegiem czasu. Jedno przeprowadzenie oceny to tylko próbka, a nie prawda obiektywna. Powtarzaj kluczowe zestawy testów i śledź trendy.
  • Główny wniosek

    Oceny systemów sztucznej inteligencji generatywnej zaczynały się jako dodatek, komórka w notatniku uruchamiana przed demonstracją. Systemy agentowe dawno już przewyższyły ten poziom. Gdy oprogramowanie może działać kilka razy, wywoływać narzędzia i przechowywać stan między kolejnymi krokami, ocena przestaje być zwykłą kontrolą jakości. Staje się głównym narzędziem do analizy rzeczywistego zachowania systemu.

    Oceny jednoetapowe oparte na śledzeniu dostarczają szybkich i tanich sprawdzeń regresji jakości wyników. Oceny wieloetapowe realizowane za pomocą symulatorów dają jedyną wiarygodną informację na temat tego, czy agent zachowuje się zgodnie z zamierzeniami podczas całej interakcji, a dla większości agentów produkcyjnych ta informacja ma największe znaczenie. Należy tworzyć oba rodzaje ocen i automatyzować je obie. Nie ufaj żadnemu z nich ślepo i zawsze zachowuj możliwość sprawdzenia ich przez człowieka.

    Literatura pokrewna