الدرس 19 من 20

بناء وكيل بحث

الاختبار والتحقق

3 دقيقة للقراءة

اختبار وكلاء الذكاء الاصطناعي يختلف عن البرمجيات التقليدية—نحتاج للتعامل مع عدم الحتمية وتقييم الجودة، ليس فقط الصحة.

هيكل الاختبار

# tests/test_agent.py
import pytest
from unittest.mock import Mock, patch
from agent import ResearchAgent
from config import Config

class TestResearchAgent:
    @pytest.fixture
    def agent(self):
        config = Config()
        config.MAX_ITERATIONS = 3  # تحديد للاختبارات
        return ResearchAgent(config)

    @pytest.fixture
    def mock_search_results(self):
        return {
            "success": True,
            "results": [
                {
                    "title": "مقالة اختبار",
                    "url": "https://example.com/test",
                    "snippet": "هذا محتوى اختبار عن وكلاء الذكاء الاصطناعي."
                }
            ]
        }

اختبارات الوحدة

اختبر المكونات الفردية:

# tests/test_tools.py
from tools.search import WebSearchTool

class TestWebSearchTool:
    def test_search_returns_results(self):
        tool = WebSearchTool()
        result = tool.run("Python programming")

        assert result["success"] == True
        assert len(result["results"]) > 0
        assert "title" in result["results"][0]

    def test_search_handles_errors(self):
        tool = WebSearchTool()
        # اختبار مع استعلام إشكالي
        result = tool.run("")

        assert "success" in result
        # يجب ألا يرفع استثناء

# tests/test_memory.py
from memory.store import ResearchMemory

class TestResearchMemory:
    def test_add_and_retrieve_finding(self):
        memory = ResearchMemory()

        memory.add_finding(
            query="AI agents",
            content="الوكلاء هي أنظمة مستقلة",
            url="https://example.com",
            title="عن الوكلاء"
        )

        assert len(memory.findings) == 1
        assert memory.has_searched("AI agents")
        assert not memory.has_searched("موضوع غير معروف")

    def test_get_sources_deduplicates(self):
        memory = ResearchMemory()

        # إضافة نفس المصدر مرتين
        for _ in range(2):
            memory.add_finding(
                query="test",
                content="محتوى",
                url="https://same-url.com",
                title="نفس العنوان"
            )

        sources = memory.get_sources()
        assert len(sources) == 1  # إزالة التكرارات

اختبارات التكامل

اختبر تدفق الوكيل الكامل:

# tests/test_integration.py
import pytest
from agent import ResearchAgent
from config import Config

class TestAgentIntegration:
    @pytest.mark.integration
    def test_full_research_flow(self):
        """اختبار البحث الكامل على موضوع معروف"""
        agent = ResearchAgent(Config())

        report = agent.research("What is machine learning?")

        # التحقق من هيكل التقرير
        assert len(report) > 100
        assert "machine learning" in report.lower()

    @pytest.mark.integration
    def test_handles_unknown_topic(self):
        """يجب أن ينتج الوكيل مخرجات للمواضيع الغامضة"""
        agent = ResearchAgent(Config())

        report = agent.research("xyznonexistenttopic123")

        # يجب ألا يتعطل، يجب أن يشير لنتائج محدودة
        assert report is not None

التحقق من المخرجات

# utils/validators.py
from pydantic import BaseModel, validator
from typing import List, Optional
import re

class ResearchReport(BaseModel):
    content: str
    sources: List[str]

    @validator('content')
    def content_not_empty(cls, v):
        if len(v.strip()) < 50:
            raise ValueError('التقرير قصير جداً')
        return v

    @validator('content')
    def no_hallucinated_urls(cls, v):
        # التحقق من أنماط URL المشبوهة
        urls = re.findall(r'https?://[^\s]+', v)
        for url in urls:
            if 'example.com' in url and 'real' not in url:
                raise ValueError(f'URL مهلوس محتمل: {url}')
        return v

def validate_report(report: str, sources: List[dict]) -> dict:
    """التحقق من تقرير مولد"""
    issues = []

    # التحقق من الحد الأدنى للطول
    if len(report) < 100:
        issues.append("التقرير قصير جداً")

    # التحقق من الاستشهادات
    citation_pattern = r'\[\d+\]'
    citations = re.findall(citation_pattern, report)
    if not citations:
        issues.append("لم يتم العثور على استشهادات")

    # التحقق من تطابق أرقام الاستشهادات مع المصادر
    cited_numbers = set(int(c[1:-1]) for c in citations)
    available_numbers = set(s['id'] for s in sources)
    invalid_citations = cited_numbers - available_numbers
    if invalid_citations:
        issues.append(f"أرقام استشهاد غير صالحة: {invalid_citations}")

    return {
        "valid": len(issues) == 0,
        "issues": issues
    }

تقييم الجودة

# tests/test_quality.py
from langchain_openai import ChatOpenAI

def evaluate_report_quality(report: str, topic: str) -> dict:
    """استخدام LLM لتقييم جودة التقرير"""
    llm = ChatOpenAI(model="gpt-4o")

    eval_prompt = f"""
    قيّم تقرير البحث هذا عن "{topic}".

    التقرير:
    {report}

    قيّم كل معيار من 1-5:
    1. الصلة: هل يتناول الموضوع؟
    2. الدقة: هل الحقائق صحيحة (حسب معرفتك)؟
    3. الشمولية: هل الجوانب الرئيسية مغطاة؟
    4. الوضوح: هل هو منظم ومقروء؟
    5. المصادر: هل الادعاءات موثقة؟

    أرجع JSON: {{"relevance": X, "accuracy": X, "completeness": X, "clarity": X, "sources": X, "overall": X, "feedback": "..."}}
    """

    response = llm.invoke([{"role": "user", "content": eval_prompt}])
    return parse_json(response.content)

class TestReportQuality:
    @pytest.mark.quality
    def test_report_meets_quality_threshold(self):
        agent = ResearchAgent(Config())
        report = agent.research("Benefits of renewable energy")

        scores = evaluate_report_quality(report, "renewable energy")

        assert scores["overall"] >= 3.5
        assert scores["relevance"] >= 4

تشغيل الاختبارات

# تشغيل جميع الاختبارات
pytest tests/

# تشغيل اختبارات الوحدة فقط
pytest tests/ -m "not integration and not quality"

# تشغيل مع التغطية
pytest tests/ --cov=. --cov-report=html

# تشغيل اختبارات تقييم الجودة
pytest tests/ -m quality -v

التالي: تعلم كيفية توسيع ونشر وكيل البحث الخاص بك. :::

اختبار

الوحدة 5: بناء وكيل بحث

خذ الاختبار