الدرس 14 من 22

أنماط نماذج اللغة المحلية المتقدمة

استدعاء الوظائف محلياً

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

استدعاء الوظائف (استخدام الأدوات) يسمح لنماذج اللغة الكبيرة بالتفاعل مع الأنظمة الخارجية. لننفذ هذا النمط مع النماذج المحلية.

كيف يعمل استدعاء الوظائف المحلي

┌─────────────────────────────────────────────────────────────────┐
│                  تدفق استدعاء الوظائف المحلي                     │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. استعلام المستخدم ──► LLM يحلل ويقرر استدعاء وظيفة          │
│                                                                 │
│  2. مخرجات LLM ──► JSON باسم الوظيفة والوسيطات                  │
│                                                                 │
│  3. كودك ──► يحلل JSON، ينفذ الوظيفة                           │
│                                                                 │
│  4. النتيجة ──► تُغذى للـ LLM للرد النهائي                      │
│                                                                 │
│  ملاحظة: النماذج المحلية تخرج نص. أنت تحلله كاستدعاءات وظائف   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

التنفيذ الأساسي

import ollama
import json
from typing import Callable

# حدد الوظائف المتاحة
def get_weather(city: str) -> str:
    """احصل على الطقس لمدينة (تنفيذ وهمي)."""
    weather_data = {
        "paris": "Sunny, 22°C",
        "london": "Cloudy, 15°C",
        "tokyo": "Rainy, 18°C"
    }
    return weather_data.get(city.lower(), f"Weather data not available for {city}")

def calculate(expression: str) -> str:
    """قيّم تعبير رياضي بأمان."""
    try:
        # اسمح فقط بعمليات رياضية آمنة
        allowed = set("0123456789+-*/().  ")
        if all(c in allowed for c in expression):
            result = eval(expression)
            return str(result)
        return "Invalid expression"
    except Exception as e:
        return f"Error: {e}"

# سجل الوظائف
FUNCTIONS = {
    "get_weather": get_weather,
    "calculate": calculate
}

# طلب النظام لاستدعاء الوظائف
SYSTEM_PROMPT = """You are a helpful assistant with access to these functions:

1. get_weather(city: str) - Get current weather for a city
2. calculate(expression: str) - Calculate a math expression

When you need to use a function, respond ONLY with JSON in this format:
{"function": "function_name", "arguments": {"arg_name": "value"}}

If you don't need a function, respond normally.
"""

def process_with_functions(user_query: str) -> str:
    """عالج استعلام مع دعم استدعاء الوظائف."""
    # أول استدعاء LLM - قرر إذا الوظيفة مطلوبة
    response = ollama.chat(
        model="llama3.2",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": user_query}
        ]
    )

    content = response["message"]["content"].strip()

    # حاول التحليل كاستدعاء وظيفة
    try:
        if content.startswith("{"):
            call = json.loads(content)
            if "function" in call:
                func_name = call["function"]
                args = call.get("arguments", {})

                if func_name in FUNCTIONS:
                    # نفذ الوظيفة
                    result = FUNCTIONS[func_name](**args)

                    # ثاني استدعاء LLM - ولّد الرد النهائي
                    response = ollama.chat(
                        model="llama3.2",
                        messages=[
                            {"role": "system", "content": SYSTEM_PROMPT},
                            {"role": "user", "content": user_query},
                            {"role": "assistant", "content": content},
                            {"role": "user", "content": f"Function result: {result}"}
                        ]
                    )
                    return response["message"]["content"]
    except json.JSONDecodeError:
        pass

    return content

# اختبر
print(process_with_functions("What's the weather in Paris?"))
print(process_with_functions("Calculate 15 * 7 + 23"))
print(process_with_functions("Hello, how are you?"))

محلل وظائف قوي

import ollama
import json
import re

def extract_function_call(text: str) -> dict | None:
    """استخرج استدعاء الوظيفة من مخرجات LLM، مع معالجة تنسيقات متنوعة."""
    # جرب التحليل المباشر لـ JSON
    try:
        # جد كائن JSON في النص
        json_match = re.search(r'\{[^{}]*\}', text)
        if json_match:
            return json.loads(json_match.group())
    except json.JSONDecodeError:
        pass

    # جرب تحليل النص المنظم
    patterns = [
        r'function:\s*(\w+)\s*arguments?:\s*(.+)',
        r'call\s+(\w+)\s+with\s+(.+)',
    ]

    for pattern in patterns:
        match = re.search(pattern, text, re.IGNORECASE)
        if match:
            return {
                "function": match.group(1),
                "arguments": {"input": match.group(2).strip()}
            }

    return None

تكامل أدوات LangChain

from langchain_ollama import ChatOllama
from langchain_core.tools import tool
from langchain_core.messages import HumanMessage, ToolMessage

@tool
def search_database(query: str) -> str:
    """ابحث في قاعدة البيانات الداخلية عن معلومات."""
    # بحث وهمي في قاعدة البيانات
    data = {
        "revenue": "Q4 2024 revenue was $1.2M",
        "employees": "Current employee count is 45",
        "products": "We offer 3 main products"
    }
    for key, value in data.items():
        if key in query.lower():
            return value
    return "No matching data found"

