AI Agents · Lektion

Assertion-basiertes Agenten-Testing

Tool-Aufrufe, Zwischenschritte und die Struktur der finalen Ausgabe prüfen.

Lektion 3 von 413 Schritte

Assertion-basiertes Agenten-Testing ist eine kostenlose AI Agents-Lektion auf CoddyKit. Dies ist Lektion 3 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des AI Agents-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der AI Agents-Kurs umfasst insgesamt 4 Lektionen.

Über den exakten String-Vergleich hinaus

Da LLM-Ausgaben nichtdeterministisch sind, ist das Testen mit assert response == 'exact text' fragil. Schreiben Sie stattdessen Assertions, die die Struktur und Absicht der Antwort prüfen, ohne von einer exakt gleichen Formulierung abhängig zu sein.

Prüfen, ob Tool-Aufrufe ausgeführt wurden

Bei Agents mit Function Calling ist die zuverlässigste Assertion die Überprüfung, ob der Agent den richtigen Tool-Aufruf ausgewählt hat. Das ist eine strukturelle Prüfung und hängt nicht von der genauen Formulierung des Denkprozesses des LLM ab.

import json
from unittest.mock import patch, MagicMock

@patch('myagent.client.chat.completions.create')
def test_agent_calls_search_tool(mock_create):
    # Mock: agent decides to call search_web
    tool_call = MagicMock()
    tool_call.function.name = 'search_web'
    tool_call.function.arguments = json.dumps({'query': 'Python tutorials'})
    mock_create.return_value = MagicMock(
        choices=[MagicMock(message=MagicMock(tool_calls=[tool_call]))]
    )

    response = mock_create()  # simulating the agent call
    tc = response.choices[0].message.tool_calls

    assert tc is not None
    assert len(tc) > 0
    assert tc[0].function.name == 'search_web'

# --- demo: give unittest.mock.patch a real dotted path to patch ---
import sys
import types

_myagent = types.ModuleType('myagent')
_myagent.client = types.SimpleNamespace(
    chat=types.SimpleNamespace(completions=types.SimpleNamespace(create=lambda *a, **k: None))
)
sys.modules['myagent'] = _myagent

test_agent_calls_search_tool()
print('test_agent_calls_search_tool: PASS')

Den korrekten Tool-Namen prüfen

Prüfen Sie nicht nur, ob Tool-Aufrufe vorhanden sind, sondern auch, ob der konkrete Tool-Name den Erwartungen entspricht. So erkennen Sie Fälle, in denen der Agent für eine bestimmte Anfrage das falsche Tool auswählt.

import json
from unittest.mock import MagicMock

def extract_tool_calls(response) -> list:
    message = response.choices[0].message
    if not message.tool_calls:
        return []
    return [
        {
            'name': tc.function.name,
            'args': json.loads(tc.function.arguments)
        }
        for tc in message.tool_calls
    ]

# In a test:
# calls = extract_tool_calls(mock_response)
# assert calls[0]['name'] == 'get_weather'
# assert calls[0]['args']['city'] == 'Paris'
print('Tool name and argument assertions are the most reliable agent tests')

Tool-Argumente prüfen

Nachdem Sie den Tool-Namen überprüft haben, prüfen Sie, ob die Argumente korrekt sind. Der Agent muss nicht nur das richtige Tool auswählen, sondern es auch mit den richtigen Parametern aus der Anfrage des Benutzers füllen.

import json
from unittest.mock import patch, MagicMock

@patch('myagent.client.chat.completions.create')
def test_weather_tool_gets_correct_city(mock_create):
    tool_call = MagicMock()
    tool_call.function.name = 'get_weather'
    tool_call.function.arguments = json.dumps({'city': 'Tokyo', 'unit': 'celsius'})
    mock_create.return_value = MagicMock(
        choices=[MagicMock(message=MagicMock(tool_calls=[tool_call]))]
    )

    response = mock_create()
    args = json.loads(response.choices[0].message.tool_calls[0].function.arguments)

    assert args['city'] == 'Tokyo'
    assert args.get('unit') in ['celsius', 'fahrenheit', None]  # flexible

# --- demo: give unittest.mock.patch a real dotted path to patch ---
import sys
import types

_myagent = types.ModuleType('myagent')
_myagent.client = types.SimpleNamespace(
    chat=types.SimpleNamespace(completions=types.SimpleNamespace(create=lambda *a, **k: None))
)
sys.modules['myagent'] = _myagent

test_weather_tool_gets_correct_city()
print('test_weather_tool_gets_correct_city: PASS')

JSON-Schema-Validierung für Ausgaben

Wenn Ihr Agent strukturiertes JSON zurückgibt, validieren Sie die Ausgabe anhand eines JSON-Schemas, um sicherzustellen, dass alle erforderlichen Felder vorhanden sind und die richtigen Typen haben. Die Bibliothek jsonschema macht dies einfach.

