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

دليل CrewAI 2026: بناء أنظمة وكلاء ذكاء اصطناعي متعددين بلغة بايثون

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

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

على عكس الأطر القائمة على الرسوم البيانية مثل LangGraph أو منفّذي الوكيل الواحد مثل OpenAI Agents SDK، تعامل CrewAI التنسيق وكأنه هيكل تنظيمي لشركة. في هذا الدرس ستقوم بتثبيت CrewAI من الصفر، وبناء طاقم بحث سوقي من أربعة وكلاء، وتزويده بأدوات تصفّح وكتابة ملفات، والتبديل بين العمليات التسلسلية والهرمية، وإضافة ذاكرة طويلة الأمد، وأخيراً تجهيز كل شيء للاستخدام الإنتاجي.

المتطلبات الأساسية

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

  • Python 3.10 أو أحدث
  • مفتاح OpenAI أو Anthropic (أو تثبيت محلي لـ Ollama)
  • مفتاح Serper.dev مجاني للبحث على الويب (اختياري لكن مستحسن)
  • إلمام أساسي بفئات بايثون والمزخرفات و async/await
  • محرر كود (يُفضّل VS Code مع إضافة Python)

ماذا ستبني

في نهاية هذا الدرس سيكون لديك:

  1. مشروع CrewAI جاهز عبر uv وأدوات الـ CLI الرسمية
  2. طاقم من أربعة وكلاء — باحث ومحلل وكاتب ومحرر — يُنتج موجزاً سوقياً مصقولاً
  3. أدوات بحث على الويب وكتابة ملفات موصولة بالوكلاء المناسبين
  4. تنفيذ تسلسلي ونسخة هرمية بمدير من نفس الطاقم
  5. ذاكرة قصيرة وطويلة المدى مفعّلة بتضمينات vector
  6. callbacks مخصّصة تبث أفكار الوكلاء واستدعاءات الأدوات لحظياً
  7. نقطة وصول FastAPI تُشغّل الطاقم عند الطلب
  8. مراقبة عبر تيليمتري CrewAI Plus وسجلات منظّمة

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

تأتي CrewAI كحزمة واحدة مع إضافات اختيارية للأدوات والتضمينات والنشر. ابدأ ببيئة معزولة — uv هي الأسرع في 2026.

mkdir market-crew && cd market-crew
uv venv --python 3.11
source .venv/bin/activate
uv pip install "crewai[tools]" python-dotenv fastapi uvicorn

أو باستخدام pip التقليدي:

python -m venv .venv
source .venv/bin/activate
pip install "crewai[tools]" python-dotenv fastapi uvicorn

تحقّق من التثبيت:

crewai version
# CrewAI version: 0.86.x

الخطوة 2: إعداد هيكل المشروع

تأتي CrewAI مع CLI يولّد بنية المجلدات التي يتوقّعها الإطار. شغّل المولّد من المجلد الأب.

cd .. && crewai create crew market-crew

عند السؤال اختر openai كمزوّد و gpt-4o-mini كموديل. سيُنشئ الـ CLI هذه البنية:

market-crew/
├── src/
│   └── market_crew/
│       ├── config/
│       │   ├── agents.yaml
│       │   └── tasks.yaml
│       ├── crew.py
│       ├── main.py
│       └── tools/
├── .env
├── pyproject.toml
└── README.md

ملفّا الـ YAML هما حيث ستكتب معظم منطقك. ملف agents.yaml يُعرّف الأدوار والأهداف، وملف tasks.yaml يُعرّف ماذا يجب أن يُنتج كل وكيل.

أضف مفاتيحك إلى .env:

OPENAI_API_KEY=sk-...
SERPER_API_KEY=...      # من serper.dev، اختياري
MODEL=gpt-4o-mini

الخطوة 3: تعريف الوكلاء

افتح src/market_crew/config/agents.yaml واستبدل المحتوى الافتراضي بأربعة أدوار متخصّصة.

researcher:
  role: >
    باحث سوقي أول متخصص في {industry}
  goal: >
    جمع أحدث الحقائق والإحصاءات والاقتباسات الموثّقة حول {topic}
    من مصادر ويب عامة نُشرت خلال آخر اثني عشر شهراً.
  backstory: >
    قضيت عقداً كاملاً في McKinsey تدير البحوث الأولية والثانوية.
    تتحقّق من كل ادعاء عبر مصدرين مستقلّين على الأقل، وتُرفق كل
    معلومة بتاريخ نشرها ورابطها.
  verbose: true
  allow_delegation: false
 