@tool
def send_email(to: str, subject: str, body: str) -> str:
    """أرسل بريد إلكتروني للمستلم المحدد."""
    # إرسال بريد وهمي
    return f"Email sent to {to} with subject: {subject}"

# أنشئ LLM مع أدوات
llm = ChatOllama(model="llama3.2")

# اربط الأدوات (للنماذج التي تدعم استدعاء الأدوات الأصلي)
llm_with_tools = llm.bind_tools([search_database, send_email])

# للنماذج بدون استدعاء أدوات أصلي، استخدم نهج قائم على الطلب
tools_description = """
Available tools:
1. search_database(query: str) - Search internal database
2. send_email(to: str, subject: str, body: str) - Send email

Respond with JSON: {"tool": "name", "args": {...}} when using a tool.
"""

def agent_step(user_input: str):
    """خطوة وكيل واحدة مع استخدام الأداة."""
    response = llm.invoke(
        f"{tools_description}\n\nUser: {user_input}"
    )
    return response.content

وكيل أدوات متعدد الأدوار

import ollama
import json

class LocalToolAgent:
    """وكيل يمكنه استخدام الأدوات عبر أدوار متعددة."""

    def __init__(self, model: str = "llama3.2"):
        self.model = model
        self.tools = {}
        self.conversation = []

    def register_tool(self, name: str, func: callable, description: str):
        """سجل أداة للوكيل ليستخدمها."""
        self.tools[name] = {"function": func, "description": description}

    def _get_tools_prompt(self) -> str:
        """ولّد وصف الأدوات للطلب."""
        lines = ["Available tools:"]
        for name, info in self.tools.items():
            lines.append(f"- {name}: {info['description']}")
        lines.append("")
        lines.append('To use a tool, respond with: {"tool": "name", "args": {...}}')
        lines.append("After using a tool, you'll see the result and can respond to the user.")
        return "\n".join(lines)

    def run(self, user_input: str) -> str:
        """عالج مدخلات المستخدم، مع استخدام الأدوات المحتمل."""
        self.conversation.append({"role": "user", "content": user_input})

        # ابنِ الرسائل
        messages = [
            {"role": "system", "content": self._get_tools_prompt()}
        ] + self.conversation

        response = ollama.chat(model=self.model, messages=messages)
        content = response["message"]["content"]

        # تحقق من استدعاء الأداة
        tool_call = self._parse_tool_call(content)
        if tool_call:
            # نفذ الأداة
            tool_name = tool_call["tool"]
            args = tool_call.get("args", {})

            if tool_name in self.tools:
                result = self.tools[tool_name]["function"](**args)

                # أضف للمحادثة
                self.conversation.append({"role": "assistant", "content": content})
                self.conversation.append({
                    "role": "user",
                    "content": f"Tool result for {tool_name}: {result}"
                })

                # احصل على الرد النهائي
                final_response = ollama.chat(
                    model=self.model,
                    messages=[
                        {"role": "system", "content": self._get_tools_prompt()}
                    ] + self.conversation
                )
                final_content = final_response["message"]["content"]
                self.conversation.append({"role": "assistant", "content": final_content})
                return final_content

        self.conversation.append({"role": "assistant", "content": content})
        return content

    def _parse_tool_call(self, text: str) -> dict | None:
        """حلل استدعاء الأداة من الرد."""
        try:
            match = re.search(r'\{[^{}]*"tool"[^{}]*\}', text)
            if match:
                return json.loads(match.group())
        except:
            pass
        return None

# الاستخدام
agent = LocalToolAgent()

agent.register_tool(
    "get_time",
    lambda: __import__("datetime").datetime.now().strftime("%H:%M"),
    "Get the current time"
)

agent.register_tool(
    "search",
    lambda query: f"Search results for '{query}': [Result 1, Result 2]",
    "Search for information"
)

print(agent.run("What time is it?"))
print(agent.run("Search for Python tutorials"))

أفضل الممارسات

الممارسة لماذا
أوصاف أدوات واضحة تساعد LLM على فهم متى تستخدم كل أداة
التحقق من الوسيطات مخرجات LLM يمكن أن تكون مشوهة
معالجة الأخطاء برشاقة الأدوات يمكن أن تفشل
تحديد عدد الأدوات كثرة الأدوات تربك النماذج الأصغر
استخدم تنسيق JSON أكثر تنسيق قابل للتحليل لاستدعاءات الوظائف

استدعاء الوظائف يوسع نماذج اللغة المحلية إلى ما وراء توليد النص. بعد ذلك، سنستكشف سير عمل النماذج المتعددة. :::

اختبار

الوحدة 4: أنماط نماذج اللغة المحلية المتقدمة

خذ الاختبار
نشرة أسبوعية مجانية

ابقَ على مسار النيرد

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

بدون إزعاج. إلغاء الاشتراك في أي وقت.