# pip install jsonschema
import jsonschema

AGENT_RESPONSE_SCHEMA = {
    'type': 'object',
    'required': ['answer', 'sources', 'confidence'],
    'properties': {
        'answer': {'type': 'string', 'minLength': 1},
        'sources': {
            'type': 'array',
            'items': {'type': 'string', 'format': 'uri'}
        },
        'confidence': {'type': 'number', 'minimum': 0, 'maximum': 1}
    }
}

def test_agent_output_schema(agent_output: dict):
    try:
        jsonschema.validate(instance=agent_output, schema=AGENT_RESPONSE_SCHEMA)
        print('Schema validation passed')
    except jsonschema.ValidationError as e:
        raise AssertionError(f'Invalid agent output: {e.message}')

Assertions auf das Vorhandensein von Schlüsselwörtern

Bei Textantworten, deren genaue Formulierung variieren kann, prüfen Sie, ob wichtige Konzepte oder Wörter in der Ausgabe vorkommen. Das ist flexibel und dennoch aussagekräftig – die Antwort des Agenten muss zumindest die relevanten Begriffe erwähnen.

def assert_keywords_present(text: str, keywords: list, require_all: bool = True):
    lower_text = text.lower()
    found = [kw.lower() in lower_text for kw in keywords]

    if require_all:
        missing = [kw for kw, f in zip(keywords, found) if not f]
        assert not missing, f'Missing keywords: {missing}'
    else:
        assert any(found), f'None of {keywords} found in: {text[:100]}'

# Tests
response = 'The capital city of France is Paris, located in western Europe.'
assert_keywords_present(response, ['paris', 'france', 'capital'])
print('All keywords present!')  # passes

assert_keywords_present(response, ['spain', 'france'], require_all=False)
print('At least one keyword present!')  # passes

Das Antwortformat prüfen: Typprüfungen

Typprüfungen sind schnell und zuverlässig. Überprüfen Sie, dass der Agent ein dict und nicht None zurückgibt, dass Listenfelder Listen sind und dass numerische Felder innerhalb gültiger Wertebereiche liegen.

def test_agent_returns_valid_structure(agent_result):
    # Type checks
    assert isinstance(agent_result, dict), 'Result must be a dict'
    assert isinstance(agent_result.get('answer'), str), 'answer must be a string'
    assert isinstance(agent_result.get('steps'), list), 'steps must be a list'

    # Non-empty checks
    assert len(agent_result['answer']) > 0, 'answer must not be empty'
    assert len(agent_result['steps']) >= 1, 'must have at least one step'

    # Range checks
    confidence = agent_result.get('confidence', 0)
    assert 0.0 <= confidence <= 1.0, 'confidence must be 0-1'

print('Structural assertions are fast and reliable')

finish_reason prüfen

Das Feld finish_reason gibt an, warum das Modell die Generierung beendet hat. Die Prüfung dieses Feldes hilft, Probleme zu erkennen: 'stop' bedeutet eine ordnungsgemäß beendete Antwort, 'tool_calls' bedeutet, dass der Agent ein Tool aufrufen möchte, und 'length' bedeutet, dass die Ausgabe abgeschnitten wurde.

from unittest.mock import MagicMock

def test_agent_stops_cleanly(mock_response):
    finish_reason = mock_response.choices[0].finish_reason
    assert finish_reason in ('stop', 'tool_calls'), \
        f'Unexpected finish_reason: {finish_reason}'

def test_no_truncation(mock_response):
    finish_reason = mock_response.choices[0].finish_reason
    assert finish_reason != 'length', \
        'Response was truncated — increase max_tokens'

# Example mock for a clean stop
mock = MagicMock()
mock.choices = [MagicMock(finish_reason='stop')]
test_agent_stops_cleanly(mock)
print('finish_reason: stop — clean termination')

Die Anzahl der Schleifendurchläufe prüfen

Ein Agent, der in einer Schleife ausgeführt wird, sollte innerhalb einer angemessenen Anzahl von Schritten abgeschlossen werden. Prüfen Sie, dass der Agent innerhalb einer maximalen Anzahl von Iterationen fertig wird – so erkennen Sie Endlosschleifen, die durch Ihre max_iterations-Schranke verhindert werden sollen.

def test_agent_completes_in_bounded_steps(mock_agent):
    result = mock_agent.run('Search for the weather in Paris')

    # Agent should complete within 5 steps
    assert result['steps_taken'] <= 5, \
        f'Agent took too many steps: {result["steps_taken"]}'

    # Agent should produce a final answer, not exit on timeout
    assert result['status'] == 'completed', \
        f'Agent did not complete: {result["status"]}'

    assert result['answer'] is not None

print('Bounding step count prevents runaway agents from passing tests')

Tests für mehrere Eingaben parametrisieren

