الكتابات/tutorial/2026/05
Tutorial26 مايو 2026·26 دقيقة

smolagents: بناء وكلاء ذكاء اصطناعي بنهج الكود في بايثون مع Hugging Face

دليل عملي لإطار smolagents من Hugging Face، الإطار الأصغر والأخف لبناء الوكلاء الذكية. تعرّف على سبب تفوّق وكلاء الكود على استدعاءات JSON، وابنِ مساعد بحث في بايثون، وأضف أدوات مخصصة، ونسّق أنظمة متعددة الوكلاء، وعزل التنفيذ بواسطة E2B.

مقدمة

معظم أطر الوكلاء الذكية تستخدم الوصفة نفسها: النموذج يولّد كائن JSON يصف الأداة التي يجب استدعاؤها، ثم يقوم المحرك بتحليله وتنفيذ الأداة وإعادة النتيجة في حلقة مغلقة. النهج يعمل، لكن كل خطوة تدفع ضريبة — JSON مطوّل، وتركيب الأدوات معقّد، وتسلسل ثلاث عمليات يتطلب ثلاث جولات كاملة.

smolagents، أصدرته Hugging Face في 2025 واستقرّ خلال 2026، يراهن على نهج مختلف: بدلًا من توليد JSON، يكتب الوكيل كودًا في بايثون ويُنفّذه مباشرة. عملية توليد واحدة قد تستدعي ثلاث أدوات، وتدور على قائمة، وتُجري عمليات حسابية، وتُخزّن متغيرات وسيطة — كل ذلك في خطوة واحدة. أظهرت أبحاث Hugging Face وDeepMind أن وكلاء الكود يحققون الدقة نفسها بعدد خطوات أقل بنسبة 30 بالمائة.

المكتبة نفسها صغيرة بشكل لافت — أقل من 1000 سطر من الكود الأساسي — وتدعم أي نموذج يتحدث بروتوكولات OpenAI أو Anthropic أو Hugging Face Inference أو LiteLLM. في هذا الدرس ستبني وكيل بحث جاهزًا للإنتاج يجلب البيانات من الويب، ويلخّص الأوراق العلمية، ويُنسّق مع وكيل فرعي — كل ذلك ببايثون نقيّ.

المتطلبات المسبقة

قبل البدء، تأكد من توفّر:

  • بايثون 3.10 أو أحدث
  • حساب Hugging Face ورمز وصول (الباقة المجانية كافية)
  • مفتاح OpenAI أو Anthropic (اختياري، للمقارنة)
  • إلمام بـ pip والبيئات الافتراضية
  • فهم أساسي لمفاهيم نماذج اللغة الكبيرة (الرموز، النصوص التوجيهية، استدعاء الأدوات)
  • نحو 30 دقيقة من التركيز

ما ستبنيه

وكيل بحث متعدد الخطوات يقوم بـ:

  • استقبال سؤال بحثي بلغة طبيعية
  • البحث على الويب باستخدام DuckDuckGo
  • جلب صفحات الويب وتحويلها إلى نص نظيف
  • تلخيص النتائج بمنطق التفكير المتسلسل
  • تفويض المهام الحسابية إلى وكيل فرعي متخصص
  • تشغيل الكود غير الموثوق داخل صندوق رمل E2B لضمان الأمان

في النهاية ستملك هيكل وكيل قابل لإعادة الاستخدام يمكن نشره خلف نقطة نهاية FastAPI.

الخطوة 1: تثبيت smolagents

أنشئ مشروعًا جديدًا وثبّت المكتبة مع التكاملات المطلوبة:

mkdir smol-research && cd smol-research
python -m venv .venv
source .venv/bin/activate
pip install "smolagents[toolkit,litellm,e2b]>=1.10" \
  "duckduckgo-search" "markdownify" "requests"

الإضافات بين الأقواس تجلب:

  • toolkit — مجموعة الأدوات الرسمية (بحث الويب، جالب الصفحات، آلة حاسبة)
  • litellm — محوّل لـ OpenAI وAnthropic وGroq وOllama وأي مزوّد متوافق مع LiteLLM
  • e2b — صناديق رمل بعيدة لتنفيذ الكود بأمان

صدِّر الرموز:

export HF_TOKEN="hf_xxx"
export OPENAI_API_KEY="sk-..."
export E2B_API_KEY="e2b_..."   # اختياري، لخطوة الصندوق فقط

الخطوة 2: بناء أول CodeAgent

أنشئ ملف agent.py. أصغر وكيل مفيد يتكون من ثلاثة أسطر إضافة إلى نموذج:

from smolagents import CodeAgent, InferenceClientModel, DuckDuckGoSearchTool
 
