العودة إلى المدونة

API وSDKدليل

مهلة وإعادات محاولة OpenAI Python SDK: اضبطها لـ CheapTokens

اضبط timeout وmax_retries وmax_tokens في OpenAI Python SDK، والتقط الأخطاء الصحيحة، وامنع طلبًا عالقًا من العمل لمدة 10 دقائق.

بواسطة CheapTokens Teamنُشر في 4 دقيقة قراءة

كود Python مع timeout=30.0 وmax_retries=2 على خلفية داكنة
في هذه الصفحة
  1. ما يفعله SDK عندما لا تضبط شيئًا
  2. اضبط timeout وmax_retries على العميل
  3. تجاوزه لطلب واحد
  4. التقط الأخطاء المهمة
  5. حدّد max_tokens حتى لا تفلت إجابة طويلة
  6. ماذا تفعل إعادات المحاولة بالفاتورة
  7. قبل أن تنشر

استدعى سكربتك النموذج، ولم يعد شيء، وبعد عشر دقائق لا يزال ينتظر. هذا هو الوضع الافتراضي في OpenAI Python SDK: مهلة 10 دقائق وإعادة محاولتين. لتغيير ذلك، مرّر timeout=30.0 وmax_retries=2 إلى OpenAI(...)، وتجاوزها لكل استدعاء باستخدام client.with_options(...)، وحدّد الإجابة بـmax_tokens.

يوثّق README الخاص بـ SDK (تم التحقق في 27 أكتوبر 2026) كل هذا. أدناه يتم تطبيقه على نقطة نهاية CheapTokens، https://api.cheaptokens.dev/v1، التي تتحدث بصيغة OpenAI Chat Completions. تفاصيل هذا الإعداد موجودة في طلبك الأول لواجهة API مع CheapTokens والوثائق.

ما يفعله SDK عندما لا تضبط شيئًا#

هناك وضعان افتراضيان مهمان. المهلة 10 دقائق. إعادة المحاولات 2، مع تراجع أسي قصير، لأخطاء الاتصال ولردود 408 و409 و429 و5xx، وفقط عندما يمكن إعادة إرسال جسم الطلب بأمان. الطلب الذي تنتهي مهلته يُعاد أيضًا.

لذا تحصل كل محاولة على مهلتها الخاصة، وأسوأ حالة هي تقريبًا المهلة مضروبة في عدد المحاولات، بالإضافة إلى فترات التوقف بينها:

  • الافتراضي: 600 × 3 = 1800 ثانية، نصف ساعة
  • timeout=30.0، max_retries=2: 30 × 3 = 90 ثانية

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

خمّن الرقم

عميل لديه timeout=45.0 وmax_retries=3. ما أقصى انتظار بالثواني قبل الاستثناء، دون احتساب فترات التوقف بين المحاولات؟

إظهار الإجابة

الإجابة: 180

45 × (3 إعادات + 1 محاولة أولى) = 180 ثانية؛ تضيف فترات التوقف بين المحاولات قليلًا فوق ذلك.

اضبط timeout وmax_retries على العميل#

أبسط إصلاح هو ضبط كليهما مرة واحدة، عند إنشاء العميل:

python
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.cheaptokens.dev/v1",
    api_key=os.environ["CHEAPTOKENS_API_KEY"],
    timeout=30.0,      # seconds per attempt
    max_retries=2,     # 0 turns retries off
)

resp = client.chat.completions.create(
    model="deepseek-ai/DeepSeek-V4-Flash-0731",
    messages=[{"role": "user", "content": "Summarize this ticket in two sentences: ..."}],
    max_tokens=800,
)
print(resp.choices[0].message.content)
print(resp.usage.prompt_tokens, resp.usage.completion_tokens)

يجب أن يكون max_retries عددًا صحيحًا غير سالب. يأخذ timeout قيمة float، أو كائن httpx Timeout إذا أردت حدودًا منفصلة للاتصال والقراءة. يستورد README للفرع الرئيسي الحالي httpx2 لذلك، بينما استخدمت الإصدارات الأقدم httpx، لذا شغّل pip show openai وتحقق من أيّهما يستخدمه تثبيتك. لا يحتاج float العادي إلى import ويعمل في الحالتين.

مسار الطلب مع timeout=30 وإعادتين
طلب واحد: محاولة، مهلة، حتى إعادتين، ثم استثناء

استخدم معرّف النموذج الكامل من وثائق CheapTokens، deepseek-ai/DeepSeek-V4-Flash-0731 هنا: تختلف المعرّفات بين المزوّدين. يقبل هذا النموذج حتى 32,768 رمز إخراج لكل إجابة ولديه سياق 380K، ولهذا يوجد سطر max_tokens أعلاه عن قصد. المزيد عنه أدناه، وعن النموذج في cheap DeepSeek.

تجاوزه لطلب واحد#

