تركز هذه المقالة على الفئتين الأخيرتين: استطلاع TaskHandle للمهام غير المتزامنة و تفاصيل استجابة الدردشة المتدفقة، والفخاخ، والاختلافات عبر اللغات.
أولاً، TaskHandle — التجريد الموحد للمهام غير المتزامنة
تقوم ثلاث SDK بتغليف المهام غير المتزامنة فيTaskHandle، وتوفر نفس 4 طرق:
طريقتان لاستدعاء إنشاء المهمة
كل مورد غير متزامن (images.generate / video.generate / audio.generate) لديه معلمة wait:
wait=False(افتراضي): تعيد على الفورTaskHandle، ويقرر كود العمل متى يقوم بالاستطلاع.wait=True: تستدعي SDK داخليًاhandle.wait()، وتعيد الاستجابة بعد الانتهاء. استخدمها فقط عندما تكون متأكدًا من أن واجهة برمجة التطبيقات المستهدفة ستعيد حقلstatus: succeeded— بعض المزودين لم يلتزموا بهذا الاتفاق، مما يجعلwaitتستمر حتىmax_waitقبل أن ترميTimeoutError.
اختلاف الوحدات (⚠️ يجب قراءته)
وحداتpoll_interval و max_wait تختلف في اللغات الثلاث، وهي نقطة شائعة للخطأ عند الانتقال بين اللغات:
إذا تم اعتبار{ pollInterval: 3000 }في TS كأجزاء من الثانية وترجم إلى Pythonpoll_interval=3000، فسوف يجعل SDK ينتظر 50 دقيقة قبل أن يقوم بالاستطلاع مرة ثانية.
مثال: استطلاع Midjourney بشكل صريح باستخدام Python
images.generate(..., wait=False)ترسلpromptإلى واجهة برمجة التطبيقات Midjourney، وتحصل علىhandleعلى الفور، دون حظر.handle.wait(poll_interval=3.0, max_wait=180.0)تستدعي داخليًا POST مرة كل 3 ثوانٍ إلى/midjourney/tasks، حتى تتغيرstatusإلىsucceededأوfailed، أو يتجاوز الوقت الإجمالي 180 ثانية وترميTimeoutError.- بعد الانتهاء، عادةً ما تحتوي
result["response"]["data"]على 4 صور (Midjourney افتراضيًا 2x2 grid).
مثال: استطلاع Midjourney بشكل صريح باستخدام TypeScript
المقارنة بين التوليد المتزامن والمهام غير المتزامنة
إذا كانت واجهة برمجة التطبيقات الخاصة بك تقوم بتوليد الصور بشكل متزامن (NanoBanana / Flux / Seedream)، لا تمررwait:
task_id + /tasks، فهي توليد متزامن؛ حيث تحتوي الاستجابة الخاصة بالتوليد المتزامن بالفعل على النتيجة النهائية في حقل data.
بروتوكول TaskHandle الداخلي
استدعاءTaskHandle.get() هو:
response — حيث يمكن قراءة status من المستوى الأعلى، لذا فإن التبديل بين الاستجابات القديمة والجديدة لا يؤثر على كود العمل.
ثانياً، استجابة SSE المتدفقة (chat.completions)
chat.completions.create(stream=True) هي الواجهة الوحيدة المتدفقة حاليًا في SDK (لم يتم دعم تدفقات الصوت / الفيديو بعد). أنماط التكرار في اللغات الثلاثة مختلفة بطبيعتها:
TypeScript
بايثون
جوا
هيكل chunk المتدفق
كل chunk هوchat.completion.chunk متوافق مع OpenAI:
- عادةً ما يحمل chunk الأول
delta.role: "assistant"لكنcontentفارغ. - كل chunk في المنتصف يحمل
delta.content، يمكن دمجها مباشرة. - chunk الأخير
deltaفارغ، وfinish_reasonهوstop/length/content_filter.
الإلغاء في منتصف الطريق
الإلغاء المبكر يتم احتسابه على التوكنات المدفوعة - التوكنات التي تم إنشاؤها قبل لحظة الإلغاء ستظل تُخصم حسب الاستهلاك الفعلي.
ثلاثة، المهلة وإعادة المحاولة
تشارك الثلاثة SDK نفس استراتيجية إعادة المحاولة:
لإلغاء إعادة المحاولة: مرر
max_retries=0 / maxRetries: 0 / WithMaxRetries(0) عند إنشاء العميل.
استطلاع المهام غير المتزامنة (TaskHandle) لا يتأثر بـ max_retries - حلقتها هي على مستوى الأعمال وليس على مستوى HTTP، وتتحكم فيها max_wait في المدة الإجمالية.
أربعة، الفخاخ الشائعة
- لا تمرر
waitلمزود متزامن: NanoBanana / Flux / Seedream كلها تولد بشكل متزامن، فرضwait=Trueسيجعل SDK يستطلع واجهةtasksالتي لن تتحدث أبداً. - اختلاف وحدات TaskHandle: بايثون بالثواني، TS بالمللي ثانية، تأكد من التحويل عند النقل بين اللغات.
wait=Trueقد يؤدي إلىTimeoutError: يجب أن تستوفي الاستجابةstatus in ('succeeded','failed')للخروج من الحلقة؛ إذا استخدم المزود أسماء حقول أخرى، يجب على كود الأعمال معالجةhandle.get()بنفسه.- الإلغاء المتدفق: التوكنات التي تم إنشاؤها قبل الإلغاء قد تم احتسابها.
- إعادة استخدام العميل داخل نفس العملية: SDK يأتي مع مجموعة اتصالات، إنشاء
new AceDataCloud()/AceDataCloud()بشكل متكرر سيجعل مصافحة TLS تصبح عنق الزجاجة.