model = InferenceClientModel(model_id="meta-llama/Llama-3.3-70B-Instruct")
 
agent = CodeAgent(
    tools=[DuckDuckGoSearchTool()],
    model=model,
    max_steps=6,
)
 
result = agent.run("ما هي الورقة العلمية الأكثر استشهادًا في الذكاء الاصطناعي عام 2025؟")
print(result)

شغّله:

python agent.py

سترى الوكيل يطبع منطقه والكود الذي ولّده في كل خطوة. تبدو الخطوة الأولى عادةً هكذا:

# الخطوة 1 — كود ولّده الوكيل
results = duckduckgo_search(query="most cited AI paper 2025")
print(results[:3])

لاحظ أن الوكيل لم يولّد JSON — بل كتب بايثون حقيقيًا يستدعي duckduckgo_search كدالة. المحرك يُنفّذ هذا الكود داخل مفسّر مقيّد، ويلتقط مخرجات print، ثم يُعيدها إلى النموذج كمشاهدة.

تبديل النماذج

InferenceClientModel يستخدم Hugging Face Inference API. للتبديل إلى OpenAI أو Anthropic، استبدل صنف النموذج:

from smolagents import LiteLLMModel
 
# OpenAI
model = LiteLLMModel(model_id="gpt-4o-mini", api_key=os.environ["OPENAI_API_KEY"])
 
# Anthropic
model = LiteLLMModel(
    model_id="anthropic/claude-haiku-4-5",
    api_key=os.environ["ANTHROPIC_API_KEY"],
)
 
# Ollama يعمل محليًا
model = LiteLLMModel(model_id="ollama/llama3.1:8b", api_base="http://localhost:11434")

كل شيء آخر يبقى كما هو. هذا هو السبب الرئيسي لانتشار smolagents — مستقل عن المزوّد بحكم التصميم، لا حاجة لمخطط استدعاءات خاص بكل واجهة برمجية.

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

تغطي مجموعة الأدوات الرسمية الأساسيات، لكن الوكلاء الحقيقيون يحتاجون أدوات خاصة بمجالهم. الأداة في smolagents مجرد دالة بايثون مع docstring وtype hints — الإطار يولّد المخطط تلقائيًا.

أضف أداة تجلب صفحة ويب وتحوّلها إلى Markdown نظيف:

from smolagents import tool
import requests
from markdownify import markdownify
import re
 
@tool
def fetch_page(url: str) -> str:
    """يجلب صفحة ويب ويعيد محتواها كنص Markdown نظيف.
 
    Args:
        url: العنوان الكامل للصفحة المراد جلبها.
    """
    response = requests.get(url, timeout=10, headers={"User-Agent": "Mozilla/5.0"})
    response.raise_for_status()
    markdown = markdownify(response.text, heading_style="ATX")
    markdown = re.sub(r"\n{3,}", "\n\n", markdown)
    return markdown[:8000]

المُزخرف @tool يقوم بثلاثة أمور:

  1. يُحلّل توقيع الدالة إلى وصف معادل لـ JSON Schema
  2. يستخرج docstring كوصف للأداة
  3. يسجّل عمليات الاستيراد الآمنة حتى يتمكّن الوكيل من استدعائها

سجّل الأداة الجديدة عند بناء الوكيل:

agent = CodeAgent(
    tools=[DuckDuckGoSearchTool(), fetch_page],
    model=model,
    max_steps=8,
    additional_authorized_imports=["re", "json"],
)

المعامل additional_authorized_imports بالغ الأهمية. افتراضيًا يمنع المفسّر كل عمليات الاستيراد باستثناء قائمة بيضاء صغيرة (math, statistics, datetime). أي مكتبة تعتمد عليها أدواتك يجب التصريح بها صراحةً — هذا ما يبقي الكود المولَّد آمنًا.

الخطوة 4: التفكير والتخطيط والذاكرة

للأسئلة المعقدة، جولة بحث واحدة لا تكفي. يحوي smolagents خطوة تخطيط مدمجة يمكن تفعيلها:

agent = CodeAgent(
    tools=[DuckDuckGoSearchTool(), fetch_page],
    model=model,
    max_steps=10,
    planning_interval=3,
    additional_authorized_imports=["re", "json"],
)

مع planning_interval=3، يتوقف الوكيل كل ثلاث خطوات ليكتب خطة باللغة الطبيعية تلخّص ما تعلّمه وما يحتاج إليه. في اختباراتنا، هذا يقلّل التشتّت في الأسئلة متعددة القفزات بنحو 40 بالمائة.

