Giskard — testowanie modeli ML i systemów agentowych
Test jednostkowy zakłada, że to samo wejście daje to samo wyjście. Przy funkcjach opartych na modelach językowych to założenie nie obowiązuje — i dlatego potrzebna jest inna kategoria narzędzi. Giskard w wersji trzeciej, przepisanej od zera w sierpniu 2026, daje scenariusze z sędziami opartymi na modelu oraz skaner podatności generujący zestawy testów przeciwnika z jednozdaniowego opisu agenta.
Funkcje oparte na modelach językowych trafiają dziś do projektów klienckich rutynowo — czat obsługi, podsumowywanie zgłoszeń, wyszukiwanie po dokumentach firmowych, klasyfikacja wiadomości. I niemal zawsze towarzyszy im ta sama luka: nikt nie wie, jak to przetestować.
Powód jest fundamentalny, nie organizacyjny. Test jednostkowy opiera się na założeniu, że to samo wejście daje to samo wyjście — a przy modelu językowym to samo pytanie może dać dwie różne, równie poprawne odpowiedzi. Klasyczne narzędzia nie mają tu czego sprawdzać, więc kończy się na tym, że ktoś raz na kilka dni wkleja parę pytań i patrzy, czy odpowiedzi wyglądają sensownie. To nie jest test, a nawyk.
Giskard (github.com/Giskard-AI/giskard-oss) jest biblioteką z tej właśnie brakującej kategorii: ewaluacji, testowania i czerwonego zespołu dla systemów agentowych.
Stan projektu i świeże przepisanie
Dane z API GitHuba i PyPI na 12 października 2026:
- 5805 gwiazdek i 531 forków, repozytorium założone 6 marca 2022, licencja Apache-2.0,
- ostatni push dwa dni przed napisaniem tego tekstu, 63 otwarte zgłoszenia,
- wersja 3.0.0 wydana 26 sierpnia 2026, wraz z osobnymi wydaniami pakietów składowych,
- wymagany Python 3.12 lub nowszy,
- repozytorium przeniosło się przy tym pod nazwę
giskard-oss— stara nazwa przekierowuje.
Wersja trzecia nie jest kolejnym wydaniem, a przepisaniem od zera, i projekt mówi to wprost: nowa architektura jest zaprojektowana pod dynamiczne, wielotorowe testowanie agentów, porzuca ciężkie zależności i wnosi mocniejszy skaner podatności oraz lepszą ewaluację systemów opartych na wyszukiwaniu.
Do tego dochodzi zdanie, które trzeba przeczytać uważnie przed wyborem wersji: „Giskard v2 pozostaje dostępny, ale nie jest już aktywnie utrzymywany". Ma to konkretną konsekwencję, do której wrócę na końcu — bo część funkcji została w wersji drugiej i nie zostanie przeniesiona.
Czym eval różni się od testu jednostkowego
Dokumentacja definiuje to jednym zdaniem, które warto zapamiętać i powtarzać klientom: ewaluacje są przeznaczone dla wyjść niedeterministycznych, gdzie to samo wejście może dać różne poprawne odpowiedzi.
Z tego wynikają cztery zastosowania, które biblioteka wymienia i które pokrywają się z tym, o co realnie martwimy się w projektach:
- Wychwytywanie regresji — sprawdzenie, czy system zachowuje się poprawnie po zmianie promptu, modelu albo dostawcy. To jest scenariusz numer jeden, bo podmiana modelu na nowszy jest dziś zmianą, którą robi się co kwartał, i nikt nie wie, co przy niej zepsuł,
- Weryfikacja jakości odpowiedzi opartych na wyszukiwaniu — czy odpowiedź jest osadzona w dostarczonym kontekście, czy model dopisał ją z siebie,
- Wymuszanie reguł bezpieczeństwa — czy wyjście mieści się w polityce treści klienta,
- Ocena agentów wielotorowych — testowanie całych rozmów, nie pojedynczych wymian. To jest ta część, której wcześniejsze narzędzia nie obejmowały wcale.
Cztery pojęcia i jeden przykład
Model pojęciowy jest mały, co jest tu zaletą:
- Cel (target) — testowany system: dowolna funkcja synchroniczna albo asynchroniczna przyjmująca wejście i zwracająca wyjście,
- Scenariusz — jedna ewaluacja: interakcje wraz ze sprawdzeniami,
- Sprawdzenie — asercja albo sędzia oparty na modelu, działający na śladzie wykonania,
- Zestaw — wiele scenariuszy uruchamianych razem.
Definicja celu jest tu najważniejsza i decyduje o użyteczności całej biblioteki: nie musisz przyjmować żadnego frameworku agentowego. Owijasz to, co masz — pojedyncze wywołanie modelu, cudzego agenta traktowanego jako czarna skrzynka albo własny wieloetapowy potok — w jedną funkcję i to wystarczy.
import asyncio
from giskard.checks import Scenario, Groundedness
def get_answer(inputs: str) -> str:
return "Paris" # tu wchodzi Twój model albo agent
async def main() -> None:
scenario = (
Scenario("test_france_capital")
.interact(inputs="What is the capital of France?", outputs=get_answer)
.check(
Groundedness(
name="answer is grounded",
context="France is in Western Europe. Its capital is Paris.",
)
)
)
result = await scenario.run()
result.print_report()
asyncio.run(main())Warto zauważyć, że biblioteka jest asynchroniczna z założenia — scenariusz się oczekuje, a nie wywołuje. Przy zestawie kilkudziesięciu scenariuszy, z których każdy woła model przez sieć, jest to różnica między minutą a kwadransem.
Jak to podłączyć do aplikacji w Laravelu
Giskard jest biblioteką w Pythonie, a nasze aplikacje stoją na PHP — i to jest pierwsze pytanie, które się pojawia. Odpowiedź wynika z definicji celu: skoro celem jest dowolna funkcja przyjmująca wejście i zwracająca wyjście, to może nią być zwykłe wywołanie HTTP do naszego punktu końcowego.
import httpx
async def support_chat(inputs: str) -> str:
async with httpx.AsyncClient() as client:
r = await client.post(
"https://staging.klient.pl/api/chat",
json={"message": inputs},
headers={"Authorization": "Bearer ..."},
timeout=30,
)
return r.json()["reply"]Od tego miejsca cała biblioteka działa tak samo, jakby testowała kod w Pythonie — a testowany jest pełny stos klienta razem z promptem, kontekstem, filtrami i logiką biznesową, nie samo wywołanie modelu. To jest zresztą właściwszy przedmiot testu: błędy w takich funkcjach rzadko siedzą w modelu, a zwykle w tym, co do niego trafia i co się z odpowiedzią potem robi.
Praktycznie oznacza to jeden mały projekt w Pythonie obok repozytorium aplikacji — kilka plików ze scenariuszami, uruchamiane osobnym zadaniem w potoku. Zespół nie musi przechodzić na Pythona; musi utrzymywać kilkadziesiąt linii, które opisują, czego od funkcji oczekujemy.
Sprawdzenia wbudowane i ich cena
Zestaw gotowych sprawdzeń dzieli się na dwie grupy o zupełnie różnym charakterze.
Tanie i deterministyczne: dopasowanie tekstu, porównania, wyrażenia regularne oraz podobieństwo semantyczne. Te działają bez pytania kogokolwiek o zdanie i nadają się do uruchamiania przy każdym commicie.
Sędziowie oparci na modelu: Groundedness (czy odpowiedź jest osadzona w kontekście), Conformity (czy mieści się w zadanej regule) oraz ogólny LLMJudge. Tu tkwi cała siła tej biblioteki, ale też koszt, który trzeba nazwać: sędzia jest wywołaniem modelu, więc wymaga dostawcy i klucza API, a domyślnym modelem jest openai/gpt-4o-mini.
Konsekwencje są dwie i obie warto przewidzieć przy planowaniu. Po pierwsze, zestaw testów kosztuje pieniądze przy każdym przebiegu — więc uruchamianie go przy każdym commicie na każdej gałęzi wymaga policzenia rachunku. Po drugie, zestaw testów zależy od zewnętrznej usługi, czyli awaria dostawcy oznacza czerwone testy niezależnie od stanu naszego kodu. Praktyczny podział, który bym stosował: sprawdzenia deterministyczne w potoku przy każdej zmianie, sędziowie w przebiegu nocnym i przed wydaniem.
Skaner podatności: czerwony zespół z jednego zdania
To jest funkcja, która wyróżnia Giskarda spośród bibliotek do ewaluacji i jednocześnie ta, którą najłatwiej zamienić w usługę dla klienta.
vulnerability_scan generuje zestawy testów przeciwnika automatycznie, na podstawie opisu agenta w zwykłym języku. Cały wywołujący kod to kilka linii:
from giskard.scan import vulnerability_scan
await vulnerability_scan(
target=my_agent,
description="A customer support chatbot for an e-commerce platform.",
languages=["en"],
)Zakres generowanych ataków jest opisany konkretnie: kategorie zagrożeń z listy OWASP LLM Top-10, wstrzykiwanie promptu, treści szkodliwe, stereotypy i dezinformacja. Do tego dochodzi wbudowany zbiór gotowych ładunków do wstrzykiwania promptu oraz możliwość rejestrowania własnych generatorów scenariuszy — czyli dołożenia ataków specyficznych dla dziedziny klienta.
Wartość praktyczna jest tu bezpośrednia. Przed uruchomieniem czatu obsługi na stronie klienta warto wiedzieć, czy da się go namówić na ujawnienie instrukcji systemowej, obrażanie użytkownika albo doradzanie w sprawach, w których nie powinien się wypowiadać. Dotąd odpowiedź na to pytanie wymagała albo specjalisty, albo godziny wymyślania złośliwych zapytań. Tutaj jest to jedno wywołanie z jednozdaniowym opisem — a wynik jest raportem, który da się pokazać klientowi.
Parametr languages zasługuje przy tym na osobną uwagę: ataki generowane są w zadanym języku. Czat obsługujący polskich klientów trzeba testować po polsku, bo skuteczność wstrzykiwania promptu bywa językowo zależna, a filtr treści wytrenowany głównie na angielskim może zachowywać się inaczej.
Ewaluacja systemów z bazą wiedzy
Druga połowa pakietu skanującego to quality_scan działający na obiekcie bazy wiedzy — następca mechanizmu, który w wersji drugiej nazywał się RAGET i służył do generowania zestawów testowych dla systemów odpowiadających na podstawie dokumentów.
Zastosowanie jest u nas częste i konkretne: klient wrzuca kilkaset dokumentów firmowych i chce, żeby czat odpowiadał na ich podstawie. Pytanie „czy to działa" jest wtedy bez sensu, bo działa zawsze — odpowiada coś. Pytanie właściwe brzmi: na ilu pytaniach z tej bazy odpowiada poprawnie i z osadzeniem w źródle, a to wymaga wygenerowania zestawu testowego z samych dokumentów. Właśnie to robi ta funkcja.
Modularność i telemetria opisana uczciwie
Wersja trzecia jest rozbita na pakiety, z których każdy nosi tylko własne zależności. Stabilne są dwa: giskard-checks (scenariusze, sprawdzenia, sędziowie) oraz giskard-scan (skaner podatności i ewaluacja bazy wiedzy). Pod nimi leżą trzy biblioteki pomocnicze — wspólne narzędzia, routing do dostawców modeli oraz orkiestracja agentów — dociągane automatycznie i rzadko używane wprost. Dodatki instalacyjne dokładają zestawy SDK poszczególnych dostawców.
Osobno chcę wyróżnić sposób opisania telemetrii, bo jest wzorcowy i kontrastuje z tym, co spotyka się najczęściej. Dokumentacja podaje: telemetria jest opcjonalna i zagregowana, a prompty ani wyjścia nie są wysyłane. Wyłącza się ją jedną z dwóch zmiennych środowiskowych — w tym powszechnie przyjętą DO_NOT_TRACK — a jeśli ustawi się je przed importem, plik z identyfikatorem instalacji nie zostanie nawet utworzony; ustawienie później zatrzymuje dalsze wysyłki.
Ten poziom precyzji ma znaczenie praktyczne: przy narzędziu, które przetwarza prompty i odpowiedzi z systemu klienta, zdanie „prompty nie są wysyłane" wraz z opisem, co dokładnie dzieje się przy każdym wariancie wyłączenia, jest dokładnie tym, czego wymaga rozmowa o zgodności. Uszanowanie ustalonej w branży zmiennej zamiast wymyślania własnej też jest gestem wartym odnotowania.
Co zostało w wersji drugiej i nie wróci
To najważniejsze zastrzeżenie przy wyborze narzędzia i projekt stawia je otwarcie. Trzy rzeczy nie są planowane w wersji trzeciej:
- Automatyczny skan modeli tabelarycznych — czyli zestaw detektorów badających model wraz ze zbiorem danych i wykrywających problemy z wydajnością, uprzedzeniami i odpornością,
- Zestaw testów dla klasycznego uczenia maszynowego,
- Giskard Hub, czyli warstwa serwerowa.
Wniosek jest jednoznaczny i wart wypowiedzenia wprost: jeśli klient ma klasyczny model na danych tabelarycznych i pyta o wykrywanie uprzedzeń albo odporności, potrzebujesz wersji drugiej — która nie jest już aktywnie utrzymywana. Wersja trzecia obsłuży taki model tylko jako czarną skrzynkę owiniętą w funkcję celu, bez automatycznych detektorów zaglądających do środka. To jest realne zwężenie zakresu, a nie zmiana architektury.
Pułapki
- Sędziowie oparci na modelu kosztują przy każdym przebiegu i wymagają klucza API. Rozdziel sprawdzenia deterministyczne od tych z sędzią,
- Zestaw testów zależy od zewnętrznej usługi — awaria dostawcy da czerwone testy bez winy Twojego kodu,
- Domyślnym sędzią jest konkretny model konkretnego dostawcy; wynik oceny zależy od jego zachowania, więc jego podmiana zmienia wyniki testów,
- Wersja trzecia to przepisanie, a nie aktualizacja — kod oparty na wersji drugiej trzeba przenieść, nie podbić,
- Wersja druga nie jest już aktywnie utrzymywana, a mieszka w niej skan modeli tabelarycznych,
- Skan tabelaryczny, zestaw testów ML i Hub nie są planowane w wersji trzeciej,
- Wymagany Python 3.12 lub nowszy — na starszych środowiskach klienta to może być blokada,
- Testuj w języku docelowym; skan po angielsku nie mówi wiele o odporności czatu obsługującego po polsku,
- Skan generuje ataki, więc odpala je na Twoim systemie — uruchamiaj go na środowisku testowym, nie na produkcyjnym czacie z dostępem do danych klientów,
- Raport ze skanu nie jest audytem bezpieczeństwa. Brak znalezisk znaczy, że wygenerowane ataki nie przeszły, a nie że system jest odporny.
Gdzie to ma sens w naszej pracy
- Przed uruchomieniem czatu u klienta. Skan podatności z opisem w jednym zdaniu i raportem do przekazania — to jest usługa, którą da się wycenić i sprzedać osobno,
- Przy każdej podmianie modelu. Zestaw scenariuszy zamienia pytanie „czy nowy model jest lepszy" z opinii w wynik. Bez tego zmiana dostawcy jest skokiem w ciemność,
- Przy systemach odpowiadających z dokumentów klienta. Wygenerowany z bazy wiedzy zestaw testowy odpowiada na pytanie o skuteczność liczbą, a nie wrażeniem,
- Jako bramka przed wydaniem. Sprawdzenia deterministyczne przy każdej zmianie, sędziowie i skan w przebiegu nocnym,
- Do rozmowy o zgodności. Jawnie opisana telemetria i licencja permisywna sprawiają, że narzędzie przechodzi przegląd u klienta bez dyskusji,
- Jako wzorzec myślenia. Nawet nie instalując tej biblioteki, warto przyjąć jej rozróżnienie: cel, scenariusz, sprawdzenie, zestaw. Przenosi się wprost na własne testy pisane w PHPUnicie wokół funkcji korzystających z modelu.
Podsumowanie
- Ewaluacje są dla wyjść niedeterministycznych — tam, gdzie test jednostkowy nie ma czego sprawdzać,
- Cel to dowolna funkcja, więc żadnego frameworku agentowego nie trzeba przyjmować,
- Cztery pojęcia: cel, scenariusz, sprawdzenie, zestaw,
- Celem może być wywołanie HTTP do naszego punktu końcowego — testujesz wtedy pełny stos aplikacji, nie samo wywołanie modelu,
- Sprawdzenia deterministyczne przy każdej zmianie, sędziowie w nocy — bo sędzia to wywołanie modelu i koszt,
vulnerability_scangeneruje ataki z jednozdaniowego opisu agenta, w kategoriach OWASP LLM Top-10,- Skanuj w języku docelowym i wyłącznie na środowisku testowym,
quality_scanocenia systemy oparte na bazie wiedzy, generując zestaw testowy z dokumentów,- Telemetria jest opcjonalna, zagregowana i opisana precyzyjnie, z uszanowaniem zmiennej
DO_NOT_TRACK, - Wersja trzecia to przepisanie, a wersja druga nie jest już aktywnie utrzymywana,
- Skan modeli tabelarycznych i Hub zostały w wersji drugiej i nie są planowane dalej,
- Raport ze skanu to nie audyt — brak znalezisk nie jest dowodem odporności.
Licencja: Giskard jest na Apache-2.0, czyli najwygodniejszym wariancie licencji permisywnej dla pracy komercyjnej: wolno używać, modyfikować, wpinać w produkty zamknięte i redystrybuować, przy zachowaniu noty licencyjnej i pliku NOTICE, jeśli występuje, oraz odnotowaniu istotnych zmian w modyfikowanych plikach. Apache dokłada przy tym jawną licencję patentową od kontrybutorów, co przy narzędziu wchodzącym w obszar oceny i bezpieczeństwa modeli jest zaletą praktyczną, nie formalnością. Nie ma tu open core w wersji trzeciej — wszystkie pakiety, skaner podatności i sędziowie są na tych samych warunkach. Warto natomiast rozdzielić trzy rzeczy, których licencja nie obejmuje. Po pierwsze, Giskard Hub, czyli warstwa serwerowa firmy stojącej za projektem, jest osobnym produktem i — jak zapowiada dokumentacja — nie jest planowany w wersji trzeciej; jeśli klient oczekuje panelu z historią przebiegów, jest to rozmowa handlowa, nie instalacja. Po drugie, sędziowie i generatory ataków wołają modele zewnętrznych dostawców, więc obowiązują ich regulaminy i zasady przetwarzania danych — a przez sędziego przechodzą prompty i odpowiedzi z systemu klienta, co przy danych wrażliwych wymaga świadomej decyzji o wyborze dostawcy albo modelu lokalnego. Po trzecie, wygenerowane ładunki ataków są narzędziem podwójnego zastosowania: wolno je uruchamiać na systemie, którego testowanie ktoś nam zlecił, i tylko na takim. Licencja mówi o kodzie, a zgoda właściciela systemu jest sprawą osobną i konieczną.