Mit @pytest.mark.parametrize von pytest können Sie denselben Test mit vielen verschiedenen Eingaben ausführen. Das eignet sich ideal, um zu prüfen, ob Ihr Agent unterschiedliche Abfragetypen an die richtigen Tools weiterleitet.

import pytest
from unittest.mock import patch, MagicMock
import json

@pytest.mark.parametrize('query,expected_tool', [
    ('What is the weather in Tokyo?', 'get_weather'),
    ('Calculate 15% of 200', 'calculator'),
    ('Search for Python books', 'web_search'),
    ('What time is it in Berlin?', 'get_time'),
])
@patch('myagent.client.chat.completions.create')
def test_agent_tool_routing(mock_create, query, expected_tool):
    tool_call = MagicMock()
    tool_call.function.name = expected_tool
    tool_call.function.arguments = json.dumps({'input': query})
    mock_create.return_value = MagicMock(
        choices=[MagicMock(message=MagicMock(tool_calls=[tool_call]))]
    )
    response = mock_create()
    actual = response.choices[0].message.tool_calls[0].function.name
    assert actual == expected_tool

Benutzerdefinierte Assertion-Hilfsfunktionen schreiben

Wenn Ihre Testsuite für Agenten wächst, lagern Sie wiederkehrende Assertion-Muster in Hilfsfunktionen aus. Dadurch werden Tests kürzer, lesbarer und leichter wartbar, wenn sich das Antwortformat des Agenten ändert.

import json

def assert_tool_called(response, tool_name: str, required_args: dict = None):
    message = response.choices[0].message
    assert message.tool_calls, 'Expected tool call but got plain text'
    names = [tc.function.name for tc in message.tool_calls]
    assert tool_name in names, f'Expected {tool_name}, got {names}'

    if required_args:
        for tc in message.tool_calls:
            if tc.function.name == tool_name:
                args = json.loads(tc.function.arguments)
                for key, val in required_args.items():
                    assert args.get(key) == val, \
                        f'Arg {key}: expected {val}, got {args.get(key)}'

# Clean test using the helper:
# assert_tool_called(response, 'get_weather', {'city': 'Paris'})

# --- demo ---
from unittest.mock import MagicMock

tool_call = MagicMock()
tool_call.function.name = 'get_weather'
tool_call.function.arguments = json.dumps({'city': 'Paris'})
response = MagicMock(choices=[MagicMock(message=MagicMock(tool_calls=[tool_call]))])

assert_tool_called(response, 'get_weather', {'city': 'Paris'})
print('assert_tool_called passed: agent called get_weather with city=Paris')

Wissenscheck: Assertions für Agententests

Testen Sie Ihr Verständnis der Assertion-Strategien für Agententests.

Zusammenfassung: Assertions für Agententests

Sie verfügen nun über ein vollständiges Assertion-Werkzeugset für Agententests:

  • Prüfen Sie, dass tool_calls nicht leer ist, wenn der Agent ein Tool verwenden soll
  • Prüfen Sie den korrekten Tool-Namen mit tc.function.name == 'expected_tool'
  • Validieren Sie Tool-Argumente, indem Sie tc.function.arguments als JSON parsen
  • Verwenden Sie jsonschema.validate() zur Validierung strukturierter Ausgaben
  • Verwenden Sie Prüfungen auf das Vorhandensein von Schlüsselwörtern für flexible Text-Assertions
  • Prüfen Sie finish_reason und die Schrittanzahl bei Agenten mit Schleifen
  • Verwenden Sie @pytest.mark.parametrize für Szenarien mit mehreren Eingaben
Kostenlos starten

Lerne AI Agents mit einem KI-Tutor — kostenlos

Schreibe und führe echten Code in deinem Browser aus, bekomme sofortige Hilfe von einem 24/7 KI-Tutor und setze dein Lernen im Web oder in der App fort.

Kurse
60
Lektionen
239

Häufig gestellte Fragen

Ist die Lektion „Assertion-basiertes Agenten-Testing“ kostenlos?

Ja — der vollständige Text von „Assertion-basiertes Agenten-Testing“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des AI Agents-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der AI Agents-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Assertion-basiertes Agenten-Testing“?

Tool-Aufrufe, Zwischenschritte und die Struktur der finalen Ausgabe prüfen. Du übst AI Agents mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um AI Agents zu starten?

Keine Vorkenntnisse erforderlich. AI Agents auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 4.

Wie lange dauert die Lektion „Assertion-basiertes Agenten-Testing“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser AI Agents-Lektion Code schreiben und ausführen?

Ja. Jede AI Agents-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Warum das Testen von Agenten anders ist
  2. LLM-Aufrufe in Tests mocken
  3. Assertion-basiertes Agenten-Testing
  4. Integrationstests für Agenten-Pipelines
← Zurück zu AI Agents