analyst:
  role: >
    محلل استراتيجي في قطاع {industry}
  goal: >
    تحويل ملاحظات الباحث الخام إلى SWOT ومصفوفة تنافسية وثلاث
    توصيات قابلة للتنفيذ موجّهة إلى {target_audience}.
  backstory: >
    تكتب نوع المذكرات ذات الصفحتين التي يقرؤها الرؤساء التنفيذيون،
    وترفض إدراج أي ادعاء غير مدعوم بمصدر موثّق من ملاحظات الباحث.
  verbose: true
 
writer:
  role: >
    كاتب تحريري أول
  goal: >
    إنتاج موجز تنفيذي من 1200 كلمة حول {topic} يستطيع مستثمر
    قراءته في أقل من ست دقائق وإعادة توجيهه إلى شركائه.
  backstory: >
    سبق أن كتبت في Stratechery أسبوعياً. تفضّل الجمل القصيرة
    والأمثلة الملموسة وأطروحة واحدة قوية لكل مقال.
  verbose: true
 
editor:
  role: >
    رئيس التحرير
  goal: >
    التحقّق من الموجز مقابل قائمة مصادر الباحث، وإصلاح الصياغة
    الضعيفة، والتأكّد من أن كل ادعاء يستشهد بمصدره.
  backstory: >
    أدرت قسم المعايير في The Economist لمدة ثماني سنوات. لا تسمح
    لأي رقم غير موثّق بالمرور.
  verbose: true

تُبدّل CrewAI القيم النائبة {industry} و {topic} و {target_audience} تلقائياً عند التشغيل من المدخلات التي تمرّرها للطاقم.

الخطوة 4: تعريف المهام

عدّل src/market_crew/config/tasks.yaml:

research_task:
  description: >
    اجمع ما لا يقل عن 12 معلومة عالية الجودة حول {topic} في قطاع
    {industry}. لكل معلومة سجّل: الادعاء، رابط المصدر، تاريخ
    النشر، وملخّص في جملة واحدة.
  expected_output: >
    قائمة markdown تحتوي على 12 نقطة على الأقل. كل نقطة يجب أن
    تتضمّن رابط المصدر وتاريخه. لا إعادة صياغة بدون استشهاد.
  agent: researcher
 
analysis_task:
  description: >
    باستخدام نتائج الباحث، أنتج تحليل SWOT لـ {target_audience}
    يدخلون سوق {topic}، ومصفوفة تنافسية من 5 صفوف، وبالضبط ثلاث
    توصيات مرتّبة حسب الأثر.
  expected_output: >
    مستند markdown بثلاثة أقسام: SWOT، المصفوفة التنافسية،
    التوصيات. كل ادعاء رقمي يجب أن يستشهد بمعلومة من الباحث.
  agent: analyst
  context:
    - research_task
 
writing_task:
  description: >
    اكتب موجزاً تنفيذياً من 1200 كلمة حول {topic} موجّهاً إلى
    {target_audience}. ابدأ بأطروحة من جملة واحدة. استخدم SWOT
    وتوصيات المحلل. اختم بقسم "ما يجب مراقبته" يحتوي على ثلاثة
    مؤشرات استشرافية.
  expected_output: >
    موجز markdown مصقول بين 1100 و 1300 كلمة، بعناوين H2
    واستشهادات مدمجة كروابط markdown.
  agent: writer
  context:
    - research_task
    - analysis_task
 
editing_task:
  description: >
    حرّر الموجز للوضوح والدقّة. كل ادعاء رقمي يجب أن يستشهد بمصدر
    من قائمة الباحث. أعلم عن أي ادعاء غير مدعوم بإستبداله بتعليق
    TODO.
  expected_output: >
    الموجز النهائي بصيغة markdown محفوظاً في `output/brief.md`.
  agent: editor
  context:
    - research_task
    - analysis_task
    - writing_task
  output_file: output/brief.md

حقل context هو حيث يعيش نموذج التعاون في CrewAI. كل مهمّة تستقبل نواتج المهام التي تعتمد عليها كمدخلات — دون الحاجة إلى ربط prompts يدوياً.

