الانتقال إلى المحتوى الرئيسي
تربط سياسة جدار حماية بمفتاح، يبثّ النموذج استدعاء أداة عائداً، وتجرّده مرحلة response أو تعيد كتابته قبل أن يتصرّف وكيلك بناءً عليه. قرار الفرض متطابق على كل مزود — نفس القواعد، نفس الأحكام، نفس الأحداث. ما يختلف هو شكل السلك الذي يراه عميلك بمجرد أن يتصرّف جدار الحماية على استدعاء أداة مبثوث، لأن OpenAI chat، وOpenAI Responses API، وClaude /v1/messages الأصلي كل منها يؤطّر استدعاءات الأدوات بشكل مختلف. هذه الصفحة هي الملاحظة المركّزة على تلك الفروق الملاحظة من قبل العميل. لا تعيد توثيق لغة القواعد — انظر قواعد جدار الحماية — أو نموذج المرحلة، المغطّى في المراحل. لآلية الاحتجاز-وإعادة-التجميع الداخلية المشتركة بين الثلاثة، اقرأ داخليات البث.

1. لماذا يختلف بث المزود في جدار الحماية حسب السلك

على استجابة غير مبثوثة يرى جدار الحماية الرد كله دفعةً واحدة ويقرّر. على بث، يصل استدعاء أداة النموذج كسلسلة من الشظايا — اسم في إطار، وJSON وسائط يتقطّر عبر إطارات أكثر بكثير. يحتاج حكم الاستدعاء الكامل (الاسم و الوسائط الكاملة)، وشظية استدعاء أداة، بمجرد تمريرها، لا يمكن سحبها. فعلى كل مزود تفعل البوابة نفس الشيء: تدع المحتوى العادي يُبَث حياً، وتحتجز إطارات استدعاء الأداة حتى يُجمَّع الاستدعاء بالكامل. عند نهاية البث تقيّم كل استدعاء مجمَّع وتصدر الناجين فقط — بشكل حدث ذلك المزود الخاص.
نصك لا يتوقّف أبداً. فقط إطارات استدعاء الأداة تُحتجَز. محتوى المساعد، والاستدلال، وإطارات الدور تُبَث حياً ودون تغيير. ينطبق الاحتجاز من أول شظية استدعاء أداة إلى نهاية ذلك الدور — فاستجابة محادثة فقط تُبَث تماماً كأن لا جدار حماية مربوطاً.

2. OpenAI chat completions

على /v1/chat/completions، تُبَث استدعاءات الأدوات كشظايا delta.tool_calls مفتاحها الفهرس. تحتجز البوابة تلك (وشكل delta.function_call القديم)، وعند الإطار الختامي، تصدر الاستدعاءات الناجية مُعاد فهرستها من صفر، متبوعةً بإطار نهاية:
النتيجةماذا يتلقّى عميلك
allowالإطارات المُحتجَزة الأصلية، بايت ببايت — تمرير حقيقي.
sanitizeفرق tool_calls واحد بوسائط مُعاد كتابتها، ثم finish_reason: "tool_calls".
deny (بعض الاستدعاءات)الاستدعاءات الناجية فقط، ثم finish_reason: "tool_calls".
deny (كل الاستدعاءات)لا استدعاء أداة، ثم finish_reason: "stop" — يبدو الدور كأن النموذج اختار الإجابة نصاً.
ذلك الصف الأخير هو الدلالة للاختبار مقابلها: عندما يجرّد جدار حماية كل استدعاء أداة من دور OpenAI chat، يرى وكيلك finish_reason: "stop" نظيفاً، وليس إطار خطأ. ابنِ حلقتك لتعامل “لا استدعاء أداة هذا الدور” كنتيجة صالحة.

3. OpenAI Responses API

بث /v1/responses الأصلي له نموذج حدثه الخاص — استدعاء الأداة عنصر function_call يفتح بـ response.output_item.added، يبثّ شظايا response.function_call_arguments.delta، ويكتمل عند response.output_item.done. يقيّم جدار الحماية عند done، النقطة الأولى التي يكتمل فيها الاستدعاء:
أحداث العنصر added / فرق الوسائط / done تُصدَر دون تغيير بمجرد أن يجتاز الاستدعاء.
قشرة added تُبَث، ثم done وسائطه هي النسخة المنقَّحة — شظايا فرق الوسائط الأصلية تُسقَط فلا تصلك القيمة غير المنقَّحة أبداً.
الأحداث المُخزَّنة تُسقَط، والعنصر المرفوض يُصفّى أيضاً من كائن response.completed النهائي الذي يبني منه عميلك حالته النهائية — لا مرجع معلَّق لاستدعاء لم يعمل أبداً.
فروقات النص والاستدلال تُبَث حياً طوال الوقت، تماماً كما على chat completions.

