DEV Community

Cover image for وكلاء الذكاء الاصطناعي واستدعاءات API طويلة الأمد: الاستقصاء مقابل الويب هوكس
Yusuf Khalidd
Yusuf Khalidd

Posted on Originally published at apidog.com

وكلاء الذكاء الاصطناعي واستدعاءات API طويلة الأمد: الاستقصاء مقابل الويب هوكس

تصميم عمليات غير متزامنة يمكن لوكلاء الذكاء الاصطناعي اتباعها

يستدعي الوكيل نقطة نهاية تحويل ترميز الفيديو، فتُعيد النقطة 202 Accepted ومعرّف مهمة. لكن الوكيل، الذي لا يعرف دلالة 202 في نظامك، قد يعلن اكتمال التحويل وينتقل إلى خطوة تقرأ ملفًا لم يُنشأ بعد.

جرّب Apidog اليوم

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

يوضح هذا الدليل كيفية:

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

يتناول دليل استعادة أخطاء الوكيل فشل استدعاءات API، بينما يركز هذا الدليل على العمليات التي تنجح، ولكن ببطء.

يتناسب Apidog مع هذه الحالة، لأنه يساعدك على اختبار مهمة تستغرق أربع دقائق ثم تفشل قبل اكتشاف المشكلة في الإنتاج.

لماذا يسيء الوكلاء التعامل مع العمليات غير المتزامنة؟

تسبب ثلاث عادات معظم المشاكل.

1. اعتبار كل رمز 2xx اكتمالًا

يشير الرمز 202 Accepted إلى قبول الطلب للمعالجة، ولا يعني أن المعالجة اكتملت. وتوضح مواصفات دلالات HTTP ذلك صراحة.

تميل النماذج المدربة على نمط الطلب/الاستجابة التقليدي إلى تفسير أي رمز 2xx على أنه نجاح نهائي، ما لم توضّح الاستجابة خلاف ذلك.

2. الاستطلاع داخل حلقة التفكير

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

يوضح دليل إبقاء استجابات الأدوات خارج نافذة السياق سبب تراكم هذه التكلفة أسرع مما يبدو.

3. فقدان معرّف المهمة

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

صمّم الاستجابة بحيث لا يسيء النموذج قراءتها

الإصلاح الأكثر فعالية هو الصياغة الواضحة. اجعل نص الاستجابة يشرح ما حدث وما يجب فعله بعد ذلك، بصرف النظر عن رمز الحالة.

{
  "status": "processing",
  "job_id": "job_7f21c",
  "message": "The transcode has STARTED and is NOT complete. Do not report success. Check status with getJobStatus(job_id) after at least 30 seconds.",
  "poll_after_seconds": 30,
  "estimated_duration_seconds": 240,
  "status_url": "/v1/jobs/job_7f21c"
}
Enter fullscreen mode Exit fullscreen mode

قد تبدو هذه الصياغة مبالغًا فيها لمستهلك API بشري، لكنها مناسبة للنموذج. ثلاث تفاصيل مهمة هنا:

  • التصريح بأن العملية غير مكتملة.
  • تحديد اسم الأداة التالية.
  • تحديد الحد الأدنى للانتظار قبل الاستطلاع.

تصف مواصفة AIP-151 للعمليات طويلة الأمد موردًا موحدًا يحمل حقولًا مثل done وerror وresponse. يساعد تبني هذا النمط على توحيد جميع نقاط النهاية البطيئة، ويتيح للوكيل تعلم نمط استطلاع واحد.

اجعل استجابة الحالة واضحة أيضًا:

{
  "job_id": "job_7f21c",
  "status": "processing",
  "done": false,
  "progress_percent": 45,
  "elapsed_seconds": 108,
  "poll_after_seconds": 45,
  "message": "Still processing. Do not proceed to the next step."
}
Enter fullscreen mode Exit fullscreen mode

