0Pricing
AI Agents · Leçon

Simuler les appels aux LLM dans les tests

unittest.mock, fixtures pytest et enregistrement/relecture des réponses des LLM.

Simuler les appels aux LLM dans les tests est une leçon AI Agents gratuite sur CoddyKit. Ceci est la leçon 2 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage AI Agents, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours AI Agents comprend 4 leçons au total.

Qu'est-ce que la simulation ?

La simulation remplace une fonction ou un objet réel par une version factice qui renvoie des réponses contrôlées. Lors des tests d'agents, nous simulons les appels aux API LLM afin que les tests s'exécutent instantanément, ne coûtent rien et produisent des résultats prévisibles.

Le module Python unittest.mock est l'outil standard pour cela.

Notions de base de unittest.mock.patch()

unittest.mock.patch(target) remplace temporairement l'objet nommé pendant toute la durée d'un test. La target est une chaîne de caractères avec points qui pointe vers l'objet tel qu'il est importé dans le module testé.

from unittest.mock import patch, MagicMock

# The function under test calls openai.chat.completions.create
# We patch it so no real API call is made

def ask_llm(question: str) -> str:
    import openai
    client = openai.OpenAI(api_key='test')
    resp = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role': 'user', 'content': question}]
    )
    return resp.choices[0].message.content

with patch('openai.OpenAI') as mock_client_class:
    mock_instance = MagicMock()
    mock_client_class.return_value = mock_instance
    mock_instance.chat.completions.create.return_value = MagicMock(
        choices=[MagicMock(message=MagicMock(content='Paris'))]
    )
    result = ask_llm('Capital of France?')
    print(result)  # 'Paris' — no API call made

Utiliser patch comme décorateur dans pytest

Utilisé comme décorateur avec pytest, @patch() injecte la simulation comme paramètre de fonction. La simulation est automatiquement supprimée une fois le test terminé.

from unittest.mock import patch, MagicMock
import pytest

# Assume agent.py contains: import openai; client = openai.OpenAI(...)

@patch('agent.openai.OpenAI')
def test_agent_calls_llm(mock_openai_class):
    # Set up the mock chain
    mock_client = MagicMock()
    mock_openai_class.return_value = mock_client
    mock_client.chat.completions.create.return_value = MagicMock(
        choices=[MagicMock(message=MagicMock(content='Paris is the capital of France.'))]
    )

    from agent import ask_llm
    result = ask_llm('What is the capital of France?')

    assert 'Paris' in result
    mock_client.chat.completions.create.assert_called_once()

Créer une réponse simulée réutilisable

Construire manuellement des objets de réponse simulés est verbeux. Créez une fonction utilitaire qui construit des objets simulés correctement structurés et correspondant à la forme des réponses du SDK OpenAI.

from unittest.mock import MagicMock

def make_mock_response(content: str, tool_calls: list = None) -> MagicMock:
    message = MagicMock()
    message.content = content
    message.tool_calls = tool_calls or []

    choice = MagicMock()
    choice.message = message
    choice.finish_reason = 'stop' if not tool_calls else 'tool_calls'

    response = MagicMock()
    response.choices = [choice]
    response.usage = MagicMock(total_tokens=42)
    return response

# Usage in tests:
# mock_create.return_value = make_mock_response('Hello!')
# mock_create.return_value = make_mock_response('', tool_calls=[...])

# --- demo ---
response = make_mock_response('The weather in Paris is 18C and sunny.')
print('content:', response.choices[0].message.content)
print('finish_reason:', response.choices[0].finish_reason)
print('total_tokens:', response.usage.total_tokens)

Simuler les appels d'outils dans les réponses

Lors du test de la logique d'appel d'outils d'un agent, la réponse simulée doit inclure un champ tool_calls correctement structuré afin que le code d'analyse de l'agent puisse le traiter correctement.

import json
from unittest.mock import MagicMock