4. Claude /v1/messages الأصلي

بث Anthropic الأصلي وحش مختلف: يصل المحتوى كـ كتل مفهرسةcontent_block_startcontent_block_delta (شظايا input_json_delta) ← content_block_stop — مُغلَقة بـ message_delta حامل stop_reason. يحتجز جدار الحماية من أول كتلة tool_use، يقيّم كل واحدة، ويعيد بناء الكتل الناجية بـ فهارس متجاورة فكتلة مجرَّدة لا تترك فجوة فهرس. الدلالة الخاصة بـ Claude هي stop_reason. إذا رُفضت كل كتلة tool_use، فـ stop_reason بقيمة tool_use سيعد عميلك باستدعاء أداة لا يصل أبداً — فتعيد البوابة كتابته إلى end_turn:
upstream:  content_block_start (tool_use) … message_delta {stop_reason: "tool_use"}
            ↓ firewall denies the only tool_use
client:    (no tool_use block)            … message_delta {stop_reason: "end_turn"}
تجريد جزئي يبقي كتل tool_use الناجية، مُعاد فهرستها متجاورةً، ويترك stop_reason: "tool_use" سليماً.
ينطبق هذا على بث Claude الأصلي. نموذج Claude مُستدعى عبر نقاط نهاية بصيغة OpenAI يُفرَض على سلك OpenAI chat بدلاً من ذلك (§2)، فيُظهر finish_reason: "stop"، وليس stop_reason: "end_turn". طابق معالجة نهاية الدور لديك مع صيغة السلك التي استدعيتها، وليس النموذج الأساسي.

5. مثال ملموس واحد

نفس القاعدة تنتج نفس القرار على كل مزود — فقط شكل السلك الذي يقرأه عميلك يختلف. ألّفها مرة واحدة، على مرحلة response:
{
  "stage": "response",
  "tool_name_glob": "shell.exec",
  "verdict": "deny",
  "args_match_json": "{\"clauses\":[{\"path\":\"$.command\",\"op\":\"regex\",\"value\":\"rm -rf|mkfs\"}]}"
}
ابثّ نفس المطالبة بثلاث طرق ويرفض جدار الحماية استدعاء rm -rf في كل مرة. ما يرصده عميلك:
السلكالإشارة النهائية بعد تجريد كامل
OpenAI chatfinish_reason: "stop"
OpenAI Responsesالعنصر غائب من response.completed
Claude الأصليstop_reason: "end_turn"
الاستدعاء المطابَق-والمرفوض يظهر متطابقاً في أحداث جدار الحماية بغض النظر عن السلك، فقابليتك للملاحظة محايدة للمزود رغم أن البث ليس كذلك.

6. ما يبقى ثابتاً عبر المزودين

السلك يختلف؛ العقد لا:
  • الأحكام والقواعد محايدة للسلك. allow / audit / deny / sanitize تعني نفس الشيء على كل مزود. انظر الأحكام.
  • sanitize يلمس وسائط استدعاء الأداة فقط، وليس أبداً المحتوى الذي تعيده أداة — على كل سلك. انظر تطهير الاستجابات.
  • allow تمرير حقيقي. عندما لا يتخذ جدار الحماية أي إجراء، تُعاد الإطارات المُحتجَزة كبايتات الأعلى بالضبط — لا إعادة تجميع، لا حقول خاصة بالمزود مفقودة.
  • وضع الظل ينطبق في كل مكان. فعّله وتنجو استدعاءات الأدوات المُحتجَزة دائماً (مُخفَّضة إلى audit) فيمكنك قياس أثر سياسة عبر المزودين قبل أن تغيّر حركة المرور. انظر وضع الظل.

7. أين يقع هذا

داخليات البث

آلية الاحتجاز-التجميع-إعادة-التجميع التي يشاركها كل مزود.

المراحل

لماذا يعيش فرض استدعاء الأداة المبثوث على سطح response.

الأحكام

القرارات المحايدة للمزود التي يُحَل إليها استدعاء مبثوث.

تصفية الاستجابة

حكم استدعاءات الأدوات التي يصدرها نموذج، بثاً أم لا.
للتهديدات التي تعالجها هذه الفحوصات المبثوثة، انظر استدعاءات الأدوات الخطرة و تسريب البيانات؛ ولمكان جلوس فرض البث على مسار الطلب، انظر زمن استجابة مسار الفرض.