الخطوة 3 في الوكلاء: بناء وكيل بحث

ابنِ وكيلًا يستطيع البحث عن المعلومات في الويب.

ما ستتعلمه

  • استخدام أدوات متعددة داخل وكيل واحد
  • واجهة Wikipedia البرمجية (API)
  • توجيه الأدوات (إسناد الطلب إلى الدالة المناسبة)
  • التعامل مع استدعاءات أدوات متعددة في استجابة واحدة

الخطوة 1: إضافة أداة بحث في Wikipedia

أضف إلى agent.py:

import requests


def search_wikipedia(query: str) -> str:
    """Search Wikipedia and return a summary."""
    try:
        url = "https://en.wikipedia.org/api/rest_v1/page/summary/" + requests.utils.quote(query)
        response = requests.get(url, timeout=10)

        if response.status_code == 200:
            data = response.json()
            return f"Title: {data['title']}\nSummary: {data['extract'][:500]}"
        elif response.status_code == 404:
            return f"No Wikipedia page found for '{query}'"
        else:
            return f"Wikipedia error: {response.status_code}"
    except Exception as e:
        return f"Error searching Wikipedia: {str(e)}"

الخطوة 2: إضافة مخطط الأداة

tools = [
    {
        "type": "function",
        "function": {
            "name": "calculate",
            "description": "Evaluate a mathematical expression",
            "parameters": {
                "type": "object",
                "properties": {
                    "expression": {
                        "type": "string",
                        "description": "Math expression like '2 + 2' or '3 * (4 + 5)'"
                    }
                },
                "required": ["expression"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "search_wikipedia",
            "description": "Search Wikipedia for a topic and get a summary",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "The topic to search for"
                    }
                },
                "required": ["query"]
            }
        }
    }
]

الخطوة 3: تحديث حلقة الوكيل مع توجيه الأدوات

def run_tool(tool_call):
    """Execute the right function based on tool name."""
    args = json.loads(tool_call.function.arguments)

    if tool_call.function.name == "calculate":
        return calculate(args["expression"])
    elif tool_call.function.name == "search_wikipedia":
        return search_wikipedia(args["query"])
    else:
        return f"Unknown tool: {tool_call.function.name}"


def run_agent(user_message: str) -> str:
    messages = [
        {"role": "system", "content": "You are a research assistant with access to a calculator and Wikipedia."},
        {"role": "user", "content": user_message},
    ]

    max_turns = 5  # منع الحلقات اللانهائية

    for _ in range(max_turns):
        response = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=messages,
            tools=tools,
            tool_choice="auto",
        )

        message = response.choices[0].message

        if not message.tool_calls:
            return message.content

        messages.append(message)

        for tool_call in message.tool_calls:
            print(f"  → Calling: {tool_call.function.name}({tool_call.function.arguments})")
            result = run_tool(tool_call)
            print(f"  → Result: {result[:100]}...")
            messages.append({
                "role": "tool",
                "tool_call_id": tool_call.id,
                "content": result,
            })

    return "Agent stopped after maximum turns."

أبرز التغييرات: - توجيه الأدوات — تتولى run_tool() إسناد الطلب إلى الدالة الصحيحة - الحد الأقصى للجولات — يمنع الحلقات اللانهائية إذا استمر الذكاء الاصطناعي في استدعاء الأدوات - طباعة معلومات التصحيح — تُظهر ما يفعله الذكاء الاصطناعي

الخطوة 4: اختبار الأدوات وآلية التوجيه

اختبار أداة Wikipedia

أضف إلى advanced/agentic/tests/test_tools.py:

from agent import search_wikipedia


def test_search_wikipedia_returns_summary():
    result = search_wikipedia("Python (programming language)")
    assert "Python" in result
    assert len(result) > 50


def test_search_wikipedia_handles_not_found():
    result = search_wikipedia("XyzzyNotARealTopic12345")
    assert "No Wikipedia page found" in result

اختبار توجيه الأدوات

أنشئ advanced/agentic/tests/test_agent.py:

import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))

from agent import run_tool


class FakeToolCall:
    def __init__(self, name, args):
        self.function = FakeFunction(name, args)
        self.id = "test_123"


class FakeFunction:
    def __init__(self, name, args):
        self.name = name
        self.arguments = args


def test_run_tool_dispatches_calculate():
    tool = FakeToolCall("calculate", '{"expression": "10 * 5"}')
    result = run_tool(tool)
    assert result == "50"


def test_run_tool_unknown():
    tool = FakeToolCall("nonexistent", "{}")
    result = run_tool(tool)
    assert "Unknown tool" in result

شغّل جميع الاختبارات:

cd aiproject
python -m pytest advanced/agentic/tests/ -v

الخطوة 5: اختبار وكيل البحث

if __name__ == "__main__":
    queries = [
        "What is the capital of France and what is its population?",
        "Search Wikipedia for Python programming language and tell me about it",
        "What is 2 + 2?",
        "Who is Marie Curie and what year was she born?",
    ]

    for query in queries:
        print(f"\n{'='*50}")
        print(f"User: {query}")
        print("-" * 50)
        result = run_agent(query)
        print(f"AI: {result}")

كيف يعمل وكيل البحث

اسأل: «من هي Marie Curie وفي أي عام وُلدت؟»

  1. الذكاء الاصطناعي: «ينبغي أن أبحث في Wikipedia عن Marie Curie»
  2. → يستدعي search_wikipedia("Marie Curie")
  3. → يعيد ملخصًا يتضمن سنة الميلاد
  4. الذكاء الاصطناعي: «وُلدت Marie Curie عام 1867...»

اسأل: «كم يبلغ عدد سكان فرنسا مقسومًا على 1000؟»

  1. الذكاء الاصطناعي: «أولًا، سأبحث عن عدد سكان فرنسا»
  2. → يستدعي search_wikipedia("France") → ويحصل على نحو 68 مليون نسمة
  3. الذكاء الاصطناعي: «الآن سأقسم على 1000»
  4. → يستدعي calculate("68000000 / 1000") → فيُعيد "68000"
  5. الذكاء الاصطناعي: «عدد سكان فرنسا مقسومًا على 1000 هو 68,000»

يربط الوكيل الأدوات بعضها ببعض بشكل طبيعي — وهذا جوهر الذكاء الاصطناعي الوكيلي.