نقاط رئيسية
- يأتي النص من العميل، لذا أعد إنتاج الطلب باستخدام curl لرؤية جسم الخطأ والحالة الحقيقية.
- HTTP 429 مع رمز rate_limited أو concurrency هو السبب الأكثر شيوعاً في الحسابات المزدحمة، ويحتفظ التدفق بمكانه حتى ينتهي.
- تحقق من عنوان URL الأساسي والمفتاح ومعرف النموذج uncensored وحجم الجسم (8 MB) والرموز الإجمالية (100,000) قبل أي شيء آخر.
- أعد المحاولة فقط مع أخطاء 429 وانقطاعات الشبكة، وانتظر Retry-After، واحتفظ بالطلبات المتزامنة تحت حد المفتاح.
ما تخبرك به الرسالة فعلياً
إذا بحثت عن خطأ غير معروف من تدفق LLM، فأنت على الأرجح تنظر إلى إشعار أو سطر أحمر في واجهة أمامية للدردشة، أو إضافة محرر، أو إطار عمل وكيل. يأتي النص من ذلك العميل. يعني ذلك أن التطبيق طلب إجابة متدفقة، حدث خطأ قبل أو أثناء التدفق، ولم يعرف التطبيق كيفية وصفه. تبلغ الـ API نفسها عن المشاكل بحالة HTTP وجسم خطأ بصيغة JSON، وقد تجاهل العميل تلك التفاصيل.
هذه أخبار جيدة، لأنها تعني أنه يمكنك استعادة التفاصيل. أرسل نفس الطلب خارج العميل، اقرأ سطر الحالة والجسم، وعادة ما يكون السبب واضحاً خلال محاولة أو اثنتين. يتناول بقية هذه الصفحة الأسباب بالترتيب الذي تميل إلى الحدوث به على هذه الـ API، ثم يقدم لك عميلاً متدفقاً صغيراً يطبع الخطأ الحقيقي بدلاً من إخفائه.
شيء واحد يجب وضعه في الاعتبار منذ البداية: الطلب المتدفق لديه نقطتا فشل. يمكن أن يفشل قبل وصول أول بايت، عندما يرفض الخادم الطلب (مفتاح خاطئ، عنوان URL خاطئ، حدّ). أو يمكن أن يفشل في المنتصف، عندما ينقطع الاتصال بعد وصول بعض النصوص بالفعل. تختلف الإصلاحات، لذا لاحظ أي من الحالتين تراه. إذا لم يبدأ الرد أبداً، انظر إلى الأقسام الثاني والثالث والرابع. إذا بدأ ثم توقف، انظر إلى قسم الوكلاء وأوقات الاستجابة.
تحقق من عنوان URL الأساسي والمفتاح والنموذج أولاً
تأتي معظم أخطاء التدفق في إعداد جديد من ثلاثة أخطاء صغيرة. تستغرق دقيقة لاستبعادها.
- عنوان URL الأساسي. يجب أن يكون
https://api.uncensoredllmhub.com/v1، متضمناً/v1ودون وجود/chat/completionsفي النهاية. تضيف العملاء المسار بأنفسهم. إذا ألصقت نقطة النهاية الكاملة في حقل يتوقع عنواناً أساسياً، سيرسل العميل طلباً لمسار غير موجود وسيبلغ عن خطأ غامض. - المفتاح. يكون الرأس
Authorization: Bearer YOUR_KEY. المسافة الزائدة، أو سطر جديد يُنسخ مع المفتاح، أو مفتاح من خدمة أخرى، كلها تؤدي إلى نفس الفشل. أنشئ أو انسخ المفتاح مرة أخرى من صفحة مفتاح API إذا كنت غير متأكد. - معرف النموذج. النموذج الوحيد هو
uncensored. العملاء الذين يقدمون قائمة منسدلة غالباً ما يملأون اسماً من مزود آخر تلقائياً. اكتب المعرف يدوياً، واستدعِGET /v1/modelsإذا أردت تأكيد ما يسرده الخادم.
طريقة سريعة لاختبار الثلاثة معاً هي استدعاء النماذج. لا يستخدم البث المتدفق، لذا يفصل بين مشكلة الاتصال أو المفتاح ومشكلة البث:
curl -i https://api.uncensoredllmhub.com/v1/models -H "Authorization: Bearer $API_KEY"
إذا أعاد قائمة عادية، فالعنوان ومفتاح API صحيحان ويمكنك التوقف عن الشك فيهما. إذا فشل، أصلح ذلك قبل لمس أي شيء يتعلق بالبث المتدفق. تحقق أيضاً من أن حسابك يحتوي على رصيد: ترسل API الرصيد المتبقي في رأس X-Balance-USD في الاستجابات، وهو مفيد عندما يتوقف مفتاح فجأة عن العمل بعد الاستخدام الكثيف. يشرح صفحة التسعير عمليات شحن الرصيد، ويمكن للحسابات الجديدة المطالبة برصيد تجريبي مجاني بقيمة $0.50 من صفحة المفاتيح.
حدّ المعدل والبث الذي يحتفظ بمكانه
السبب الأكثر شيوعاً التالي هو HTTP 429. هناك ثلاثة أنواع، وسيقوم عميلك بدمجها جميعاً في رسالة واحدة غير مفيدة.
| الإشارة | المعنى | الإجراء المطلوب |
|---|---|---|
429، الرمز rate_limited | طلبات كثيرة جداً في الدقيقة للمفتاح | بطئ؛ المفتاح الكامل يسمح بـ 300 في الدقيقة، والمفتاح التجريبي يسمح بـ 60 |
429، الرمز concurrency | طلبات كثيرة تعمل في وقت واحد | ضعها في الطابور؛ يسمح المفتاح الكامل بـ 8 في وقت واحد، والمفتاح التجريبي 2 |
429 مع Retry-After: 5 | إجهاد مؤقت في جانب الخدمة | انتظر 5 ثوانٍ، ثم أعد المحاولة |
حدّ التوازي هو ما يفاجئ الناس، بسبب طريقة عمل البث. يشغل الطلب المتدفق مقعده حتى ينتهي البث، وليس حتى وصول الرمز الأول. إذا فتح تطبيقك تدفقاً لكل رسالة ولم يغلق القديم أبداً، على سبيل المثال لأن المستخدم انتقل إلى مكان آخر ونسيت واجهة المستخدم إلغاء الطلب، تظل هذه المقاعد مشغولة. في المفتاح التجريبي ذي الحد 2، يكفي تدفقان مهملان لجعل الرسالة الثالثة تفشل.
الأعراض متسقة. تعمل الرسائل القليلة الأولى، ثم تبدأ الأخطاء، ثم يعود كل شيء للعمل مرة أخرى بعد انتظار قصير. إذا كان هذا مطابقاً، أوقف تدفقاتك التي لم تعد بحاجة إليها (استخدم AbortController في المتصفح، أو أغلق الاستجابة في الخادم)، وحدد عدد المكالمات المتزامنة في كودك الخاص. الوكلاء هم المعتادون على التسبب في المشكلة: المخطط الذي يطلق عشر استدعاءات دوال في وقت واحد سيضرب الحد فوراً في المفتاح التجريبي.
تساعدك رؤوس الاستجابة في معرفة وضعك. يُظهر X-RateLimit-Limit-Requests و X-RateLimit-Limit-Concurrency الحدود التي تنطبق على المفتاح الذي استخدمته، و X-Request-Id يحدد المكالمة إذا احتجت إلى طلب الدعم بشأنها.
حجم الطلب وطول نافذة السياق
يمكن أيضاً رفض الطلب لأنه كبير جداً. رقمان مهمان. يمكن أن يكون حجم الجسم 8 MB كحد أقصى، ويجب أن يتسع النص الأولي والإكمال في نافذة سياق بحجم 100,000 رمز. واجهات الدردشة التي تعيد إرسال المحادثة الكاملة في كل خطوة تصل إلى هذه الحدود ببطء ثم فجأة: تعمل الدردشة لمدة ساعة، ثم رسالة طويلة واحدة أو ملف ملصق يتجاوز الحد، وتفشل كل الخطوات اللاحقة لأن السجل لا يزال في الطلب.
إذا بدأ الخطأ بعد جلسة طويلة، اختبر بمحادثة جديدة قصيرة. إذا نجحت، فإن السجل هو السبب. قلصه بإسقاط الخطوات القديمة، أو تلخيصها في رسالة واحدة، أو بدء دردشة جديدة. المستندات الكبيرة الملصقة هي المؤثر الآخر. ملف نصي بحجم بضعة مئات من الكيلوبايت أمر جيد، لكن كتل base64 أو السجلات الكبيرة جداً يمكن أن تصل إلى 8 MB بشكل أسرع مما تتوقع.
لا يتعين عليك تعيين max_tokens، حيث يمكن للإكمال استخدام ما تبقى من نافذة السياق. إذا قمت بتعيينه، تأكد من أن رموز الموجّه زائد max_tokens تبقى أقل من 100,000. العميل الذي يحدد قيمة كبيرة لـ max_tokens بشكل ثابت فوق سجل طويل يمكن أن يدفع المجموع فوق نافذة السياق حتى عندما يبدو الموجّه وحده جيداً.
الوكلاء، التخزين المؤقت وفترات انتهاء الصلاحية
يستخدم البث أحداثاً مرسلة من الخادم: استجابة HTTP طويلة الأمد تسلم أجزاء صغيرة بمجرد إنتاجها. أي شيء بينك وبين API ينتظر الاستجابة الكاملة قبل إعادة توجيهها سيكسر ذلك. النتيجة هي إما صمت طويل يتبعه انفجار، أو انتهاء المهلة والخطأ العام.
ابحث عن هذه في إعدادك الخاص:
- الوكلاء العكسيون. إذا كنت توجه API عبر nginx أو وكيل مشابه، عطّل تخزين الاستجابة لذلك الموقع، وارفع وقت القراءة فوق أطول إجابة تتوقعها. الإجابات الطويلة من نافذة 100,000 رمز قد تستغرق وقتاً.
- وكلاء الشركات أو برامج مكافحة الفيروسات. بعض البرامج تفحص حركة HTTPS وتحتفظ بالجسم. اختبر من نقطة اتصال هاتفية لاستبعاد هذا الاحتمال.
- الدوال السحابية. تحدد العديد من المنصات وقت التنفيذ أو تخزن الاستجابات ما لم تختار البث المتدفق. إذا مات التدفق في نفس عدد الثواني كل مرة، فإن حد وقت المنصة هو السبب المحتمل.
- إضافات المتصفح وشبكات VPN. نادرة، لكنها يمكن أن تقطع الاتصالات الخاملة.
العلامة التي تشير إلى هنا هي وجود خطأ في منتصف الإجابة، مع نفس وقت القطع في كل محاولة. سيُرفض الطلب في البداية بسبب حدّ المعدل، لذا فإن قطع في منتصف التدفق يحدث دائماً، على سبيل المثال، في 30 ثانية هو نادراً ما يكون حداً.
عميل يظهر الخطأ الحقيقي
استخدم هذا عندما تريد الحصول على الحقيقة بدلاً من الرسالة الودية. يلتقط استثناءات OpenAI SDK، ويعرض الحالة وجسم الخطأ، ويقرأ تلميح إعادة المحاولة عند وجوده.
import time
from openai import OpenAI, APIConnectionError, APIStatusError, RateLimitError
client = OpenAI(
base_url="https://api.uncensoredllmhub.com/v1",
api_key="YOUR_API_KEY",
)
def stream_once(messages):
stream = client.chat.completions.create(
model="uncensored",
messages=messages,
stream=True,
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
if getattr(chunk, "usage", None):
print("\n[usage]", chunk.usage)
messages = [{"role": "user", "content": "Write two sentences about harbours."}]
for attempt in range(4):
try:
stream_once(messages)
break
except RateLimitError as e:
wait = int(e.response.headers.get("retry-after", 5))
print("429:", e.body, "- waiting", wait, "s")
time.sleep(wait)
except APIStatusError as e:
print("status", e.status_code, e.body)
print("request id:", e.response.headers.get("x-request-id"))
break
except APIConnectionError as e:
print("connection problem:", e)
time.sleep(2)
نفس الفكرة في Node، مع إشارة إلغاء (abort signal) بحيث تطلق التدفقات المهجورة شغلتها:
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.uncensoredllmhub.com/v1",
apiKey: process.env.API_KEY,
});
const controller = new AbortController();
try {
const stream = await client.chat.completions.create(
{
model: "uncensored",
messages: [{ role: "user", content: "Write two sentences about harbours." }],
stream: true,
},
{ signal: controller.signal }
);
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}
} catch (err) {
console.error("status:", err.status, "body:", err.error);
}
// call controller.abort() when the user leaves the page
وأيضاً استدعاء curl الخام، الذي يزيل كل عميل من الصورة. يُعطّل -N التخزين المؤقت الخاص بـ curl و -i يطبع سطر الحالة والرؤوس، بما في ذلك X-Request-Id:
curl -N -i https://api.uncensoredllmhub.com/v1/chat/completions -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" -d '{"model":"uncensored","stream":true,"messages":[{"role":"user","content":"Say hello."}]}'
إذا كانت curl تدفق النص بشكل جيد وتطبيقك لا، فإن API سليم والمشكلة تكمن في التطبيق، وكيله أو إعداداته. إذا أظهرت curl خطأ 429 أو حالة أخرى، لديك الآن السبب الدقيق.
قواعد إعادة المحاولة التي لا تجعل الأمور أسوأ
تساعد إعادة المحاولة مع المشاكل المؤقتة وتضر مع الدائمة. سياسة قصيرة تبعدك عن المشاكل.
- أعد المحاولة في حالة 429 والاتصالات المنقطعة. انتظر
Retry-Afterعند وجوده، وإلا فانتظر لبضع ثوانٍ وأضف بعض العشوائية (jitter) حتى لا يقوم العمال المتوازيون بإعادة المحاولة في تزامن. - لا تعيد محاولة أخطاء المصادقة أو الطلبات الكبيرة جداً. لن تتغير النتيجة، وتضيف كل محاولة إعادة فقط ضوضاء.
- حدّ المحاولات إلى ثلاث أو أربع، ثم اعرض نص الخطأ الحقيقي للمستخدم.
- حدّ التوازي الخاص بك تحت حد المفتاح. سمافور (semaphore) بقيمة 6 على مفتاح كامل يترك مساحة لأداة ثانية تستخدم نفس المفتاح.
- إذا انقطع التدفق في المنتصف، احتفظ بالنص الجزئي. أعد إرساله مع ذلك النص كرسالة مساعد واطلب من النموذج الاستمرار، بدلاً من إعادة التوليد من البداية.
الطلبات الفاشلة أو المرفوضة لا تُحسب، لذا فإن التصحيح باستخدام مكالمات اختبار متكررة لا يستنزف رصيدك. تُحسب المكالمات الناجحة بسعر $0.15 لكل مليون رمز إدخال و $0.50 لكل مليون رمز إخراج، والتدفق الجزئي الذي يكمل بشكل طبيعي هو ببساطة إجابة قصيرة. مزيد من التفاصيل حول تنسيق الطلب في وثائق API.
إذا قمت بجميع الخطوات أعلاه ولا تزال ترى الرسالة، أرسل X-Request-Id الخاص بالطلب الفاشل إلى صفحة الدعم، مع وقت المحاولة وما إذا كان الفشل قد حدث قبل أو بعد ظهور الرمز الأول. هذه المعلومات كافية لتتبع ما حدث.
