حلول المسار الوكيلي


إجابات أسئلة التحقق من المعرفة

  1. النموذج اللغوي العادي (LLM) يردّ على المستخدم مباشرة. أما النموذج الوكيلي فيستطيع استدعاء أدوات (دوال) للحصول على معلومات إضافية قبل الرد، ما يتيح له إجراء العمليات الحسابية والبحث والوصول إلى قاعدة البيانات وغير ذلك.

  2. tool_choice="auto" يترك للذكاء الاصطناعي أن يقرر بنفسه: هل يستدعي أداة أم يرد مباشرة؟ أما البديل tool_choice="required" فيفرض استدعاء أداة في كل مرة.

  3. يمنع الحلقات اللانهائية حين يستمر الذكاء الاصطناعي في استدعاء الأدوات من دون الوصول إلى إجابة نهائية. فمثلًا، إذا استمرت أداة في إرجاع الأخطاء، فقد يعيد المحاولة إلى ما لا نهاية.

  4. tool_call_id يربط نتيجة استدعاء الأداة بطلب الاستدعاء الأصلي. وتستخدمه OpenAI لمعرفة نتيجة أي استدعاء تنتمي إلى أي طلب عندما تتعدد استدعاءات الأدوات في استجابة واحدة.

  5. سلسلة التفكير (chain-of-thought) تجبر الذكاء الاصطناعي على تفكيك المشكلة إلى خطوات وسيطة، ما يقلل الأخطاء الناتجة عن القفز إلى الاستنتاجات. وهي فعّالة بشكل خاص في الرياضيات والمنطق والمهام التي تحتاج إلى تفكير متعدد الخطوات.


حل التحدي 1

استبدل دالة get_weather الوهمية بواجهة API حقيقية للطقس:

def get_weather(city: str) -> str:
    """Get current weather for a city using wttr.in."""
    try:
        response = requests.get(
            f"https://wttr.in/{city}?format=%C+%t+%w",
            timeout=10,
        )
        if response.status_code == 200:
            return f"Weather in {city}: {response.text}"
        else:
            return f"Weather error: {response.status_code}"
    except Exception as e:
        return f"Error getting weather: {str(e)}"

أو استخدم OpenWeatherMap (يتطلب مفتاح API مجانيًا من https://openweathermap.org/api):

def get_weather_openweather(city: str) -> str:
    """Get current weather using OpenWeatherMap API."""
    api_key = os.getenv("OPENWEATHER_API_KEY", "")
    url = "https://api.openweathermap.org/data/2.5/weather"
    params = {"q": city, "appid": api_key, "units": "metric"}
    try:
        response = requests.get(url, params=params, timeout=10)
        if response.status_code == 200:
            data = response.json()
            temp = data["main"]["temp"]
            desc = data["weather"][0]["description"]
            return f"Weather in {city}: {temp}°C, {desc}"
        else:
            return f"Weather not found for {city}"
    except Exception as e:
        return f"Error: {str(e)}"

حل التحدي 2

import sqlite3


def query_database(sql: str) -> str:
    """Execute a SELECT query on the chat database."""
    sql_upper = sql.strip().upper()
    if not sql_upper.startswith("SELECT"):
        return "Error: Only SELECT queries are allowed."

    try:
        db_path = os.path.join(
            os.path.dirname(__file__),
            "../backend/instance/chat.db",
        )
        conn = sqlite3.connect(db_path)
        cursor = conn.cursor()
        cursor.execute(sql)
        rows = cursor.fetchall()
        columns = [description[0] for description in cursor.description]
        conn.close()

        if not rows:
            return "No results found."

        result = " | ".join(columns) + "\n"
        result += "-" * len(result) + "\n"
        for row in rows:
            result += " | ".join(str(col) for col in row) + "\n"
        return result.strip()
    except Exception as e:
        return f"Database error: {str(e)}"

أضف مخطط الأداة:

{
    "type": "function",
    "function": {
        "name": "query_database",
        "description": "Execute a SELECT query on the chat database to retrieve data",
        "parameters": {
            "type": "object",
            "properties": {
                "sql": {
                    "type": "string",
                    "description": "A SQL SELECT query",
                }
            },
            "required": ["sql"],
        },
    },
}

جرّب: اسأل «كم عدد الرسائل في قاعدة البيانات؟» → يولّد الذكاء الاصطناعي استعلام SELECT COUNT(*) FROM message ويعيد العدد.


حل التحدي 3

import json

MEMORY_FILE = "agent_memory.json"


def load_memory():
    try:
        with open(MEMORY_FILE, "r") as f:
            return json.load(f)
    except (FileNotFoundError, json.JSONDecodeError):
        return {}


def save_memory(memory):
    with open(MEMORY_FILE, "w") as f:
        json.dump(memory, f, indent=2)


def remember(key: str, value: str) -> str:
    """Store a fact in memory."""
    memory = load_memory()
    memory[key.lower()] = value
    save_memory(memory)
    return f"Remembered: {key} = {value}"


def recall(key: str) -> str:
    """Retrieve a fact from memory."""
    memory = load_memory()
    value = memory.get(key.lower())
    if value:
        return f"{key}: {value}"
    return f"No memory found for '{key}'"


def forget(key: str) -> str:
    """Remove a fact from memory."""
    memory = load_memory()
    if key.lower() in memory:
        del memory[key.lower()]
        save_memory(memory)
        return f"Forgot: {key}"
    return f"No memory found for '{key}'"


def list_memories() -> str:
    """List all stored facts."""
    memory = load_memory()
    if not memory:
        return "No memories stored."
    return "\n".join(f"{k}: {v}" for k, v in memory.items())

أضف مخططات الأدوات لكل دالة، ثم أضفها إلى موزّع run_tool. جرّب:

User: "Remember my favorite color is blue"
User: "What is my favorite color?"
User: "Forget my favorite color"

مشروع مفتوح: مساعد بحث مخصص

def save_report(filename: str, content: str) -> str:
    """Save content to a markdown file."""
    try:
        with open(filename, "w") as f:
            f.write(content)
        return f"Report saved to {filename}"
    except Exception as e:
        return f"Error saving report: {str(e)}"


def research_topic(topic: str) -> str:
    """Full research pipeline."""
    sections = [
        ("Introduction", f"What is {topic}?"),
        ("Key Concepts", f"Key concepts in {topic}"),
        ("History", f"History of {topic}"),
        ("Applications", f"Applications of {topic}"),
    ]

    report = f"# Research Report: {topic}\n\n"

    for section_title, search_query in sections:
        print(f"  Researching: {section_title}...")
        summary = search_wikipedia(search_query)
        report += f"## {section_title}\n\n{summary}\n\n---\n\n"

    report += "\n*Report generated by AI Research Agent*\n"

    filename = f"{topic.lower().replace(' ', '-')}-report.md"
    save_report(filename, report)
    return f"Report written to {filename}"

أضف الأداة ومخططها. ثم في الوضع التفاعلي:

User: "Research renewable energy"