محاكاة استدعاءات LLM في الاختبارات
unittest.mock وpytest fixtures وتسجيل استجابات LLM وإعادة تشغيلها
محاكاة استدعاءات LLM في الاختبارات درس مجاني في AI Agents على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في AI Agents، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة AI Agents 4 دروس في المجموع.
ما المقصود بالمحاكاة الوهمية؟
تستبدل المحاكاة الوهمية دالة أو كائنًا فعليًا بإصدار وهمي يعيد استجابات يمكن التحكم فيها. عند اختبار الوكلاء، نحاكي استدعاءات LLM إلى API، لكي تعمل الاختبارات فورًا ومن دون تكلفة وتنتج نتائج متوقعة.
تُعد وحدة unittest.mock في Python الأداة القياسية لذلك.
أساسيات unittest.mock.patch()
تستبدل unittest.mock.patch(target) الكائن المسمى مؤقتًا طوال مدة الاختبار. ويمثل target سلسلة نصية منقوطة تشير إلى الكائن بالطريقة التي جرى استيراده بها في الوحدة قيد الاختبار.
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استخدام patch كمُزخرف في pytest
عند استخدام @patch() كمُزخرف مع pytest، تُمرر المحاكاة الوهمية إلى الدالة كمعامل. وتُزال المحاكاة الوهمية تلقائيًا بعد اكتمال الاختبار.
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()إنشاء استجابة وهمية قابلة لإعادة الاستخدام
إنشاء كائنات استجابة وهمية يدويًا أمر مطوّل. أنشئ دالة مساعدة لإنشاء كائنات وهمية منظمة بصورة صحيحة، وتطابق بنية استجابة OpenAI SDK.
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)
محاكاة استدعاءات الأدوات في الاستجابات
عند اختبار منطق استدعاء الأدوات لدى وكيل، يجب أن تتضمن الاستجابة الوهمية حقل tool_calls منظمًا بصورة صحيحة، حتى يتمكن كود تحليل الوكيل من معالجته بشكل صحيح.
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 في pytest للمحاكاة الوهمية
تتيح لك fixtures في pytest تعريف كود إعداد قابل لإعادة الاستخدام. أنشئ fixture تُجري تصحيحًا للعميل الخاص بـ LLM وتوفره لأي اختبار يطلبه — من دون تكرار.
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()Fixture المسمى mocker من pytest-mock
توفر pytest-mock fixture باسم mocker لتبسيط التصحيح. فهي تنظف الكائنات الوهمية تلقائيًا، وتوفر صياغة أوضح من unittest.mock.patch الخام.
# 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التسجيل وإعادة التشغيل باستخدام vcr.py
تسجل vcrpy تفاعلات HTTP الفعلية في ملف «cassette» عند التشغيل الأول، ثم تعيد تشغيلها في عمليات التشغيل اللاحقة. وهذا مثالي لاختبار الكود الذي يستخدم HTTP API الخام بدلًا من 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التحقق من استدعاء المحاكاة الوهمية بشكل صحيح
بعد الاختبار، تحقّق من استدعاء المحاكاة الوهمية بالمعاملات الصحيحة. فهذا يكشف الأخطاء التي يرسل فيها الوكيل النموذج الخطأ أو معاملات مفقودة أو رسائل غير صحيحة.
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'محاكاة أخطاء API في الاختبارات
اختبر كيفية تعامل وكيلك مع إخفاقات LLM من خلال إعداد المحاكاة الوهمية لرفع استثناءات. وبذلك تتحقق من معالجة الأخطاء ومنطق إعادة المحاولة، من دون التسبب في إخفاقات فعلية في 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تنظيم fixtures الوهمية في conftest.py
ضع fixtures المشتركة في conftest.py في جذر مجلد الاختبارات. يكتشف pytest هذا الملف تلقائيًا، ويتيح fixtures لجميع ملفات الاختبار من دون استيرادها.
# 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اختبار المعرفة: محاكاة استدعاءات LLM
اختبر مدى فهمك لتقنيات المحاكاة الوهمية في اختبارات الوكلاء.
ملخص: محاكاة استدعاءات LLM في الاختبارات
أصبحت لديك الآن الأدوات اللازمة لكتابة اختبارات وحدات سريعة وموثوقة للوكلاء:
- استخدم
unittest.mock.patch()لاستبدال عملاء LLM بكائنات وهمية - أنشئ دوال مساعدة قابلة لإعادة الاستخدام للاستجابات الوهمية، بحيث تطابق بنية استجابة SDK
- حاكِ استدعاءات الأدوات باستخدام حقول
tool_callsمنظمة بصورة صحيحة - استخدم fixtures في pytest و
conftest.pyلمشاركة الكائنات الوهمية بين الاختبارات - استخدم
pytest-mockللحصول على صياغة أوضح - استخدم
vcrpyلتسجيل تفاعلات HTTP الفعلية وإعادة تشغيلها
تشكل الكائنات الوهمية أساس مجموعة اختبارات وكلاء سريعة وسهلة الصيانة.
تعلم AI Agents مع معلم ذكاء اصطناعي — مجانًا
اكتب وقم بتشغيل أكوادك الفعلية في المتصفح، واحصل على مساعدة فورية من معلم ذكاء اصطناعي متاح 24/7، واستمر من حيث توقفت على الويب أو في التطبيق.
- الدورات
- 60
- الدروس
- 239
الأسئلة الشائعة
هل درس «محاكاة استدعاءات LLM في الاختبارات» مجاني؟
نعم — نص درس «محاكاة استدعاءات LLM في الاختبارات» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة AI Agents، انتقل إلى CoddyKit PRO. تتضمن دورة AI Agents 4 دروس في المجموع.
ماذا ستتعلم في «محاكاة استدعاءات LLM في الاختبارات»؟
unittest.mock وpytest fixtures وتسجيل استجابات LLM وإعادة تشغيلها تتمرن على AI Agents مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ AI Agents؟
لا تُشترط خبرة سابقة. AI Agents على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.
كم من الوقت يستغرق درس «محاكاة استدعاءات LLM في الاختبارات»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس AI Agents هذا؟
نعم. كل درس في AI Agents يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- لماذا يختلف اختبار الوكلاء؟
- محاكاة استدعاءات LLM في الاختبارات
- اختبار الوكلاء القائم على التأكيدات
- اختبارات التكامل لمسارات الوكلاء