تُعدّ unbleep واجهة API متوافقة مع OpenAI، وهو ما يعني عمليًا أن الترحيل سطران اثنان دون أي اعتمادية جديدة. تحتفظ بالـ SDK الرسمي، ومنطق إعادة المحاولة لديك، وحلقة البث، ومحاسبة التوكنات، ومعالجات الأخطاء. ما يتغير هو الوجهة التي تذهب إليها الطلبات والمفتاح الذي يصادق عليها. يغطي هذا المقال عملية الاستبدال، ثم الأمور الأربعة التي تختلف بما يكفي لتعطيل شيء ما إن لم تكن على علم بها.
الترحيل إلى واجهة API المتوافقة مع OpenAI في سطرين
import os
from openai import OpenAI
client = OpenAI(
base_url="https://unbleep.ai/v1",
api_key=os.environ["UNBLEEP_API_KEY"],
)
resp = client.chat.completions.create(
model="unbleep",
messages=[{"role": "user", "content": "Summarise this incident report."}],
)
print(resp.choices[0].message.content)وإن كنت تفضّل عدم لمس الكود إطلاقًا، فالـ SDK يقرأ القيمتين من متغيرات البيئة، لذا يكفي تغيير في الإعدادات:
export OPENAI_BASE_URL="https://unbleep.ai/v1"
export OPENAI_API_KEY="ub_live_9f2c..."هذا الزوج نفسه يغطي معظم المنظومة المبنية فوق الـ SDK — LangChain وLlamaIndex وInstructor وVercel AI SDK، وأي شيء يتيح إعداد base URL. المفاتيح تحمل بادئة كي تكون التسريبات واضحة لأدوات فحص الأسرار: ub_live_ وub_test_ يُحاسَبان كلاهما من الرصيد المدفوع مسبقًا نفسه وبسعر التوكن نفسه. مفتاح الاختبار بيانات اعتماد منفصلة قابلة للإلغاء بسقف أدنى — 15 طلبًا في الدقيقة بدلًا من 60 للحساب — وليس فئة مجانية. أبقِ كليهما على جانب الخادم.
المسار GET /v1/models يعمل، لذا لا تحتاج الأدوات التي تعدّد النماذج لملء قائمة منسدلة إلى معالجة خاصة.
اختيار النموذج
ثلاث فئات. المعرّفات المؤرّخة — unbleep-250811 وunbleep-high-250811 وunbleep-mini-250811 — مقبولة كأسماء بديلة، لكنها اليوم تشير إلى البنية نفسها التي يشير إليها المعرّف المجرد، والاستجابة تعيد المعرّف المجرد. تعامل معها بوصفها تهجئة متوافقة مع المستقبل لا ضمانًا لقابلية التكرار؛ فإن كان لا بد من إمكانية تكرار تقييم ما، فسجّل المخرجات لا معرّف النموذج.
| النموذج | السياق | السعر إدخال / إخراج لكل مليون | ملاحظات | | --- | --- | --- | --- | | unbleep | 256K | $3.00 / $3.00 | الافتراضي. فئة تفكير. | | unbleep-high | 1M* | $5.00 / $5.00 | أكبر المهام. فئة تفكير. | | unbleep-mini | 32K | $1.00 / $1.00 | رخيص وسريع. يجيب مباشرة دون أثر تفكير. |
*جسم الطلب محدود بسقف 2,000,000 بايت — قرابة 500k توكن — لذا لا يمكن لاستدعاء واحد أن يملأ فعليًا نافذة المليون؛ وأي شيء أكبر يعود بالرمز 413 payload_too_large.
سقف 32K في unbleep-mini هو ما يوقع بمن يرحّلون من نموذج بسياق 128K: الموجّه الذي كان يتّسع سابقًا سيُرفض الآن. إن كنت توجّه الطلبات بحسب التكلفة، فوجّهها بحسب الطول أيضًا.
def pick_model(prompt_chars: int) -> str:
"""~4 chars/token is a deliberate under-estimate; leave room for the completion."""
est_tokens = prompt_chars // 4
if est_tokens < 24_000:
return "unbleep-mini"
return "unbleep" if est_tokens < 200_000 else "unbleep-high"البث (streaming)
اضبط stream=True وستحصل على أحداث Server-Sent Events قياسية: كل حدث هو chat.completion.chunk يحمل delta، وينتهي البث بالنص الحرفي data: [DONE]. حلقتك الحالية تعمل دون تغيير.
curl -N https://unbleep.ai/v1/chat/completions \
-H "Authorization: Bearer $UNBLEEP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "unbleep",
"messages": [{"role": "user", "content": "Explain the residual stream."}],
"stream": true,
"stream_options": {"include_usage": true}
}'تحصل على أعداد التوكنات سواء طلبتها أم لا: تطلب unbleep دائمًا بيانات الاستخدام من الخلفية وتمرّرها، ولا يحذفها في طريق الخروج سوى تحديد صريح لـ stream_options: {"include_usage": false}. وفي الحالتين ينتهي البث بقطعة أخيرة واحدة تحمل مصفوفة choices فارغة — ومعها كائن usage المعبّأ ما لم تكن قد اخترت عدم استلامه — ولهذا تتحقق الحلقة أدناه من choices قبل أن تلمسها.
حقل reasoning_content
هذه هي الإضافة الحقيقية الوحيدة إلى المخطط. النموذجان unbleep وunbleep-high يفكران قبل الإجابة، وتُعاد سلسلة التفكير تلك في reasoning_content، وهو حقل شقيق لـ content في الرسالة (بدون بث) أو في الـ delta (مع البث). تختلف الخلفيات الأصلية في تسميته reasoning أو reasoning_content؛ وتوحّده الـ API إلى reasoning_content كي لا تتعامل إلا مع شكل واحد.
ولأنه ليس جزءًا من مخطط OpenAI، فهو غير موجود في ملفات تعريف الأنواع (type stubs) الخاصة بالـ SDK. نماذج الاستجابة تسمح بحقول إضافية، لذا يعمل الوصول إلى الخاصية في وقت التشغيل — لكن اقرأه بـ getattr كي لا تُطلق استجابة mini، التي لا تحمل أثرًا، أي استثناء:
import sys
stream = client.chat.completions.create(
model="unbleep",
messages=[{"role": "user", "content": "Why did this detection rule misfire?"}],
stream=True,
stream_options={"include_usage": True},
)
usage = None
for chunk in stream:
if not chunk.choices: # final usage-only chunk
usage = chunk.usage
continue
delta = chunk.choices[0].delta
thought = getattr(delta, "reasoning_content", None)
if thought: # trace to stderr, answer to stdout
sys.stderr.write(thought)
if delta.content:
sys.stdout.write(delta.content)
if usage:
details = usage.completion_tokens_details
print(f"\nreasoning tokens: {getattr(details, 'reasoning_tokens', 0)}")ثلاث نتائج عملية:
- توكنات التفكير هي توكنات إخراج. تظهر في
completion_tokensوتُحاسَب بسعر الإخراج. ويخبركusage.completion_tokens_details.reasoning_tokensبمقدار ما ذهب من الفاتورة إلى التفكير. - وهي تستهلك
max_tokensأيضًا. حد ضيق على فئة تفكير قد يُستنفد بالكامل في الأثر، فيتركك بإجابة مبتورة أوcontentفارغ. خصّص ميزانية للاثنين معًا، أو أوقف التفكير. - أوقفه حين لا تحتاج إليه. أرسل
"thinking": falseعبرextra_bodyللاستدعاءات القصيرة أو عالية الحجم. ويمرَّرreasoning_effortكذلك.
resp = client.chat.completions.create(
model="unbleep",
messages=[{"role": "user", "content": "phishing or benign?"}],
max_tokens=4,
extra_body={"thinking": False}, # spend the budget on the answer, not the trace
)لا تُعِد أبدًا تغذية reasoning_content في دور لاحق بوصفه محتوى للمساعد. فهو مخرجات تشخيصية لا سجل محادثة، وإعادة تشغيله تُضعف الاستجابة التالية.
الأخطاء والمزلقان الحقيقيان
تستخدم الأخطاء غلاف OpenAI — {"error": {"type", "code", "message"}} — لذا تستمر كتل except الحالية لديك في العمل. رموز الحالة تُطابق ما تتوقعه: 401 مفتاح غير صالح، و422 محظور بواسطة policy: strict، و429 حد المعدل، و5xx خطأ في الخلفية يمكن إعادة المحاولة بعده.
أما رمز الحالة الذي لم تتعامل معه على الأرجح من قبل فهو 402، نفاد الرصيد. الحسابات مدفوعة مسبقًا، فلا تجاوز للحد ولا فاتورة — تتوقف الطلبات ببساطة حتى تعيد الشحن. تشير OpenAI إلى نفاد الحصة بالرمز 429، ما يعني أن مسار الترحيل الساذج سيجعل منطق التراجع (backoff) لديك يعيد محاولة الـ 402 إلى الأبد. تعامل معه بوصفه خطأ نهائيًا وأطلق تنبيهًا عنده.
المزلق الثاني: لا يُعاد system_fingerprint. فهو يحدد هوية خلفية التقديم، لذا يُحذف مع بقية الحقول الخاصة بالمزوّد. إن كنت تبني مفتاح ذاكرة تخزين مؤقت أو فحص قابلية تكرار عليه، فستحتاج إلى علامة إصدار خاصة بك: معرّفات النماذج المؤرّخة أسماء بديلة للبنية الحالية لا لقطات مجمّدة، لذا لن تخبرك متى تتغير الخلفية.
تعود حدود المعدل في ترويسات كل استجابة — x-ratelimit-limit-requests وx-ratelimit-remaining-requests وx-ratelimit-reset-requests — كي تتمكن مهمة دفعية من ضبط وتيرة طلباتها بدلًا من اكتشاف ذلك السقف بالاصطدام به. وهناك سقف ثانٍ لا تصفه الترويسات: 8 طلبات كحد أقصى قيد التنفيذ في الوقت نفسه لكل حساب، والطلب التاسع يعود بالرمز 429 مع الكود too_many_concurrent_requests. استدعاء البث يحتفظ بمكانه حتى ينتهي البث، لذا حدّد مجمّع العمّال (worker pool) لديك بـ 8.
ما الذي توجّه عميلك إليه
يجدر التصريح بذلك: النماذج خلف نقطة النهاية هذه هي نماذج abliterated، أي أن سلوك الرفض فيها أُزيل على مستوى الأوزان. وهذا هو المقصود — فهي واجهة API للمطورين موجّهة للبحث الأمني والفريق الأحمر (red-teaming) والتقييم، حيث يكون الرفض خطأ قياس. ويعني ذلك أيضًا أن حواجز الحماية المعتادة ليست موجودة لالتقاط موجّه سيئ، لذا أبقِ إنسانًا مسؤولًا عن المخرجات واقرأ سياسة الاستخدام المقبول. الاستخدام القانوني مسؤوليتك.
احصل على مفتاح API — الترحيل سطران اثنان بحق.