def make_tool_call_response(tool_name: str, arguments: dict) -> MagicMock:
    tool_call = MagicMock()
    tool_call.id = 'call_abc123'
    tool_call.type = 'function'
    tool_call.function = MagicMock()
    tool_call.function.name = tool_name
    tool_call.function.arguments = json.dumps(arguments)

    message = MagicMock()
    message.content = None
    message.tool_calls = [tool_call]

    response = MagicMock()
    response.choices = [MagicMock(message=message, finish_reason='tool_calls')]
    return response

# mock.return_value = make_tool_call_response('search_web', {'query': 'Python tutorials'})

# --- demo ---
response = make_tool_call_response('search_web', {'query': 'Python tutorials'})
call = response.choices[0].message.tool_calls[0]
print('tool name:', call.function.name)
print('tool arguments:', call.function.arguments)
print('finish_reason:', response.choices[0].finish_reason)

Fonctions de préparation pytest pour la simulation

Les fonctions de préparation de pytest permettent de définir du code de préparation réutilisable. Créez une fonction de préparation qui applique un patch au client LLM et le fournit à tout test qui le demande — sans répétition.

import pytest
from unittest.mock import patch, MagicMock

@pytest.fixture
def mock_openai(make_mock_response):
    with patch('myagent.client.chat.completions.create') as mock_create:
        mock_create.return_value = MagicMock(
            choices=[MagicMock(message=MagicMock(
                content='Default mocked response',
                tool_calls=[]
            ))]
        )
        yield mock_create

# Now any test can use it:
def test_agent_responds(mock_openai):
    from myagent import agent
    result = agent.run('Hello')
    assert result is not None
    mock_openai.assert_called_once()

La fonction de préparation mocker de pytest-mock

pytest-mock fournit une fonction de préparation mocker qui simplifie l'application de patchs. Elle nettoie automatiquement les simulations et offre une syntaxe plus claire que unittest.mock.patch utilisé directement.

# pip install pytest-mock

# In your test file:
def test_agent_with_mocker(mocker):
    mock_create = mocker.patch('myagent.client.chat.completions.create')
    mock_create.return_value = mocker.MagicMock(
        choices=[mocker.MagicMock(message=mocker.MagicMock(
            content='Mocked answer',
            tool_calls=[]
        ))]
    )

    from myagent import agent
    result = agent.run('What is 2+2?')
    assert 'answer' in result.lower() or '4' in result

    mock_create.assert_called_once()
    # No cleanup needed — mocker handles it

Enregistrer et rejouer avec vcr.py

vcrpy enregistre les interactions HTTP réelles dans un fichier « cassette » lors de la première exécution, puis les rejoue lors des exécutions suivantes. C'est idéal pour tester du code qui utilise l'API HTTP brute plutôt qu'un SDK.

# pip install vcrpy
import vcr
import httpx

@vcr.use_cassette('fixtures/cassettes/openai_chat.yaml')
def test_with_recorded_response():
    # First run: makes a real HTTP call and records it
    # Subsequent runs: uses the recorded cassette (no network, no cost)
    response = httpx.post(
        'https://api.openai.com/v1/chat/completions',
        json={'model': 'gpt-4o-mini', 'messages': [{'role': 'user', 'content': 'Hello'}]},
        headers={'Authorization': 'Bearer YOUR_KEY'}
    )
    data = response.json()
    assert data['choices'][0]['message']['content'] is not None

Vérifier qu'une simulation a été appelée correctement

Après un test, vérifiez que la simulation a été appelée avec les bons arguments. Cela détecte les erreurs où l'agent envoie le mauvais modèle, omet des paramètres ou transmet des messages incorrects.

from unittest.mock import patch, MagicMock, call