وعند اكتمال العملية، أعد النتيجة مباشرة إذا كانت صغيرة، حتى لا يحتاج الوكيل إلى استدعاء ثالث:

{
  "job_id": "job_7f21c",
  "status": "succeeded",
  "done": true,
  "result": {
    "output_url": "https://cdn.example.com/out/7f21c.mp4",
    "duration_seconds": 372
  }
}
Enter fullscreen mode Exit fullscreen mode

عقد استجابة لعملية غير متزامنة

نفّذ الاستطلاع خارج النموذج

القاعدة الأهم: ضع الانتظار داخل غلاف الأداة، وليس داخل حلقة تفكير الوكيل.

import time

def start_and_await_transcode(client, source_url, max_wait=600):
    job = client.post("/v1/transcode", json={"source_url": source_url}).json()
    job_id = job["job_id"]
    delay = job.get("poll_after_seconds", 5)
    waited = 0

    while waited < max_wait:
        time.sleep(delay)
        waited += delay
        status = client.get(f"/v1/jobs/{job_id}").json()

        if status.get("done"):
            if status["status"] == "succeeded":
                return {"status": "succeeded", "result": status["result"]}
            return {"status": "failed", "error": status.get("error")}

        delay = min(int(delay * 1.5), 60)

    return {
        "status": "timed_out",
        "job_id": job_id,
        "message": f"Still running after {max_wait}s. Job {job_id} continues in the background.",
    }
Enter fullscreen mode Exit fullscreen mode

من جانب النموذج، يصبح هذا استدعاء أداة واحدًا يستغرق وقتًا ثم يعيد نتيجة نهائية. لا توجد حلقة استطلاع في السياق، ولا معرّفات مهام منسية، ولا 120 دورة.

يحافظ التراجع التدريجي على عدد الطلبات معقولًا. ويمكنك الرجوع إلى دليل المهلات وإعادة المحاولة والتراجع مع التذبذب عند ضبط هذه القيم.

اجعل التنفيذ آمنًا باتباع قاعدتين:

  1. حدّد دائمًا سقفًا للانتظار.
  2. أعد دائمًا job_id عند انتهاء المهلة، حتى يتمكن الوكيل أو الإنسان من التحقق لاحقًا.

لا تستخدم نتيجة غامضة. يجب أن يرى النموذج قيمًا مختلفة بوضوح:

  • succeeded: نجحت العملية.
  • failed: فشلت العملية.
  • timed_out: انتهت مهلة الانتظار، وقد تستمر العملية في الخلفية.

بالنسبة للمهام التي تستغرق ساعات، لا يعد الاستطلاع داخل الغلاف مناسبًا. استخدم أداتين:

  • أداة لبدء المهمة.
  • أداة للتحقق من حالتها.

وخزّن المهام قيد التنفيذ خارج المحادثة، بما في ذلك:

  • job_id.
  • المهمة أو التشغيل الذي تنتمي إليه.
  • وقت البدء.
  • الحالة الحالية.

اقرأ هذه القائمة في بداية كل تشغيل حتى لا تضيع المهام بسبب ضغط السياق.

متى تكون Webhooks أفضل؟

الاستطلاع أبسط ويعمل في معظم البيئات، بينما تكون Webhooks أكثر كفاءة ولكنها تتطلب بنية إضافية. يوضح دليل Webhooks مقابل الاستطلاع المفاضلة العامة، ويمكن تطبيقها على الوكلاء كالتالي.

استخدم الاستطلاع عندما:

  • تستغرق المهمة ثوانٍ إلى دقائق.
  • يحتاج الوكيل إلى النتيجة قبل متابعة العمل.
  • لا تستطيع استضافة نقطة نهاية عامة.

استخدم Webhooks عندما:

  • تستغرق المهمة ساعات.
  • يبدأ الوكيل العمل ثم ينتقل إلى مهمة أخرى.
  • تعمل مهام كثيرة في الوقت نفسه، ويصبح استطلاع كل مهمة مكلفًا.