الخطوة 5: ربط الطاقم

افتح src/market_crew/crew.py. ولّد الـ CLI هيكلاً افتراضياً، استبدله بهذه النسخة.

from crewai import Agent, Crew, Process, Task
from crewai.project import CrewBase, agent, crew, task
from crewai_tools import SerperDevTool, FileWriterTool
 
@CrewBase
class MarketCrew:
    """طاقم بحث سوقي من أربعة متخصصين."""
 
    agents_config = "config/agents.yaml"
    tasks_config = "config/tasks.yaml"
 
    @agent
    def researcher(self) -> Agent:
        return Agent(
            config=self.agents_config["researcher"],
            tools=[SerperDevTool()],
        )
 
    @agent
    def analyst(self) -> Agent:
        return Agent(config=self.agents_config["analyst"])
 
    @agent
    def writer(self) -> Agent:
        return Agent(config=self.agents_config["writer"])
 
    @agent
    def editor(self) -> Agent:
        return Agent(
            config=self.agents_config["editor"],
            tools=[FileWriterTool()],
        )
 
    @task
    def research_task(self) -> Task:
        return Task(config=self.tasks_config["research_task"])
 
    @task
    def analysis_task(self) -> Task:
        return Task(config=self.tasks_config["analysis_task"])
 
    @task
    def writing_task(self) -> Task:
        return Task(config=self.tasks_config["writing_task"])
 
    @task
    def editing_task(self) -> Task:
        return Task(config=self.tasks_config["editing_task"])
 
    @crew
    def crew(self) -> Crew:
        return Crew(
            agents=self.agents,
            tasks=self.tasks,
            process=Process.sequential,
            verbose=True,
        )

بعض النقاط الجديرة بالملاحظة:

  • المُزخرف @CrewBase يربط ملفات YAML بأشياء بايثون عند البناء.
  • المزخرفان @agent و @task يزخرفان دوال المصنع، وترتيب مزخرفات @task يحدّد ترتيب التنفيذ في الوضع التسلسلي.
  • فقط الباحث يحصل على البحث عبر الإنترنت وفقط المحرر يحصل على كتابة الملفات. إبقاء سطح الأدوات ضيّقاً هو أكبر مكسب موثوقية في الأنظمة متعدّدة الوكلاء.

الخطوة 6: تشغيل الطاقم

عدّل src/market_crew/main.py ليمرّر المدخلات.

from market_crew.crew import MarketCrew
 
def run():
    inputs = {
        "topic": "وكلاء الذكاء الاصطناعي للبرمجة في منصات المطوّرين المؤسسية",
        "industry": "أدوات المطوّرين",
        "target_audience": "قادة الهندسة في شركات Series B",
    }
    MarketCrew().crew().kickoff(inputs=inputs)
 
if __name__ == "__main__":
    run()

شغّله:

crewai run

سترى كل وكيل يُعلن دوره ويبحث على الويب ويصوغ ثم يُسلّم للتالي. الموجز النهائي يصل إلى output/brief.md. على gpt-4o-mini تكلّف الجولة الكاملة حوالي عشرة سنتات وتستغرق نحو أربع دقائق.

الخطوة 7: التحويل إلى عملية هرمية

التسلسلي جيّد لخط أنابيب ثابت. عندما تريد مديراً يقرّر من يعمل على ماذا، حوّل إلى Process.hierarchical. استبدل دالة crew:

from crewai import Agent
 
@crew
def crew(self) -> Crew:
    manager = Agent(
        role="مدير التحرير",
        goal="تحديد ترتيب المهام وتفويضها إلى المتخصص المناسب",
        backstory="مدير مكتب سابق في Bloomberg يُدير قاعات تحرير منضبطة.",
        allow_delegation=True,
        verbose=True,
    )
    return Crew(
        agents=self.agents,
        tasks=self.tasks,
        process=Process.hierarchical,
        manager_agent=manager,
        verbose=True,
    )

في الوضع الهرمي يقرأ المدير وصف كل مهمّة، ويختار وكيلاً، ويقيّم المخرجات، ويمكنه إعادة الدورة. يكلّف tokens أكثر لكنه يتعامل مع سير العمل الغامض أفضل بكثير من خط أنابيب ثابت.