عميل واحد، مهام مختلفة. رد الدردشة يجب أن يستسلم بسرعة، وملخص ليلي يمكنه الانتظار. بدلًا من إنشاء عميل ثانٍ، اشتق واحدًا للاستدعاء:

python
quick = client.with_options(timeout=5.0, max_retries=0)
resp = quick.chat.completions.create(
    model="deepseek-ai/DeepSeek-V4-Flash-0731",
    messages=[{"role": "user", "content": "Reply with one word: ok"}],
    max_tokens=5,
)

يعيد with_options نسخة بالقيم الجديدة ويترك client كما هو. ضبط max_retries=0 هو الخيار الصحيح عندما يعيد كودك المحاولة بالفعل، مثل طابور مهام يعيد إدراج المهمة. وإلا تتضاعف الطبقتان: 3 محاولات SDK داخل 3 محاولات طابور تعني 9 طلبات لمهمة واحدة.

التقط الأخطاء المهمة#

بعد نفاد إعادات المحاولة، يرفع SDK استثناءً. كل فئة خطأ ترث من openai.APIError، وتحمل الطلبات الفاشلة request_id، وهو ما تسجّله:

python
import openai

def ask(prompt: str) -> str | None:
    try:
        r = client.chat.completions.create(
            model="deepseek-ai/DeepSeek-V4-Flash-0731",
            messages=[{"role": "user", "content": prompt}],
            max_tokens=800,
        )
        return r.choices[0].message.content
    except openai.APITimeoutError:
        print("timed out after retries")
    except openai.RateLimitError as e:
        print("429, slow down:", e.request_id)
    except openai.APIConnectionError:
        print("cannot reach the API")
    except openai.APIStatusError as e:
        print("HTTP", e.status_code, e.request_id)
    return None

الترتيب من الضيق إلى الواسع. يغطي APIStatusError أي رد 4xx أو 5xx، لذا لو جاء أولًا لابتلع RateLimitError. الأمر نفسه ينطبق على المهلة: فهي تقع فوق خطأ الاتصال العام. في سكربت دفعي، return None هو كل الهدف: سجّل الـ prompt، وانتقل إلى التالي، وأعد تشغيل الإخفاقات في النهاية.

عندما تنطلق المهلة وتنفد إعادات المحاولة، هكذا يبدو الاستثناء:

رسالة APITimeoutError بعد نفاد إعادات المحاولة
كيف تبدو مهلة ملتقطة في السجل

لحالة 429 بالتفصيل، بما في ذلك الانتظار بين المحاولات، راجع 429 Too Many Requests من واجهة AI API.

حدّد max_tokens حتى لا تفلت إجابة طويلة#

المهلة توقف الانتظار. لكنها لا تجعل النموذج يكتب أقل. بدون max_tokens، يكون النموذج ذو حد إجابة 32,768 رمزًا حرًا في كتابة رد طويل جدًا، والرد الطويل بطيء. اضبط حدًا يناسب المهمة: 800 لملخص تذكرة، و5 لسؤال نعم/لا.

الثمن هو أن الإجابة قد تُقطع. تحقق من resp.choices[0].finish_reason: length يعني أن الحد وصل قبل أن ينتهي النموذج. لماذا تتوقف إجابة AI في منتصف الجملة؟ يغطي ذلك. إذا بثثت الإجابة بدلًا من ذلك، تصل الكلمات الأولى مبكرًا ويبدو الانتظار أقصر، راجع بث الردود في Python.

ماذا تفعل إعادات المحاولة بالفاتورة#

إعادة المحاولة طلب جديد. إذا عولجت محاولة، فهي طلب منفصل برموزه الخاصة. لنفترض أن ملخص تذكرة يستهلك 1,500 رمز إدخال و400 إخراج: يكلف طلب واحد $0.000063 بأسعار اليوم، ولدى جدول الأسعار الكامل بقية النماذج. الأسعار ثابتة لكل نموذج، بلا ساعات ذروة، لذا تكلف إعادة المحاولة في الثالثة صباحًا مثل واحدة في الظهيرة.

حرّك المنزلقات إلى دفعتك الخاصة:

حاسبة التكلفة

دفعة من 1,000 ملخص تذكرة

رموز الإدخال لكل طلب: 1,500 · رموز الإخراج لكل طلب: 400 · الطلبات يوميًا: 1,000

النموذجيوميًاشهريًا
GLM-5.3-Flash$0.046$1.38
DeepSeek-V4-Flash$0.0625$1.88
MiniMax-M2.7$0.135$4.05

يعرض الجدول تمريرة واحدة. إذا احتاج عُشر الدفعة إلى محاولة ثانية، أضف العُشر. إعادات المحاولة تأمين رخيص عندما تكون الإخفاقات نادرة، وعادة مكلفة عندما تضبط max_retries=10 مقابل نقطة نهاية تستمر في الفشل.

قبل أن تنشر#

قائمة التحقق

المهل وإعادات المحاولة، جاهزة للإنتاج