تحتاج Webhooks إلى:

  • مستقبل عام.
  • التحقق من التوقيع.
  • معالجة إعادة المحاولة.
  • طريقة لإيقاظ الوكيل عند وصول الإشعار.

راجع دليلي تصميم Webhooks موثوقة والتحقق من توقيع Webhook لتغطية هذه الأساسيات.

هناك خيار متوسط: بث تقدم المهمة باستخدام Server-Sent Events (SSE). يمنحك دلالات الدفع دون نقطة نهاية عامة، لأن العميل يحتفظ بالاتصال. يناسب ذلك الوكلاء التفاعليين الذين يراقبهم إنسان، كما يوضح دليل بث استجابات API باستخدام SSE.

أيًا كان الأسلوب، يجب أن يكون مسار الإكمال متكافئًا (idempotent). قد تعيد Webhooks الإرسال، وقد تتنافس عمليات الاستطلاع، ولا ينبغي لوكيل يرى succeeded مرتين أن يبدأ الخطوة التالية مرتين. يشرح دليل مفاتيح التكافؤ لوكلاء الذكاء الاصطناعي كيفية تحقيق ذلك بأمان.

اختبر المسار البطيء، وليس السريع فقط

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

ابنِ هذه السيناريوهات عمدًا:

المهمة البطيئة

حاكي نقطة نهاية الحالة بحيث تعيد processing عدة مرات، ثم succeeded. يجب أن يثبت الاختبار أن الغلاف:

  • يستطلع الحالة.
  • يزيد فترة الانتظار تدريجيًا.
  • يعيد النتيجة في النهاية.

في Apidog، يمكنك التحكم في ذلك بعدد الطلبات أو باستخدام معلمة مخصصة، بحيث يتكرر الاختبار بالطريقة نفسها.

الفشل المتأخر

أعد processing ثلاث مرات، ثم failed مع رسالة خطأ. يجب أن يبلغ الوكيل عن الفشل بدل اعتبار انتهاء الاستطلاع نجاحًا.

انتهاء المهلة

اجعل المحاكاة تعيد processing بعد تجاوز سقف الغلاف. يجب أن تعيد الأداة:

{
  "status": "timed_out",
  "job_id": "job_7f21c"
}
Enter fullscreen mode Exit fullscreen mode

لا تستبدل ذلك باستثناء أو نجاح زائف.

الإكمال المكرر

سلّم النجاح مرتين، إما بإعادة محاولة Webhook أو باستطلاع متزامن. تأكد من أن الخطوة التالية تعمل مرة واحدة فقط.

اختبار العمليات البطيئة والفاشلة

احفظ السيناريوهات الأربعة وشغّلها في CI. يوضح دليل اختبار عقود API نهجًا أوسع لبناء هذه الاختبارات.

ثلاث مهام تكشف المشكلة

توليد التقارير

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

باستخدام غلاف ينتظر النتيجة، ينتظر الوكيل 90 ثانية ويعيد عنوان URL الحقيقي. واجهة API نفسها، لكن الفرق هو مكان حدوث الانتظار.

عمليات الاستيراد بالجملة

يحمّل وكيل العمليات 20,000 سجل. تستغرق العملية ثماني دقائق، ثم تفشل جزئيًا عند الصف 14,000. هنا تكون قيمة done صحيحة، لكن النتيجة تحتوي على صفوف مرفوضة.

أعد النتائج الجزئية بوضوح، بما في ذلك التعدادات، واجعل الوكيل يقرأها قبل المتابعة:

{
  "job_id": "job_a11f",
  "status": "completed_with_errors",
  "done": true,
  "summary": {
    "processed": 20000,
    "succeeded": 19860,
    "failed": 140
  },
  "errors_url": "/v1/jobs/job_a11f/errors?limit=50",
  "message": "Import finished. 140 rows failed and were not written. Review errors before reporting success."
}
Enter fullscreen mode Exit fullscreen mode

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

