Dlaczego testowanie agentów jest inne
Niedeterminizm, koszty LLM i powody, dla których standardowe testy jednostkowe nie wystarczają.
Dlaczego testowanie agentów jest inne to bezpłatna lekcja AI Agents na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej AI Agents, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs AI Agents zawiera 4 lekcji w sumie.
Testowanie oprogramowania a testowanie agentów
Tradycyjne oprogramowanie jest deterministyczne: dla tych samych danych wejściowych zwraca te same dane wyjściowe. Testy jednostkowe wykorzystują tę właściwość do sprawdzania dokładnie oczekiwanych wartości.
Agenci AI podważają to założenie. Ten sam prompt może przy każdym uruchomieniu generować inne wyniki, przez co standardowe podejścia do testowania nie są wystarczające.
Niedeterminizm: te same dane wejściowe, różne dane wyjściowe
LLM-y są z natury probabilistyczne. Parametr temperature kontroluje losowość — nawet przy wartości temperature=0 wyniki mogą się różnić między wersjami modelu lub po zmianach infrastruktury.
Oznacza to, że test agenta, który dziś przechodzi pomyślnie, jutro może się nie powieść mimo braku zmian w kodzie.
import openai
client = openai.OpenAI(api_key='YOUR_API_KEY')
# Same prompt, potentially different outputs each run
for i in range(3):
response = client.chat.completions.create(
model='gpt-4o-mini',
messages=[{'role': 'user', 'content': 'Name a planet.'}],
temperature=0.9 # High randomness
)
print(f'Run {i+1}: {response.choices[0].message.content}')
# Run 1: Mars
# Run 2: Jupiter
# Run 3: SaturnProblem kosztów: rzeczywiste wywołania LLM są drogie
Uruchomienie zestawu testów wykonującego rzeczywiste wywołania API OpenAI lub Anthropic może kosztować kilka dolarów za jedno uruchomienie. Potok CI uruchamiający 100 testów × 10 iteracji może kosztować setki dolarów miesięcznie.
Sprawia to, że testowanie agentów w taki sam sposób jak testów jednostkowych jest niepraktyczne — potrzebne są strategie kontroli kosztów.
# A test that calls the real API costs tokens every run
# 100 tests x 500 tokens each x 10 CI runs/day = 500,000 tokens/day
# At $0.15/1M tokens (gpt-4o-mini): ~$0.075/day = ~$27/year for a tiny suite
# For gpt-4o: 15x more expensive = ~$400/year
# This is why mocking and recording API responses is essential
print('Real API calls in tests = expensive and slow')
print('Solution: Mock or record LLM responses in unit tests')
print('Reserve real calls for scheduled integration tests')Problem opóźnień
Rzeczywiste wywołania API LLM trwają zazwyczaj od 2 do 20 sekund. Zestaw 50 testów potrzebowałby od 100 do 1000 sekund na uruchomienie. Obniża to produktywność programistów — szybkie uzyskiwanie informacji zwrotnej jest podstawową wartością dobrych testów.
Mockowanie wywołań LLM pozwala uruchamiać testy w milisekundach.
import time
# Simulating what a test suite looks like with real vs mocked calls
num_tests = 50
# Real API calls
real_time = num_tests * 5 # avg 5 seconds per call
print(f'With real API calls: {real_time}s = {real_time/60:.1f} minutes')
# Mocked calls
mock_time = num_tests * 0.001 # <1ms per mock
print(f'With mocked calls: {mock_time:.3f}s = nearly instant')
# Conclusion: mock in unit tests, use real calls in integration testsZależności zewnętrzne w testach agentów
Agenci często wywołują narzędzia zewnętrzne: interfejsy API wyszukiwarek, bazy danych, systemy plików i scrapery internetowe. W testach te zależności mogą:
- Być niedostępne (awaria sieci, przestój API)
- Zwracać inne dane przy każdym uruchomieniu
- Mieć limity zapytań blokujące potoki CI
W testach jednostkowych należy je kontrolować lub mockować.
# An agent might call multiple external services
# Each is a potential test failure point
def agent_pipeline(query: str) -> str:
search_results = search_web(query) # External: Tavily/Serper API
documents = fetch_documents(search_results) # External: HTTP calls
answer = llm_summarize(documents) # External: OpenAI API
saved = database_store(answer) # External: PostgreSQL
return answer
# In unit tests: mock ALL of these
# In integration tests: use sandboxed versions of real services
print('Each external call is a test reliability risk')Założenia standardowych testów jednostkowych
Standardowe frameworki do testów jednostkowych, takie jak pytest, zakładają, że:
- Testy są szybkie (trwają milisekundy)
- Testy są deterministyczne
- Testy nie wywołują zewnętrznych efektów ubocznych
- Testy można uruchamiać w dowolnej kolejności
Testy agentów naruszają wszystkie cztery założenia, chyba że zostaną odpowiednio zaprojektowane.
# Standard unit test — works perfectly for deterministic code
def add(a, b):
return a + b
def test_add():
assert add(2, 3) == 5 # Always passes — deterministic
# Agent 'unit test' that calls a real LLM — problematic
# def test_agent_answers_question():
# response = agent.run('What is 2+2?')
# assert response == '4' # Might return 'The answer is 4' or 'Four'
print('Exact string matching fails for LLM outputs')
print('Need structural or semantic assertions instead')Piramida testowania agentów
Praktyczna strategia testowania agentów ma strukturę piramidy:
- Testy jednostkowe (liczne, szybkie): testowanie pojedynczych narzędzi i funkcji z mockowanymi wywołaniami LLM
- Testy integracyjne (mniej liczne, wolniejsze): testowanie całego potoku agenta z użyciem usług uruchomionych w piaskownicy
- Testy ewaluacyjne (rzadkie, kosztowne): testowanie jakości wyników za pomocą rzeczywistych wywołań LLM i oceniania w stylu ludzkim
Asercje strukturalne a semantyczne
Zamiast dokładnego porównywania ciągów znaków testy agentów powinny używać asercji strukturalnych (czy agent wywołał właściwe narzędzie?) lub kontroli semantycznych (czy wynik zawiera odpowiednią koncepcję?).
# Fragile: exact string match
# assert response.content == 'The capital of France is Paris.'
# Better: structural assertion
# assert response.tool_calls[0]['function']['name'] == 'search_web'
# Better: semantic check
def test_capital_in_response(response_text: str) -> bool:
key_words = ['paris', 'france', 'capital']
lower = response_text.lower()
return all(word in lower for word in key_words)
response = 'Paris is the capital city of France.'
print(test_capital_in_response(response)) # TrueŚrodowiska ewaluacyjne i LLM-as-Judge
Do oceny jakości branża używa podejścia LLM-as-judge: prosi drugi LLM o ocenę wyniku agenta. Frameworki takie jak DeepEval i RAGAS automatyzują ten wzorzec.
To podejście jest przeznaczone do kosztownych uruchomień ewaluacyjnych, a nie do rutynowego CI.
import openai
client = openai.OpenAI(api_key='YOUR_API_KEY')
def llm_judge(question: str, answer: str) -> dict:
prompt = f'Question: {question}\nAnswer: {answer}\nRate the answer 1-5 for accuracy. Reply with only a number.'
response = client.chat.completions.create(
model='gpt-4o-mini',
messages=[{'role': 'user', 'content': prompt}]
)
score = int(response.choices[0].message.content.strip())
return {'score': score, 'pass': score >= 4}
# result = llm_judge('What is the capital of France?', 'Paris')
# print(result) # {'score': 5, 'pass': True}Testy regresji agentów
Po zaktualizowaniu promptu lub zmianie logiki agenta testy regresji sprawdzają, czy nie została uszkodzona istniejąca funkcjonalność. Należy zapisywać wzorcowe przykłady (dane wejściowe → oczekiwana struktura) i automatycznie uruchamiać je przy każdym commitcie.
# golden_examples.py
GOLDEN_EXAMPLES = [
{
'input': 'Search for the weather in Paris',
'expected_tool': 'get_weather',
'expected_args': {'city': 'Paris'}
},
{
'input': 'Calculate 15% tip on $45',
'expected_tool': 'calculate',
'expected_args': {'expression': '45 * 0.15'}
}
]
def run_regressions(agent, examples: list) -> int:
failures = 0
for ex in examples:
result = agent.plan(ex['input']) # mocked LLM
if result['tool'] != ex['expected_tool']:
print(f'FAIL: expected {ex["expected_tool"]}, got {result["tool"]}')
failures += 1
return failures
# --- demo: a stub agent whose .plan() mimics an LLM's tool choice ---
class _StubAgent:
def plan(self, text):
if 'weather' in text.lower():
return {'tool': 'get_weather'}
if 'tip' in text.lower() or 'calculate' in text.lower():
return {'tool': 'wrong_tool'} # simulate a regression
return {'tool': 'unknown'}
failures = run_regressions(_StubAgent(), GOLDEN_EXAMPLES)
print(f'{failures} of {len(GOLDEN_EXAMPLES)} golden examples failed')
Konfigurowanie podstawowego pliku testów agenta
Oto minimalna struktura pliku testów pytest dla agenta. Rozdziela ona szybkie testy jednostkowe (z mockami) od wolnych testów integracyjnych (z rzeczywistymi wywołaniami), dzięki czemu można uruchamiać tylko potrzebne testy.
# tests/test_agent.py
import pytest
# Fast unit tests — run on every commit
class TestAgentTools:
def test_tool_returns_dict(self, mock_llm):
result = my_tool(query='test')
assert isinstance(result, dict)
assert 'data' in result
def test_agent_selects_correct_tool(self, mock_llm):
response = agent.run('Search for Python tutorials')
assert response['tool_used'] == 'web_search'
# Slow integration tests — run nightly or on release
@pytest.mark.integration
class TestAgentIntegration:
def test_full_pipeline_with_real_api(self):
# Uses real OpenAI + sandboxed services
result = agent.run('Summarize the Python docs')
assert len(result['answer']) > 50Sprawdzenie wiedzy: dlaczego testowanie agentów jest inne
Proszę sprawdzić swoją wiedzę na temat wyjątkowych wyzwań związanych z testowaniem agentów AI.
Podsumowanie: Dlaczego testowanie agentów jest inne
Testowanie agentów AI wymaga innego podejścia niż standardowe testowanie jednostkowe:
- Niedeterministyczność: Te same dane wejściowe mogą dawać różne, poprawne wyniki
- Koszt: Rzeczywiste wywołania LLM są kosztowne — w testach jednostkowych należy je mockować
- Opóźnienie: Rzeczywiste wywołania API trwają sekundy — mocki działają w milisekundach
- Zewnętrzne zależności: Narzędzia i interfejsy API należy kontrolować w testach
- Asercje: Należy stosować sprawdzanie strukturalne i semantyczne, a nie dokładne porównywanie ciągów
Należy stosować piramidę testów: wiele tanich testów jednostkowych z mockami i mniej kosztownych testów integracyjnych z rzeczywistymi wywołaniami.
Ucz się AI Agents dzięki korepetycjom AI — za darmo
Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.
- Kursy
- 60
- Lekcje
- 239
Często zadawane pytania
Czy lekcja „Dlaczego testowanie agentów jest inne” jest bezpłatna?
Tak — pełny tekst „Dlaczego testowanie agentów jest inne” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu AI Agents, przejdź na CoddyKit PRO. Kurs AI Agents zawiera 4 lekcji w sumie.
Co nauczysz się w „Dlaczego testowanie agentów jest inne”?
Niedeterminizm, koszty LLM i powody, dla których standardowe testy jednostkowe nie wystarczają. Ćwiczysz AI Agents z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć AI Agents?
Nie wymagamy żadnego doświadczenia. AI Agents w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.
Ile czasu zajmuje lekcja „Dlaczego testowanie agentów jest inne”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji AI Agents?
Tak. Każda lekcja AI Agents zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Dlaczego testowanie agentów jest inne
- Mockowanie wywołań LLM w testach
- Testowanie agentów oparte na asercjach
- Testy integracyjne potoków agentów