الخطوة 8: إضافة الذاكرة

افتراضياً تبدأ كل جولة من الصفر. لتراكم المعرفة عبر الجولات، فعّل الذاكرة.

from crewai import Crew, Process
 
@crew
def crew(self) -> Crew:
    return Crew(
        agents=self.agents,
        tasks=self.tasks,
        process=Process.sequential,
        memory=True,
        embedder={
            "provider": "openai",
            "config": {"model": "text-embedding-3-small"},
        },
        verbose=True,
    )

تحتفظ CrewAI الآن بثلاثة مخازن ذاكرة:

  • قصيرة المدى: مساحة مشاركة للجولة الحالية
  • طويلة المدى: مخزن vector ثابت عبر الجولات (SQLite + Chroma على القرص افتراضياً)
  • الكيانات: الكيانات المستخرجة وعلاقاتها

أعد تعيين الذاكرة بـ crewai reset-memories. للنشر على نطاق الفريق بدّل المُضمِّن إلى bedrock أو vertex ووجّه المخزن طويل المدى إلى Postgres مُدار مع pgvector.

الخطوة 9: بث أفكار الوكلاء عبر Callbacks

لدمج واجهة المستخدم أو التصحيح، عادةً تريد كل خطوة بشكل فوري. تعرض CrewAI callbacks على مستوى المهمّة والخطوة.

from crewai.tasks.task_output import TaskOutput
 
def on_task_complete(output: TaskOutput) -> None:
    print(f"[task:{output.task.description[:60]}] -> {len(output.raw)} chars")
 
def on_step(step: dict) -> None:
    if step.get("tool"):
        print(f"  tool call: {step['tool']} args={step['tool_input']}")
 
@task
def research_task(self) -> Task:
    return Task(
        config=self.tasks_config["research_task"],
        callback=on_task_complete,
    )

للبث على مستوى الخطوة مرّر step_callback=on_step عند بناء كل Agent. وجّه تلك الـ callbacks إلى Server-Sent Events وستحصل على تغذية وكيل حيّة في تطبيقك.

الخطوة 10: عرض الطاقم كـ API

تتكامل CrewAI بشكل ممتاز مع FastAPI. أنشئ src/market_crew/api.py:

from fastapi import FastAPI
from pydantic import BaseModel
from market_crew.crew import MarketCrew
 
app = FastAPI()
 
class BriefRequest(BaseModel):
    topic: str
    industry: str
    target_audience: str
 
@app.post("/brief")
def generate_brief(req: BriefRequest):
    result = MarketCrew().crew().kickoff(inputs=req.model_dump())
    return {"output": result.raw, "token_usage": result.token_usage}

شغّله:

uv run uvicorn market_crew.api:app --reload --port 8000

اختبره بـ curl:

curl -X POST http://localhost:8000/brief \
  -H "content-type: application/json" \
  -d '{"topic":"AI coding agents","industry":"developer tools","target_audience":"CTOs"}'

في الإنتاج، شغّل الـ API خلف Gunicorn مع فئة عامل Uvicorn، اضبط مهلة الطلب على حوالي خمس دقائق لجولات الطاقم، وأَوكِل الإطلاقات إلى Celery أو Hatchet إذا توقّعت حمولة متزامنة.

الخطوة 11: إضافة المراقبة

تأتي CrewAI مع تيليمتري من الدرجة الأولى عبر CrewAI Plus، لكن يمكنك أيضاً استخدام OpenTelemetry مباشرةً. المسار المجاني هو السجلات المنظّمة.

import logging, json, time
 
class CrewLogFormatter(logging.Formatter):
    def format(self, record):
        payload = {
            "ts": int(time.time() * 1000),
            "level": record.levelname,
            "msg": record.getMessage(),
        }
        return json.dumps(payload)
 
handler = logging.StreamHandler()
handler.setFormatter(CrewLogFormatter())
logging.getLogger("crewai").addHandler(handler)
logging.getLogger("crewai").setLevel(logging.INFO)

أرسل stdout إلى Loki أو Datadog أو ClickHouse مستضاف ذاتياً وستتمكّن من الإجابة عن "أي وكيل أحرق أكبر عدد من tokens الأسبوع الماضي" دون مشروع ثانٍ. لتتبّع spans قم بتثبيت crewai[telemetry] ووجّه OTEL_EXPORTER_OTLP_ENDPOINT إلى مجمّعك.