خطوط أنابيب النماذج والبناء

قد يستغرق تدريب نموذج أو تشغيل بناء CI مدة 40 دقيقة. الاستطلاع داخل الغلاف ليس مناسبًا هنا، لأنه سيبقي الدور مفتوحًا فترة طويلة.

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

يجب أن يرى أحدهم المهمة التي توقفت

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

إذا كان الوكيل خدمة تملكها، فأرسله إلى قائمة انتظار يراقبها فريقك. وإذا كان يعمل عبر مهام مخصصة، فاستخدم مكان الوصول الذي توفره المنصة.

في Sharkly، يبقى التشغيل الذي تنتهي مهلته مرتبطًا بمهمته مع حالة التنفيذ والنتيجة، بينما يفصل صندوق الوارد العناصر التي تحتاج إلى رد بشري أو مراجعة عن التحديثات العادية.

النقطة الأساسية ليست الأداة المحددة؛ بل أن عبارة «لا يزال قيد التشغيل، تحقّق لاحقًا» تحتاج إلى مالك. وإلا ستتحول إلى «لم يتحقق أحد».

قائمة تحقق

  • كل نقطة نهاية بطيئة تعيد معرّف مهمة، وعنوان URL للحالة، ورسالة واضحة تفيد بأن العمل لم ينتهِ.
  • تحتوي استجابات الحالة على حقل منطقي done.
  • يحدث الاستطلاع داخل غلاف الأداة، مع تراجع تدريجي وسقف صارم.
  • تعيد المهلات معرّف المهمة حتى يمكن استئناف العمل.
  • تكون succeeded وfailed وtimed_out نتائج مميزة.
  • تُسجّل المهام التي تستغرق أكثر من بضع دقائق خارج المحادثة.
  • تكون معالجة الإكمال متكافئة، سواء وصلت الإشارة عبر الاستطلاع أو Webhook.
  • توجد اختبارات للحالة البطيئة، والفشل المتأخر، وانتهاء المهلة، والإكمال المكرر.

اضبط صياغة الاستجابة وغلاف الأداة، وستتوقف العمليات طويلة الأمد عن كونها حالة خاصة للوكيل. سيستدعي الوكيل أداة، وينتظر، ويحصل على إجابة؛ وهذا هو العقد الذي يتعامل معه بأفضل شكل.

استخدم Apidog لبناء محاكيات للمهام البطيئة وتشغيلها إلى جانب اختباراتك.

أسئلة شائعة

هل يجب أن تعيد API الرمز 202 أم 200 لبدء عملية غير متزامنة؟

استخدم 202 Accepted، لأنه يوضح للعملاء القياسيين أن المعالجة لم تكتمل. لكن لا تعتمد عليه وحده مع الوكلاء؛ اجعل نص الاستجابة يوضح الحالة أيضًا.

كم يجب أن تنتظر حزمة الأداة قبل الاستسلام؟

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

ما فترة الاستطلاع المناسبة؟

ابدأ من تلميح الخادم poll_after_seconds إن وُجد، ثم زد التأخير بعامل يقارب 1.5 مع سقف يقارب 60 ثانية. الاستطلاع الثابت كل ثانية يهدر الطلبات وقد يسبب تجاوز حدود المعدل؛ راجع دليل تجاوز حدود المعدل.

هل يستطيع الوكيل تنفيذ عمل مفيد أثناء الانتظار؟

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

كيف أمنع الوكيل من إعلان النجاح مبكرًا؟

  • صرّح بذلك بوضوح في نص الاستجابة.
  • اكشف عن الحقل المنطقي done.
  • اجعل أداة الإكمال المكان الوحيد الذي تظهر فيه النتيجة.

إذا لم تتضمن استجابة البدء نتيجة، فلن يجد النموذج شيئًا يبلّغ عنه على أنه نتيجة نهائية.

هل تعمل Webhooks مع وكلاء يعملون على حاسوب محمول؟

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

Top comments (0)