0Pricing
AI Agents · Lección

Simulación de llamadas a LLM en pruebas

unittest.mock, fixtures de pytest y grabación y reproducción de respuestas de LLM.

Simulación de llamadas a LLM en pruebas es una lección gratuita de AI Agents en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de AI Agents, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de AI Agents incluye 4 lecciones en total.

¿Qué es el mocking?

El mocking reemplaza una función o un objeto real por una versión simulada que devuelve respuestas controladas. En las pruebas de agentes, simulamos las llamadas a la API de LLM para que las pruebas se ejecuten al instante, no tengan coste y produzcan resultados predecibles.

El módulo unittest.mock de Python es la herramienta estándar para esto.

Conceptos básicos de unittest.mock.patch()

unittest.mock.patch(target) reemplaza temporalmente el objeto indicado durante la ejecución de una prueba. target es una cadena de puntos que apunta al objeto tal como se importa en el módulo que se está probando.

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

Uso de patch como decorador en pytest

Cuando se usa como decorador con pytest, @patch() inyecta el mock como parámetro de la función. El mock se elimina automáticamente cuando termina la prueba.

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()

Creación de una respuesta mock reutilizable

Crear manualmente objetos de respuesta mock resulta prolijo. Cree una función auxiliar que construya objetos mock con la estructura correcta y que coincidan con la forma de las respuestas del SDK de 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)

Simulación de llamadas a herramientas en las respuestas

Al probar la lógica de llamadas a herramientas de un agente, la respuesta mock debe incluir un campo tool_calls con la estructura correcta para que el código de análisis del agente pueda procesarlo correctamente.

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)

Fixtures de pytest para mocking

Las fixtures de pytest permiten definir código de configuración reutilizable. Cree una fixture que aplique un parche al cliente de LLM y lo proporcione a cualquier prueba que lo solicite; así no necesitará repetir código.

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 fixture mocker de pytest-mock

pytest-mock proporciona una fixture mocker que simplifica la aplicación de parches. Limpia los mocks automáticamente y ofrece una sintaxis más clara que unittest.mock.patch sin abstracciones.

# 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

Grabación y reproducción con vcr.py

vcrpy graba las interacciones HTTP reales en un archivo de «cassette» durante la primera ejecución y después las reproduce en las ejecuciones posteriores. Es ideal para probar código que usa la API HTTP directamente en lugar de 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

Comprobación de que el mock se llamó correctamente

Después de una prueba, verifique que el mock se llamó con los argumentos correctos. Esto detecta errores en los que el agente envía un modelo equivocado, omite parámetros o utiliza mensajes incorrectos.

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'

Simulación de errores de API en las pruebas

Pruebe cómo gestiona su agente los fallos del LLM configurando el mock para que genere excepciones. Así podrá verificar el manejo de errores y la lógica de reintentos sin provocar fallos reales de la 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

Organización de fixtures mock en conftest.py

Coloque las fixtures compartidas en conftest.py, en la raíz del directorio de pruebas. pytest detecta este archivo automáticamente y hace que las fixtures estén disponibles para todos los archivos de pruebas sin necesidad de importarlas.

# 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

Comprobación de conocimientos: simulación de llamadas a LLM

Compruebe sus conocimientos sobre las técnicas de mocking para las pruebas de agentes.

Recapitulación: simulación de llamadas a LLM en las pruebas

Ahora dispone de las herramientas necesarias para escribir pruebas unitarias de agentes rápidas y fiables:

  • Use unittest.mock.patch() para reemplazar los clientes de LLM por mocks
  • Cree funciones auxiliares reutilizables para respuestas mock que coincidan con la estructura de respuestas del SDK
  • Simule las llamadas a herramientas con campos tool_calls estructurados correctamente
  • Use fixtures de pytest y conftest.py para compartir mocks entre pruebas
  • Use pytest-mock para disponer de una sintaxis más clara
  • Use vcrpy para grabar y reproducir interacciones HTTP reales

Los mocks son la base de una suite de pruebas de agentes rápida y fácil de mantener.

Preguntas frecuentes

¿La lección «Simulación de llamadas a LLM en pruebas» es gratis?

Sí — el texto completo de «Simulación de llamadas a LLM en pruebas» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de AI Agents, actualiza a CoddyKit PRO. El curso de AI Agents incluye 4 lecciones en total.

¿Qué aprenderé en «Simulación de llamadas a LLM en pruebas»?

unittest.mock, fixtures de pytest y grabación y reproducción de respuestas de LLM. Practicas AI Agents con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar AI Agents?

No se requiere experiencia previa. AI Agents en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.

¿Cuánto tiempo toma la lección «Simulación de llamadas a LLM en pruebas»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de AI Agents?

Sí. Cada lección de AI Agents incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Por qué probar agentes es diferente
  2. Simulación de llamadas a LLM en pruebas
  3. Pruebas de agentes basadas en aserciones
  4. Pruebas de integración para pipelines de agentes
← Volver a AI Agents