@patch('myagent.client.chat.completions.create')
def test_agent_sends_correct_model(mock_create):
    mock_create.return_value = MagicMock(
        choices=[MagicMock(message=MagicMock(content='ok', tool_calls=[]))]
    )

    from myagent import agent
    agent.run('Hello')

    # Verify the mock was called with correct arguments
    mock_create.assert_called_once()
    call_kwargs = mock_create.call_args.kwargs
    assert call_kwargs['model'] == 'gpt-4o-mini'
    assert len(call_kwargs['messages']) >= 1
    assert call_kwargs['messages'][0]['role'] == 'system'

Simuler des erreurs d'API dans les tests

Testez la manière dont votre agent gère les échecs des LLM en configurant la simulation pour qu'elle lève des exceptions. Cela vérifie votre gestion des erreurs et votre logique de nouvelle tentative sans provoquer de véritables défaillances d'API.

from unittest.mock import patch
import openai

@patch('myagent.client.chat.completions.create')
def test_agent_handles_rate_limit(mock_create):
    # Simulate a rate limit error
    mock_create.side_effect = openai.RateLimitError(
        message='Rate limit exceeded',
        response=None,
        body=None
    )

    from myagent import agent
    result = agent.run('Hello')

    # Agent should handle this gracefully
    assert result['error'] == 'rate_limit'
    # or
    assert result['retry_after'] is not None

Organiser les fonctions de préparation de simulation dans conftest.py

Placez les fonctions de préparation partagées dans conftest.py à la racine de votre répertoire de tests. pytest découvre automatiquement ce fichier et rend ces fonctions disponibles dans tous les fichiers de test, sans qu'il soit nécessaire de les importer.

# tests/conftest.py
import pytest
from unittest.mock import patch, MagicMock

@pytest.fixture(autouse=False)
def mock_llm():
    with patch('myagent.client.chat.completions.create') as mock_create:
        mock_create.return_value = MagicMock(
            choices=[MagicMock(message=MagicMock(
                content='Test response',
                tool_calls=[]
            ))]
        )
        yield mock_create

@pytest.fixture
def mock_search_tool():
    with patch('myagent.tools.search_web') as mock_search:
        mock_search.return_value = [{'title': 'Test', 'url': 'https://example.com'}]
        yield mock_search

Vérification des connaissances : simuler les appels LLM

Testez votre compréhension des techniques de simulation pour les tests d'agents.

Récapitulatif : simuler les appels LLM dans les tests

Vous disposez maintenant des outils nécessaires pour écrire des tests unitaires d'agents rapides et fiables :

  • Utilisez unittest.mock.patch() pour remplacer les clients LLM par des simulations
  • Créez des fonctions utilitaires réutilisables pour les réponses simulées, correspondant à la forme des réponses du SDK
  • Simulez les appels d'outils avec des champs tool_calls correctement structurés
  • Utilisez les fonctions de préparation pytest et conftest.py pour partager les simulations entre les tests
  • Utilisez pytest-mock pour bénéficier d'une syntaxe plus claire
  • Utilisez vcrpy pour enregistrer et rejouer les interactions HTTP réelles

Les simulations constituent la base d'une suite de tests d'agents rapide et facile à maintenir.

Questions Fréquemment Posées

La leçon « Simuler les appels aux LLM dans les tests » est-elle gratuite ?

Oui — le texte complet de « Simuler les appels aux LLM dans les tests » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours AI Agents, passe à CoddyKit PRO. Le cours AI Agents comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Simuler les appels aux LLM dans les tests » ?

unittest.mock, fixtures pytest et enregistrement/relecture des réponses des LLM. Tu pratiques AI Agents avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer AI Agents ?

Aucune expérience préalable n'est requise. AI Agents sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 4.

Combien de temps prend la leçon « Simuler les appels aux LLM dans les tests » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon AI Agents ?

Oui. Chaque leçon AI Agents inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Pourquoi tester les agents est différent
  2. Simuler les appels aux LLM dans les tests
  3. Tester les agents par assertions
  4. Tests d’intégration pour les pipelines d’agents
← Retour à AI Agents