الخطوة 12: اختبار الطاقم بشكل قطعي

جولات تعدّد الوكلاء غير قطعية افتراضياً. للـ CI استبدل LLM بمزيّف.

from crewai.llm import LLM
from market_crew.crew import MarketCrew
 
class FakeLLM(LLM):
    def __init__(self):
        super().__init__(model="fake")
        self.replies = iter([
            "- finding 1 (https://example.com 2026-01-01)",
            "## SWOT\n- strength: x",
            "Brief draft...",
            "Edited brief.",
        ])
 
    def call(self, messages, **kwargs):
        return next(self.replies)
 
def test_crew_smoke(monkeypatch):
    monkeypatch.setattr("crewai.agent.LLM", FakeLLM)
    out = MarketCrew().crew().kickoff(inputs={
        "topic": "x", "industry": "y", "target_audience": "z",
    })
    assert "Edited brief." in out.raw

شغّله بـ uv run pytest. تنتهي المجموعة بأكملها في أقل من ثانية وتمنحك تغطية انحدار على ربط الـ prompt والأدوات دون استهلاك أرصدة API.

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

تحقّق من السلوك الشامل:

  1. الأمر crewai run يُنتج output/brief.md بـ 1100 كلمة على الأقل
  2. الموجز يحتوي على ثمانية استشهادات مدمجة على الأقل
  3. تشغيل crewai run مرّة ثانية يسحب الذاكرة طويلة المدى إلى prompt الباحث (تحقّق من سجل verbose)
  4. نقطة وصول FastAPI تُرجع payload يحتوي على output و token_usage
  5. اختبار pytest بـ LLM المزيّف ينجح في أقل من ثانية

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

"AuthenticationError: Missing OPENAI_API_KEY" — تأكّد أن shell قام بتحميل .env. الأمر uv run يفعل ذلك تلقائياً، بينما python العادي لا يفعل. أضف from dotenv import load_dotenv; load_dotenv() في أعلى main.py.

الوكلاء يهلوسون مصادر — ضيّق prompt الباحث. أضف قاعدة صريحة: "إذا لم تجد مصدراً، اكتب NO_SOURCE بدلاً من اختراع واحد." ثم اجعل مهمّة المحرر تُفشل الجولة إذا ظهر أي رمز NO_SOURCE.

الجولات الهرمية تدور إلى الأبد — اضبط max_iter=15 على وكيل المدير. الافتراضي 25 وهو سخي جداً لمعظم سير العمل.

الذاكرة تنزف عبر المواضيعcrewai reset-memories --all بين الجولات غير المرتبطة، أو افصل مساحة الأسماء للذاكرة طويلة المدى بضبط CREWAI_STORAGE_DIR لكل مشروع.

استدعاءات الأدوات تُرجع HTML خام — لفّ SerperDevTool بمحوّل markdown أو استخدم ScrapeWebsiteTool من crewai_tools لتنظيف المخرجات قبل أن يراها الوكيل.

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

  • أضف طبقة مخرجات بأنماط Pydantic AI أمام الطاقم لمخطّطات موجز آمنة الأنواع
  • اربط مشرف LangGraph فوقه لسير عمل متفرّع
  • جدول الطاقم على cron من Hatchet وانشر الموجز على Slack كل صباح اثنين
  • استبدل الكاتب بعملية فرعية من Claude Agent SDK لميزانيات استدلال أطول

الخلاصة

قوّة CrewAI أنها تُجبرك على التفكير في سير عمل الذكاء الاصطناعي بنفس الطريقة التي تفكّر بها في تكوين فريق بشري. كل وكيل له وظيفة ومخرج وصندوق أدوات ضيّق. بمجرّد أن يصبح الـ YAML صحيحاً، يبقى كود بايثون أقل من مئة سطر، ومسار الترقية من خط أنابيب تسلسلي بسيط إلى طاقم هرمي مدعوم بالذاكرة ومُجهّز بالمراقبة هو في معظمه تكوين فقط.

إذا كانت مشكلتك تحتوي فعلاً على عدّة متخصصين، توقّف عن محاولة جعل وكيل واحد يفعل كل شيء. وظّف طاقماً.