يمكنك أيضًا فحص ذاكرة الوكيل أو حفظها:

result = agent.run("قارن البصمة الكربونية لاستدلال GPT-4o مع Llama 3.1.")
 
for step in agent.memory.steps:
    print(step.step_number, step.tool_calls or step.code_action)

agent.memory قائمة منظمة من كائنات ActionStep وPlanningStep وFinalAnswerStep — مثالية لتسجيلها في Langfuse أو OpenTelemetry أو أي نظام مراقبة خاص بك.

الخطوة 5: تنسيق وكلاء متعددين

أحمال العمل الحقيقية تنقسم بشكل طبيعي بين متخصصين. يدعم smolagents تعشيش الوكلاء كأدوات عبر مغلّف ManagedAgent.

أنشئ وكيلًا فرعيًا متخصصًا في الحساب:

from smolagents import ManagedAgent, ToolCallingAgent
 
math_agent = ToolCallingAgent(
    tools=[],
    model=model,
    name="math_solver",
    description=(
        "ينفّذ منطقًا عدديًا دقيقًا. أرسل له سؤالًا حسابيًا مكتفيًا بذاته "
        "ويعيد لك الإجابة."
    ),
    max_steps=4,
)
 
managed_math = ManagedAgent(
    agent=math_agent,
    name="math_solver",
    description="استخدمه لأي عملية حسابية أو مقارنة عددية أثقل من الجمع البسيط.",
)

ToolCallingAgent يستخدم استدعاءات JSON الكلاسيكية — مفيد عندما يكون النموذج صغيرًا وتوليد الكود غير موثوق. الوكيل الخارجي CodeAgent سيظل يولّد بايثون، لكنه يستطيع الآن استدعاء الوكيل الداخلي كدالة:

research_agent = CodeAgent(
    tools=[DuckDuckGoSearchTool(), fetch_page],
    managed_agents=[managed_math],
    model=model,
    max_steps=12,
    planning_interval=4,
)
 
answer = research_agent.run(
    "ابحث عن البصمة الكربونية لكل 1000 رمز في GPT-4o وLlama 3.1 70B، "
    "ثم احسب النسبة."
)

في تنفيذ نموذجي، يبحث الوكيل الخارجي عن الرقمين، ثم يكتب بايثون مثل:

ratio = math_solver(task=f"اقسم {gpt_co2} على {llama_co2} وقرّب إلى منزلتين عشريتين")
final_answer(f"يُصدر GPT-4o {ratio} أضعاف الكربون لكل 1000 رمز.")

الفائدة مزدوجة: وكيل الحساب أرخص لأنه يستخدم نموذجًا أصغر، والمنسّق يبقى مركّزًا على الاسترجاع.

الخطوة 6: تنفيذ ضمن صندوق رمل E2B

السماح لنموذج لغوي بتشغيل بايثون محليًا مقبول للنماذج الأولية الموثوقة، لكن أنظمة الإنتاج تحتاج عزلًا. يتكامل smolagents مع E2B للحصول على صناديق رمل بعيدة — كل تشغيل للوكيل يحصل على حاوية سحابية مؤقتة.

from smolagents import CodeAgent, E2BExecutor
 
research_agent = CodeAgent(
    tools=[DuckDuckGoSearchTool(), fetch_page],
    managed_agents=[managed_math],
    model=model,
    max_steps=12,
    executor_type="e2b",
    executor_kwargs={"api_key": os.environ["E2B_API_KEY"]},
)

هذا التغيير الواحد ينقل كل سطر من الكود المولّد من جهازك إلى حاوية سريعة الزوال. الوصول إلى الشبكة ونظام الملفات وحدود المعالج كلها قابلة للضبط عبر executor_kwargs. كود الوكيل يبقى مطابقًا — فقط المنفّذ يتغيّر.

للعزل المحلي بدون E2B، يدعم smolagents أيضًا منفّذًا قائمًا على Docker:

research_agent = CodeAgent(
    tools=[fetch_page],
    model=model,
    executor_type="docker",
    executor_kwargs={"image": "python:3.12-slim"},
)

الخطوة 7: البث المباشر والمراقبة

عمليات الوكيل الطويلة تحتاج تغذية راجعة. مرّر stream_outputs=True لعرض الرموز فور وصولها:

for chunk in research_agent.run(
    "لخّص أبرز 5 أوراق علمية في الذكاء الاصطناعي عام 2025",
    stream_outputs=True,
):
    print(chunk, end="", flush=True)

للتتبّع المنظم، يصدر smolagents مسارات OpenTelemetry جاهزة. اضبط مُصدّر OTLP يشير إلى Langfuse أو Honeycomb أو أي خلفية متوافقة:

