مقدمة: تحدي اختبار الذكاء الاصطناعي
بناء وكلاء أذكياء باستخدام نماذج اللغة الكبيرة (LLMs) أمر مثير، لكنه يقدم تحديات كبيرة في هندسة البرمجيات. على عكس الكود الحتمي التقليدي، تعتمد وكلاء LLM على واجهات برمجة التطبيقات الخارجية، والمخرجات العشوائية، وإدارة الحالة المعقدة. هذا يجعل الاختبار صعباً. كيف تتحقق من المنطق عندما يكون "العقل" لتطبيقك هو استدعاء واجهة برمجة تطبيقات غير حتمي؟
تتمثل الحل في أنماط تصميم البرمجيات الصارمة، وتحديداً حقن التبعيات (DI). يتفوق PydanticAI، وهو إطار عمل حديث بلغة بايثون لبناء تطبيقات LLM، في هذا المجال من خلال الاستفادة من تلميحات الأنواع ونماذج pydantic لإدارة التبعيات بشكل نظيف. من خلال عزل عميل LLM عن منطق أعمالك، يمكنك كتابة اختبارات وحدة سريعة وموثوقة لا تكلفك أموالاً على شكل رموز API ولا تعاني من مشاكل الشبكة غير المستقرة.
لماذا يهم حقن التبعيات للوكلاء
في سير عمل وكيل نموذجي، قد يكون لديك وكيل يبحث في الويب، ثم يعالج النتائج، ثم يلخصها. إذا كان أداة البحث في الويب مبرمجة بشكل ثابت داخل الوكيل، فلا يمكنك اختبار منطق التلخيص دون الوصول فعلياً إلى محرك بحث.
يتيح لك حقن التبعيات استبدال هذه التبعيات. في الإنتاج، تقوم بحقن `WebSearchTool` حقيقي. في الاختبارات، تقوم بحقن `MockWebSearchTool` يعيد بيانات محددة مسبقاً. يضمن هذا النمط أن تركز اختبارات الوحدة بشكل صارم على منطق وكيلك، وليس على موثوقية الخدمات الخارجية.
إعداد وكيل قابل للاختبار
أولاً، دعنا نحدد وكلاً بسيطاً يستخدم تبعية. سنستخدم نظام PydanticAI لإدارة تبعيات الأدوات.
from pydantic_ai import Agent
from pydantic_ai.models import Model
from pydantic_ai.toolsets import Toolset
from pydantic import BaseModel
class Fact(BaseModel):
fact: str
source: str
# Define a custom Toolset to manage dependencies
class FactToolset(Toolset):
model: Model
facts: list[Fact]
def __init__(self, model: Model, facts: list[Fact]):
self.model = model
self.facts = facts
@property
def get_facts(self):
"""Return a list of known facts."""
return self.facts
# Define the Agent
agent = Agent[FactToolset](
model='openai:gpt-4o',
system_prompt='You are a fact-checker. Use the provided facts to answer questions.',
)
async def main():
# In production, you would inject real facts
toolset = FactToolset(model=agent.model, facts=[Fact(fact="Water is wet", source="Physics")])
try:
result = await agent.run('Is water wet?', toolset=toolset)
print(result.output)
finally:
await toolset.aclose()
اختبار الوحدة باستخدام المصغرات (Mocks)
الآن، يمكننا كتابة اختبار وحدة. المفتاح هو تصغير `Model` نفسه حتى لا نقوم بإجراء استدعاءات API فعلية. يوفر PydanticAI `MockModel` لهذا الغرض.
import pytest
from pydantic_ai import Agent
from pydantic_ai.models import MockModel
from pydantic_ai.toolsets import Toolset
from pydantic import BaseModel
from pydantic_ai.messages import ModelResponse, TextPart, ToolCallPart
class Fact(BaseModel):
fact: str
source: str
class FactToolset(Toolset):
def __init__(self, facts: list[Fact]):
self.facts = facts
def get_facts(self):
return self.facts
# Create the agent with a placeholder model. The real model will be injected later.
agent = Agent[FactToolset](
model='mock',
system_prompt='You are a fact-checker.'
)
@pytest.mark.anyio
async def test_agent_facts():
# 1. Define the expected response from the LLM
# The LLM should call the 'get_facts' tool
mock_response = ModelResponse(
parts=[
ToolCallPart(tool_name='get_facts', args={}),
TextPart(content='Based on the facts, water is wet.')
]
)
# 2. Create a MockModel that returns our predefined response
mock_model = MockModel(messages=[mock_response])
# 3. Create the toolset with test data
test_facts = [Fact(fact="Water is wet", source="Test Source")]
toolset = FactToolset(facts=test_facts)
# 4. Run the agent with the mock model and toolset
# Note: We inject the mock model into the agent context
async with agent.run_with_tools('Is water wet?', toolset=toolset, model=mock_model) as result:
assert result.output == 'Based on the facts, water is wet.'
أفضل الممارسات لاختبارات متينة
1.
عزل الحالة: تأكد من أن كل اختبار ينشئ نسخة جديدة من مجموعة الأدوات. تجنب مشاركة الحالة بين الاختبارات لمنع التلوث.
2.
التحقق من الأدوات: في اختباراتك، تحقق من أن الأدوات الصحيحة تم استدعاؤها. يمكنك فحص `result.all_messages` للتأكد من وجود كائنات `ToolCallPart` بأسماء محددة.
3.
استخدام المخرجات المهيكلة: يدعم PydanticAI المخرجات المهيكلة (نماذج pydantic). اختبر أن استجابة LLM تلتزم بمخططك. هذا أمر حاسم لمعالجة البيانات اللاحقة.
خاتمة
تنفيذ وكلاء LLM يتطلب تحولاً في التفكير من "البرمجة النصية" إلى "الهندسة". من خلال الاستفادة من قدرات حقن التبعيات في PydanticAI، يمكنك بناء وكلاء ليسوا وظيفيين فحسب، بل قابلين للاختبار والصيانة أيضاً.
يسمح لك الجمع بين `MockModel` لاستجابات LLM و`Toolsets` المخصصة لتبعيات البيانات بفصل منطقك عن الطبيعة غير الحتمية للذكاء الاصطناعي. ابدأ بعزل أدواتك، وصغّر نماذجك، وستبني أساساً لتطبيقات ذكاء اصطناعي موثوقة يمكن توسيع نطاقها بثقة.