بناء روبوت محادثة من واجهة برمجة تطبيقات LLM: دليل Python
نماذج Abliterated هي نماذج لغوية كبيرة تم إزالة الآليات التي تفرض رفض السلامة منها، مما يسمح للنموذج بالإجابة على الأسئلة المثيرة للجدل أو المتعلقة بالبالغين أو المتخصصة دون مواجهة فلتر محتوى. يمنح هذا النهج المطورين تحكمًا كاملًا في نبرة النموذج وحدود معرفته، وهو أمر قيّم بشكل خاص في البرمجة، ولعب الأدوار، والكتابة الإبداعية حيث قد تمنع الحواجز القياسية المخرجات المفيدة.
محدّث

نقاط رئيسية
- واجهة API عديمة الحالة، لذا يتولى الكود الخاص بك إدارة سجل المحادثة وإرساله في كل طلب.
- يستخدم البث المتدفق، واستدعاء الدوال، ووضع JSON جميع المعايير القياسية الخاصة بـ OpenAI.
- قم بتقليم أو تلخيص سجل الرسائل قبل الاقتراب من نافذة 100,000 رمز (token).
- تكلفة 1,000 محادثة بـ 2,000 رمز إدخال و400 رمز إخراج تبلغ حوالي $0.50.
الفكرة الأساسية: روبوت الدردشة عبارة عن حلقة وقائمة
نموذج اللغة لا يتذكر شيئاً بين الطلبات. كل استدعاء لـ POST /v1/chat/completions مستقل. ما يبدو كذاكرة هو برنامجك الذي يعيد إرسال الرسائل السابقة، كل منها مُعلّم بدور: system للتعليمات الثابتة، user لما كتبه الشخص، assistant لردود النموذج السابقة.
لذا فإن بنية النظام بأكملها صغيرة. احتفظ بقائمة. أضف رسالة المستخدم. أرسل القائمة. أضف الرد. كرر. كل شيء آخر في هذا الدليل، من البث المتدفق إلى الأدوات، هو تكرار لهذه الحلقة.
الواجهة هنا متوافقة مع OpenAI، لذا استخدم حزمة openai العادية. اضبط عنوان URL الأساسي على https://api.abliterated.cc/v1، استخدم مفتاحك، واضبط النموذج على uncensored. احصل على مفتاح من صفحة مفتاح API؛ رصيد التجربة المجاني بقيمة $0.50 كافٍ لمئات الرسائل القصيرة التجريبية.
الخطوة 1: روبوت دردشة يعمل في وحدة التحكم
ثبّت SDK باستخدام pip install openai وشغّل هذا.
from openai import OpenAI
client = OpenAI(
base_url="https://api.abliterated.cc/v1",
api_key="YOUR_KEY",
)
messages = [
{"role": "system", "content": "You are a concise, friendly support assistant for a bike shop."}
]
while True:
text = input("you: ")
if text.strip() in {"quit", "exit"}:
break
messages.append({"role": "user", "content": text})
resp = client.chat.completions.create(
model="uncensored",
messages=messages,
temperature=0.7,
)
answer = resp.choices[0].message.content
messages.append({"role": "assistant", "content": answer})
print("bot:", answer)
هذا روبوت دردشة كامل. رسالة النظام تحدد مهمته، والقائمة تحمل الذاكرة، وtemperature تتحكم في مدى تنوع الردود. خفّضها نحو 0.2 لروبوتات الدعم الواقعية، وارفعها نحو 1.0 للروبوتات الإبداعية.
اكتب موجّه النظام الذي يحدد الوظيفة
رسالة النظام هي أرخص مكان لتحسين روبوت دردشة. اجعلها قصيرة ومحددة. حدد الدور، الجمهور، طول ونبرة الردود، وما يجب فعله عندما لا يعرف الروبوت الإجابة. موجّه مثل "أجب على أسئلة متجر دراجات. رد بحد أقصى ثلاث جمل. إذا كان السؤال عن سعر إصلاح، قل إن ميكانيكياً يجب أن يفحص الدراجة" يفعل أكثر من صفحة من الصفات العامة.
عادتان تؤتيان ثمارهما. أولاً، ضع القواعد في شكل إجراءات، وليس مواقف: "اطرح سؤالاً توضيحياً واحداً عندما يكون الطلب غامضاً" بدلاً من "كن مفيداً". ثانياً، اختبر مع مدخلات عدوانية، مثل رسالة فارغة، ولصق طويل جداً، وطلب لا علاقة له بمنتجك. صحح الموجّه بناءً على ما تراه، ثم احتفظ بتلك المدخلات كقائمة اختبارات.
نظراً لأن رسالة النظام تُعاد إرسالها في كل دور، يتم احتساب كل كلمة فيها في كل طلب. إضافة موجّه بـ 400 رمز (token) عبر 1,000 دردشة بـ 5 أدوار لكل منها تضيف 2,000,000 رمز إدخال، أو 2 x $0.15 = $0.30. هذا مبلغ صغير، لكنه يوضح لماذا تتراكم الموجّهات المطوّلة عند الحجم الكبير.
الخطوة 2: بث الرد
الانتظار لرد كامل يبدو بطيئاً في نافذة الدردشة. اضبط stream: true واطبع الأجزاء عند وصولها. يستخدم البث أحداثاً تُرسل من الخادم وينتهي بكتلة استخدام، لذا يمكنك تسجيل عدد الرموز.
from openai import OpenAI
client = OpenAI(base_url="https://api.abliterated.cc/v1", api_key="YOUR_KEY")
messages = [{"role": "user", "content": "Explain tire pressure in two sentences."}]
stream = client.chat.completions.create(
model="uncensored",
messages=messages,
stream=True,
)
reply = ""
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
part = chunk.choices[0].delta.content
reply += part
print(part, end="", flush=True)
if getattr(chunk, "usage", None):
print("\ntokens:", chunk.usage.prompt_tokens, chunk.usage.completion_tokens)
تذكر أن تضيف الرد المُجمّع reply في سجلك، أو أن الدور التالي لن يعرف ما قاله الروبوت.
الخطوة 3: إدارة السياق قبل أن يتوسع
النافذة هي 100,000 رمز (token)، مشتركة بين الموجّه والاستجابة. معظم روبوتات الدردشة لا تقترب منها أبداً، لكن التكلفة تنمو مع السجل لأنك تدفع مقابل كامل الموجّه في كل دور. سياسة بسيطة تبقي الاثنين تحت السيطرة:
- احتفظ دائماً برسالة النظام.
- احتفظ بآخر 10 إلى 20 رسالة كما هي.
- عندما تتجاوز القائمة حداً للحجم تختاره، مثل 8,000 رمز (token) مُقدّر، أرسل الكتلة الأقدم إلى النموذج مع التعليمات "لخص هذه المحادثة في أقل من 150 كلمة"، واستبدل تلك الكتلة بالملخص كرسالة نظام.
تقدير تقريبي لرمز (token) واحد لكل أربعة أحرف إنجليزية كافٍ للتشغيل. أرقام الاستخدام في كل استجابة تعطيك الرقم الدقيق بعد الحدث، لذا يمكنك معايرة الحد.
إذا قمت بالتقطيع بإزالة الرسائل الأقدم، أزلها في أزواج من المستخدم والمساعد. رد بدون سؤال، أو سؤال بدون رد، يربك النموذج أكثر مما تتوقع.
الخطوة 4: تزويد البوت بالأدوات
يتيح استدعاء الدوال للنموذج أن يطلب من كودك القيام بشيء ما، مثل البحث عن طلب. تصف الدوال باستخدام tools، يرد النموذج بمدخل tool_calls، تشغل الدالة، وترسل النتيجة مرة أخرى كرسالة role: "tool".
import json
from openai import OpenAI
client = OpenAI(base_url="https://api.abliterated.cc/v1", api_key="YOUR_KEY")
tools = [{
"type": "function",
"function": {
"name": "get_order_status",
"description": "Look up the status of an order by its id",
"parameters": {
"type": "object",
"properties": {"order_id": {"type": "string"}},
"required": ["order_id"],
},
},
}]
def get_order_status(order_id):
return {"order_id": order_id, "status": "shipped"}
messages = [{"role": "user", "content": "Where is order A1042?"}]
resp = client.chat.completions.create(
model="uncensored", messages=messages, tools=tools, tool_choice="auto"
)
msg = resp.choices[0].message
if msg.tool_calls:
messages.append(msg)
for call in msg.tool_calls:
args = json.loads(call.function.arguments)
result = get_order_status(**args)
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": json.dumps(result),
})
final = client.chat.completions.create(
model="uncensored", messages=messages, tools=tools
)
print(final.choices[0].message.content)
افحص دائماً الحجج قبل تنفيذ أي إجراء له آثار جانبية. يقترح النموذج استدعاءً؛ وكودك هو من يقرر ما إذا كان يجب تنفيذه.
الخطوة 5: مخرجات مُهيكلة باستخدام وضع JSON
عندما تتطلب الخطوة التالية في برنامجك بيانات بدلاً من نص سردي، مثل تصنيف رسالة في فئة، استخدم وضع JSON مع response_format. اذكر كلمة JSON والمفاتيح المتوقعة في الموجّه الخاص بك أيضاً.
curl https://api.abliterated.cc/v1/chat/completions \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "uncensored",
"response_format": {"type": "json_object"},
"messages": [
{"role": "system", "content": "Reply with JSON: {\"intent\": string, \"urgent\": boolean}"},
{"role": "user", "content": "My brakes squeal and I ride tomorrow morning."}
]
}'
لا تزال بحاجة إلى وضع json.loads داخل كتلة try. إذا فشل التحليل، أعد المحاولة مرة واحدة مع إرفاق نص الخطأ؛ الطلبات الفاشلة لا تُحسب.
ملاحظات حول الأخطاء والتكلفة والنشر
التعامل مع الأخطاء وإعادة المحاولة وحدود المعدل
يرسل المستخدمون الحقيقيون الطلبات في أوقات غير متوقعة، وقد تفشل الشبكات. غلّف الاستدعاء بمعالجة للأخطاء بحيث لا يؤدي ردّ سيء واحد إلى تعطل المحادثة.
import time
from openai import OpenAI, APIError, RateLimitError
client = OpenAI(base_url="https://api.abliterated.cc/v1", api_key="YOUR_KEY")
def chat(messages, tries=3):
for attempt in range(tries):
try:
resp = client.chat.completions.create(
model="uncensored", messages=messages, temperature=0.7
)
return resp.choices[0].message.content
except RateLimitError:
time.sleep(2 ** attempt)
except APIError as exc:
if attempt == tries - 1:
raise
time.sleep(1)
return "Sorry, the assistant is busy. Please try again in a moment."
المفتاح الكامل يسمح بـ 8 طلبات متزامنة و300 طلب في الدقيقة؛ يسمح مفتاح التجربة بـ 2 و60. إذا كان روبوتك يخدم العديد من المستخدمين في وقت واحد، ضع الطلبات في قائمة انتظار بحدّ عامل أقل من 8 بدلاً من الاعتماد على إعادة المحاولة. لأن الطلبات الفاشلة لا تُحسب، فإن إعادة المحاولة لا تكلف رموزاً. حافظ على عدد إعادة المحاولة صغيراً حتى يفشل العطل الحقيقي بسرعة.
قم أيضًا بتسجيل رأس X-Request-Id مع كل خطوة في المحادثة. عندما يبدو الرد غير صحيح، يتيح لك المعرف العثور على الطلب المحدد لاحقًا.
التكلفة والنشر
السعر هو $0.15 لكل مليون رمز إدخال و$0.50 لكل مليون رمز مخرجات. لنفترض أن روبوت الدعم استخدم 2,000 رمز إدخال في المجموع و400 رمز مخرجات.
- مدخل: 0.002M × $0.15 = $0.0003
- مخرج: 0.0004M × $0.50 = $0.0002
- دردشة واحدة: $0.0005، لذا فإن 1,000 دردشة تكلف $0.50
تحقق من الأسعار الحالية ومكافآت الشحن على صفحة الأسعار. للإنتاج، احتفظ بالمفتاح على خادمك، وليس في كود المتصفح، وراقب رأس الاستجابة X-Balance-USD لتنبيه نفسك قبل نفاد الرصيد. يسمح المفتاح الكامل بـ 8 طلبات متزامنة و300 طلب في الدقيقة، لذا ضع الطلبات المفاجئة في قائمة انتظار بدلاً من إطلاقها جميعاً في وقت واحد. توضح التوثيق كل معلمة مدعومة.
المزيد من الأدلة
أسئلة وأجوبة
هل أحتاج إلى إطار عمل لبناء روبوت دردشة؟
لا. يكفي OpenAI SDK وقائمة الرسائل لروبوت يعمل. أضف إطار عمل لاحقاً فقط إذا كنت بحاجة إلى ميزات إضافية.
هل يتذكر API الرسائل السابقة؟
لا. كل طلب مستقل، لذا يجب على كودك إعادة إرسال السجل في كل مرة.
كيف أمنع السجل من أن يصبح طويلاً جداً؟
احتفظ برسالة النظام والأدوار الأخيرة، ولخّص الأقدم في ملاحظة قصيرة بمجرد أن تتجاوز القائمة حداً معيناً من الحجم.
هل يمكن للروبوت استدعاء دوال خاصة بي؟
نعم. مرّر الأدوات وtool_choice، وشغّل الدالة عندما يحتوي الرد على tool_calls، ثم أعد النتيجة كرسالة أداة.
مفتاحك على بُعد خطوة واحدة
أنشئ حساباً، وانسخ المفتاح، ثم غيّر URL الأساسي. هذه هي الإعدادات الكاملة.