from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
 
provider = TracerProvider()
provider.add_span_processor(
    BatchSpanProcessor(OTLPSpanExporter(endpoint="https://cloud.langfuse.com/api/public/otel/v1/traces"))
)
trace.set_tracer_provider(provider)

كل استدعاء أداة وخطوة تخطيط واستدعاء نموذج يصبح الآن مسارًا يمكنك استكشافه بالتفصيل.

الخطوة 8: تقديم الوكيل خلف FastAPI

غلّف الوكيل بطبقة HTTP رفيعة ليمكن دمجه في أي منتج:

from fastapi import FastAPI
from pydantic import BaseModel
 
app = FastAPI()
 
class Question(BaseModel):
    question: str
 
@app.post("/research")
def research(payload: Question):
    answer = research_agent.run(payload.question)
    return {"answer": answer, "steps": len(research_agent.memory.steps)}

شغّله بـ uvicorn main:app --reload --port 8000 ليصبح الوكيل متاحًا على /research. اقرنه بطابور مثل Inngest أو Trigger.dev إذا كانت مهامك تتجاوز 30 ثانية بانتظام.

اختبار التنفيذ

اختبر خط الأنابيب بسؤال يتطلب استرجاعًا وحسابًا معًا:

curl -X POST http://localhost:8000/research \
  -H "Content-Type: application/json" \
  -d '{"question": "ما الفرق في الإنتاجية بين vLLM وTGI على نموذج Llama 3 70B؟"}'

ستحصل على استجابة خلال 15 إلى 40 ثانية حسب النموذج. حمولة JSON تتضمّن الإجابة النهائية وعدد خطوات التفكير المستهلكة.

لاختبارات الانحدار الحتمية، استخدم نموذجًا وهميًا:

from smolagents import FakeModel
 
fake = FakeModel(responses=[
    "Thought: I should search.\nCode:\n```py\nresults = duckduckgo_search(query='vLLM vs TGI')\nprint(results)\n```",
    "Thought: I have enough.\nCode:\n```py\nfinal_answer('vLLM is roughly 2x faster.')\n```",
])
agent = CodeAgent(tools=[DuckDuckGoSearchTool()], model=fake)
assert "2x" in agent.run("vLLM vs TGI throughput?")

FakeModel يُشغّل ردودًا معلّبة، ما يسمح بالتحقق من تسلسل الأدوات دون استهلاك رموز.

استكشاف الأخطاء وإصلاحها

الوكيل يستورد وحدات ممنوعة. أضف الوحدة إلى additional_authorized_imports. إذا احتجت فعلًا المكتبة القياسية كاملة، اضبط additional_authorized_imports=["*"] — لكن داخل صندوق رمل فقط.

أوصاف الأدوات تظهر خاطئة في المسارات. تأكد أن كل معامل لديه type hint وأن docstring يتبع أسلوب Google مع كتلة Args:. المحلّل صارم.

الوكلاء الفرعيون لا يُستدعون أبدًا. المنسّق يقرر متى يُفوّض بناءً على حقل description في ManagedAgent. اكتب الأوصاف بصيغة الأمر واذكر حالات استخدام ملموسة: "استخدمه لتحويل العملات أو حسابات الوحدات."

صندوق E2B ينتهي بانتظاره. عمر الحاوية الافتراضي 5 دقائق. للتشغيل الأطول، مرّر executor_kwargs={"timeout": 1800} (بالثواني).

الرموز ترتفع عند إعادة التشغيل. ذاكرة smolagents تنمو خطيًا مع الخطوات. للاستخدام التحاوري، استدع agent.memory.reset() بين الجولات.

الخطوات التالية

الخلاصة

يراهن smolagents على أن المخرج الصحيح لوكيل نموذج لغوي هو الكود وليس JSON — وقد أثبت هذا الرهان نفسه في المعايير وعمليات النشر الإنتاجي. خلال هذا الدرس بنيت CodeAgent، وأضفت أداة مخصصة، وأضفت طبقة وكيل فرعي للأعمال المتخصصة، ونقلت التنفيذ إلى حاوية معزولة — كل ذلك في بضع مئات من أسطر بايثون.

المكتبة صغيرة عمدًا. بمجرد فهم العناصر الأربعة الأساسية — النموذج، الأداة، الوكيل، المنفّذ — يمكنك قراءة الكود المصدري كاملًا في أمسية وتخصيص أي شيء. هذا أمر نادر في مجال الوكلاء، وهو بالضبط ما يجعل smolagents خيارًا افتراضيًا جيدًا عندما تريد تجريدات أقل وتحكّمًا أكثر.