أنماط نماذج اللغة المحلية المتقدمة
استدعاء الوظائف محلياً
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 | أكثر تنسيق قابل للتحليل لاستدعاءات الوظائف |
استدعاء الوظائف يوسع نماذج اللغة المحلية إلى ما وراء توليد النص. بعد ذلك، سنستكشف سير عمل النماذج المتعددة. :::