|
| 1 | +--- |
| 2 | +title: خطافات حدود التنفيذ |
| 3 | +description: اعتراض بداية تنفيذ الـ Crew والـ Flow ومدخلاته ومخرجاته ونهايته باستخدام المزخرف @on |
| 4 | +mode: "wide" |
| 5 | +--- |
| 6 | + |
| 7 | +تعترض خطافات حدود التنفيذ الأطراف الخارجية للتشغيل — قبل بدء أي عمل، وعند |
| 8 | +حسم المدخلات، وعند جاهزية النتيجة النهائية، وعند انتهاء التنفيذ. وهي تعمل مع |
| 9 | +الـ Crew والـ Flow على حد سواء، وتُعد المكان المناسب لفحوصات السياسة على |
| 10 | +مستوى التشغيل وإعادة كتابة المدخلات وتنقية المخرجات. |
| 11 | + |
| 12 | +## نظرة عامة |
| 13 | + |
| 14 | +أربع نقاط اعتراض تغطي الحدود: |
| 15 | + |
| 16 | +| النقطة | التوقيت | `ctx.payload` | |
| 17 | +|--------|---------|---------------| |
| 18 | +| `EXECUTION_START` | Crew أو Flow على وشك البدء | `dict` المدخلات | |
| 19 | +| `INPUT` | المدخلات المحسومة للتنفيذ | `dict` المدخلات | |
| 20 | +| `OUTPUT` | النتيجة النهائية جاهزة | كائن المخرجات | |
| 21 | +| `EXECUTION_END` | انتهى التنفيذ (نجاحًا أو فشلًا) | كائن المخرجات، أو `None` عند الفشل | |
| 22 | + |
| 23 | +بالنسبة إلى الـ Crew، يكون payload المخرجات `CrewOutput`. أما في الـ Flow فهو |
| 24 | +النتيجة النهائية لدالة الـ Flow. |
| 25 | + |
| 26 | +## توقيع الخطاف |
| 27 | + |
| 28 | +```python |
| 29 | +from crewai.hooks import on, HookAborted, InterceptionPoint |
| 30 | + |
| 31 | +@on(InterceptionPoint.EXECUTION_START) |
| 32 | +def boundary_hook(ctx) -> Any | None: |
| 33 | + # Mutate ctx.payload in place, or |
| 34 | + # return a non-None value to replace it, or |
| 35 | + # raise HookAborted(reason, source) to stop the run |
| 36 | + return None |
| 37 | +``` |
| 38 | + |
| 39 | +تتبع خطافات الحدود العقد القياسي: المتابعة (`return None`)، أو التعديل في |
| 40 | +المكان، أو الاستبدال بإرجاع قيمة، أو الإجهاض برفع `HookAborted`. أي إجهاض |
| 41 | +عند أي حد ينتشر خارج `kickoff()` مع سببه. |
| 42 | + |
| 43 | +## مخطط السياق |
| 44 | + |
| 45 | +تتلقى كل نقطة سياقًا منمّطًا. تشترك جميع السياقات في الحقول الأساسية: |
| 46 | + |
| 47 | +```python |
| 48 | +class InterceptionContext: |
| 49 | + payload: Any # The interceptable value (see table above) |
| 50 | + agent: Any = None # Not populated at execution boundaries |
| 51 | + agent_role: str | None # Not populated at execution boundaries |
| 52 | + task: Any = None # Not populated at execution boundaries |
| 53 | + crew: Any = None # The Crew instance (crew runs only) |
| 54 | + flow: Any = None # The Flow instance (flow runs only) |
| 55 | +``` |
| 56 | + |
| 57 | +تضيف سياقات كل نقطة اسمًا بديلًا للـ payload: |
| 58 | + |
| 59 | +```python |
| 60 | +class ExecutionStartContext(InterceptionContext): |
| 61 | + inputs: dict # Same dict as payload |
| 62 | + |
| 63 | +class InputContext(InterceptionContext): |
| 64 | + inputs: dict # Same dict as payload |
| 65 | + |
| 66 | +class OutputContext(InterceptionContext): |
| 67 | + output: Any # The output object |
| 68 | + |
| 69 | +class ExecutionEndContext(InterceptionContext): |
| 70 | + output: Any # The output object (None when status == "failed") |
| 71 | + status: str # "completed" or "failed" |
| 72 | + error: BaseException | None # The exception when status == "failed" |
| 73 | +``` |
| 74 | + |
| 75 | +<Note> |
| 76 | +`ctx.inputs` هو اسم بديل لقاموس المدخلات **الأصلي**، لذا فإن التعديلات في |
| 77 | +المكان عبر أي من الاسمين متكافئة. إذا *استبدل* خطاف سابق الـ payload بإرجاع |
| 78 | +dict جديد، فإن `ctx.payload` وحده يُعاد ربطه — اقرأ واكتب دائمًا عبر |
| 79 | +`ctx.payload` عندما يمكن أن تتسلسل الخطافات. |
| 80 | +</Note> |
| 81 | + |
| 82 | +## تشغيلات الـ Crew مقابل تشغيلات الـ Flow |
| 83 | + |
| 84 | +تعمل خطافات الحدود على كلا وقتي التشغيل، وتنفيذ الـ Crew يجري داخليًا فوق وقت |
| 85 | +تشغيل Flow. لذلك أثناء `crew.kickoff()` يُطلق الخطاف الحدودي العام لحدّ الـ |
| 86 | +Crew (`ctx.crew` مضبوط و`ctx.flow` يساوي `None`) **و** للـ Flow الداخلي |
| 87 | +(`ctx.flow` مضبوط و`ctx.crew` يساوي `None`). ميّز حسب وقت التشغيل: |
| 88 | + |
| 89 | +```python |
| 90 | +@on(InterceptionPoint.OUTPUT) |
| 91 | +def crew_output_only(ctx): |
| 92 | + if ctx.crew is None: |
| 93 | + return None # Skip the internal flow (or a bare flow) |
| 94 | + ctx.payload.raw = ctx.payload.raw.strip() |
| 95 | +``` |
| 96 | + |
| 97 | +## حالات استخدام شائعة |
| 98 | + |
| 99 | +### فحص السياسة عند البدء |
| 100 | + |
| 101 | +```python |
| 102 | +@on(InterceptionPoint.EXECUTION_START) |
| 103 | +def enforce_policy(ctx): |
| 104 | + if ctx.crew is not None and not ctx.payload.get("authorized"): |
| 105 | + raise HookAborted(reason="unauthorized execution", source="access-control") |
| 106 | +``` |
| 107 | + |
| 108 | +### إعادة كتابة المدخلات |
| 109 | + |
| 110 | +```python |
| 111 | +@on(InterceptionPoint.INPUT) |
| 112 | +def add_defaults(ctx): |
| 113 | + if ctx.crew is None: |
| 114 | + return None |
| 115 | + ctx.payload.setdefault("locale", "en-US") |
| 116 | + ctx.payload["topic"] = ctx.payload["topic"].strip().lower() |
| 117 | +``` |
| 118 | + |
| 119 | +تتدفق المدخلات المعاد كتابتها إلى استيفاء الـ Task، فيتصرف التشغيل كما لو |
| 120 | +بدأ بالقاموس المعدل. |
| 121 | + |
| 122 | +فضّل `INPUT` لإعادة الكتابة وعامل `EXECUTION_START` كبوابة سماح/منع. إعادة |
| 123 | +الكتابة عند `EXECUTION_START` تظل مُحترمة — في الـ Crew تغذي أيضًا استدعاءات |
| 124 | +`before_kickoff`؛ وفي الـ Flow تُطبق تمامًا كإعادة كتابة `INPUT`. |
| 125 | + |
| 126 | +### تنقية المخرجات |
| 127 | + |
| 128 | +```python |
| 129 | +import re |
| 130 | + |
| 131 | +@on(InterceptionPoint.OUTPUT) |
| 132 | +def redact_emails(ctx): |
| 133 | + if ctx.crew is None: |
| 134 | + return None |
| 135 | + ctx.payload.raw = re.sub( |
| 136 | + r"\b[\w.+-]+@[\w-]+\.[\w.]+\b", "[EMAIL-REDACTED]", ctx.payload.raw |
| 137 | + ) |
| 138 | +``` |
| 139 | + |
| 140 | +يعمل `OUTPUT` قبل `EXECUTION_END`، وكلاهما يرى الـ payload (الذي ربما |
| 141 | +استُبدل) من الخطافات السابقة؛ والقيمة النهائية المعاد كتابتها هي ما يعيده |
| 142 | +`kickoff()`. |
| 143 | + |
| 144 | +### مراقبة الإخفاقات |
| 145 | + |
| 146 | +يُطلق `EXECUTION_END` مرة واحدة بالضبط لكل تنفيذ، عند النجاح والفشل على حد |
| 147 | +سواء. عندما يرفع التشغيل استثناءً — خطأ في Task، أو استثناء في دالة Flow، أو |
| 148 | +`HookAborted` من نقطة سابقة — يتلقى الخطاف `status="failed"` مع الاستثناء في |
| 149 | +`ctx.error`، ويظل الاستثناء الأصلي ينتشر خارج `kickoff()` دون تغيير: |
| 150 | + |
| 151 | +```python |
| 152 | +@on(InterceptionPoint.EXECUTION_END) |
| 153 | +def report_outcome(ctx): |
| 154 | + if ctx.status == "failed": |
| 155 | + notify_policy_engine(status="failed", error=repr(ctx.error)) |
| 156 | + else: |
| 157 | + notify_policy_engine(status="completed") |
| 158 | +``` |
| 159 | + |
| 160 | +تنبيهان: لا يُطلق `EXECUTION_END` عندما لا يكون `EXECUTION_START` قد أُرسل |
| 161 | +أصلًا (الإجهاض عند البدء يعني أن الحد لم يُفتح قط، فلا توجد نهاية تقابله)، |
| 162 | +ورفع `HookAborted` من إرسال `EXECUTION_END` في مسار الفشل يُتجاهل — لم يعد |
| 163 | +هناك ما يُجهض، والخطأ الأصلي هو الغالب. |
| 164 | + |
| 165 | +## الترتيب |
| 166 | + |
| 167 | +لتشغيل Crew يكون ترتيب الحدود: |
| 168 | + |
| 169 | +``` |
| 170 | +EXECUTION_START → before_kickoff callbacks → INPUT → tasks execute → OUTPUT → EXECUTION_END |
| 171 | +``` |
| 172 | + |
| 173 | +لتشغيل Flow، تحسم خطافات الحدود المدخلات قبل أن تبدأ أحداث دورة الحياة: |
| 174 | + |
| 175 | +``` |
| 176 | +EXECUTION_START → INPUT → FlowStartedEvent → flow methods execute → OUTPUT → EXECUTION_END → FlowFinishedEvent |
| 177 | +``` |
| 178 | + |
| 179 | +يحمل `FlowStartedEvent` المدخلات كما حسمتها الخطافات، وإعادة كتابة |
| 180 | +`inputs["id"]` داخل خطاف حدودي تعيد توجيه استعادة الحالة. يظهر الإجهاض عند |
| 181 | +`EXECUTION_START` مع ذلك كحدث `FlowStartedEvent` يتبعه `FlowFailedEvent`، |
| 182 | +ويُبثان عند الإجهاض مع الحمولة كما حسمتها الخطافات التي عملت قبله. |
| 183 | + |
| 184 | +تعمل الخطافات في النقطة نفسها حسب ترتيب التسجيل، الخطافات العامة أولًا ثم |
| 185 | +الخطافات المحدودة بالـ Crew. تُبث القياسات (`HookDispatchedEvent`) مع كل |
| 186 | +إرسال. |
| 187 | + |
| 188 | +## إدارة الخطافات في الاختبارات |
| 189 | + |
| 190 | +```python |
| 191 | +from crewai.hooks import clear_all_hooks |
| 192 | + |
| 193 | +clear_all_hooks() # Clears every point, including boundaries |
| 194 | +``` |
| 195 | + |
| 196 | +## وثائق ذات صلة |
| 197 | + |
| 198 | +- [نظرة عامة على خطافات التنفيذ →](/edge/ar/learn/execution-hooks) |
| 199 | +- [خطافات استدعاء LLM →](/edge/ar/learn/llm-hooks) |
| 200 | +- [خطافات استدعاء الأدوات →](/edge/ar/learn/tool-hooks) |
0 commit comments