حين تريد إدخال الذكاء الاصطناعي في موقعك أو تطبيقك، فلن تتعامل بعد الآن مع صفحة دردشة؛ بل مع واجهة API. الخبر الجيد أن الاتصال نفسه بسيط. والخبر السيئ أن معظم الشروحات تنتهي عنده ولا تتطرق إلى ما يسبب المتاعب فعلًا.
كُتبت أمثلة هذا المقال بالصيغة الشائعة التي قدّمتها OpenAI وتتوافق معها خدمات أخرى كثيرة. أما الخدمات ذات الصيغة المختلفة فيختلف فيها العنوان وأسماء الحقول، وبقية النصائح واحدة.
قبل الكود: تحتاج إلى ثلاثة أشياء#
- مفتاح API من لوحة تحكم الخدمة نفسها.
- رصيد في الحساب. واجهة API منفصلة عن اشتراك صفحة الدردشة وتُحاسَب على حدة.
- خادم يستطيع الاتصال بتلك الخدمة.
اختبر الأمر الثالث قبل كل شيء. فبعض الخدمات تقيّد الوصول بحسب البلد، وقد لا يتمكن بعض الخوادم من الاتصال بها. نفّذ هذا الأمر في طرفية الاستضافة:
curl -sS -m 10 -o /dev/null -w "%{http_code}\n" https://api.openai.com/v1/modelsإذا عاد 401 فالاتصال قائم (أنت فقط لم تُرسل المفتاح). وإذا ظهر خطأ اتصال أو انتهت المهلة فالمشكلة في شبكة الخادم ولا يحلها أي كود.
أين نحفظ المفتاح#
| المكان | الحكم |
|---|---|
ملف .env خارج جذر الويب | جيد |
ثابت في wp-config.php | جيد |
| داخل كود PHP موجود في جيت | سيئ |
| داخل جافاسكريبت الصفحة | سيئ جدًا: كل زائر يراه |
القاعدة البسيطة: يجب ألّا يرى المتصفح المفتاح أبدًا. المتصفح يرسل طلبًا إلى خادمك، وخادمك يرسله إلى API.
المثال الكامل#
<?php
function ai_ask(string $question, string $apiKey): array
{
$payload = [
'model' => 'MODEL_NAME',
'messages' => [
['role' => 'system', 'content' => 'Answer in Arabic. Be concise.'],
['role' => 'user', 'content' => $question],
],
'max_tokens' => 500,
];
$ch = curl_init('https://api.openai.com/v1/chat/completions');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => 60,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Authorization: Bearer ' . $apiKey,
],
CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE),
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($body === false) {
return ['ok' => false, 'status' => 0, 'error' => $error];
}
$data = json_decode($body, true);
if ($status !== 200) {
return [
'ok' => false,
'status' => $status,
'error' => $data['error']['message'] ?? 'unknown error',
];
}
return [
'ok' => true,
'text' => $data['choices'][0]['message']['content'] ?? '',
'tokens_in' => $data['usage']['prompt_tokens'] ?? 0,
'tokens_out' => $data['usage']['completion_tokens'] ?? 0,
];
}ضع بدل MODEL_NAME اسم النموذج الذي تريده. أسماء النماذج تتغير باستمرار؛ فخذ القائمة الحالية من وثائق الخدمة نفسها.
أربعة أشياء في هذا الكود مقصودة:
max_tokensهو سقف طول الإجابة. بدونه قد تتسبب إجابة طويلة في تكلفة غير متوقعة.CURLOPT_TIMEOUTستون ثانية. إجابة الذكاء الاصطناعي بطيئة، والمهلة الافتراضية القصيرة تقطعها في المنتصف.JSON_UNESCAPED_UNICODEيُبقي النص العربي مقروءًا ويجعل الطلب أصغر.- نُرجع
usageحتى يمكن تسجيل الاستهلاك.
اضبط التكلفة#
التكلفة بحسب الرموز، منفصلةً للمدخلات والمخرجات. شرحنا ما هو الرمز ولماذا تستهلك العربية أكثر في الرموز والنافذة السياقية والهلوسة.
خمسة أعمال تمنع فاتورة مفاجئة:
- اضبط سقف الإنفاق الشهري في لوحة تحكم الخدمة. هذا أول عمل، قبل كتابة سطر كود واحد.
- ضع
max_tokensدائمًا. - سجّل استهلاك كل طلب. اكتب
tokens_inوtokens_outفي قاعدة البيانات أو في السجل. - خزّن النتيجة مؤقتًا (Cache). إذا طُرح السؤال نفسه مرة أخرى فلا تدفع مرة ثانية.
- ضع سقفًا لكل مستخدم. نموذج عام بلا قيود دعوة مفتوحة لإساءة الاستخدام.
الأخطاء الشائعة#
| الرمز | المعنى | ماذا نفعل |
|---|---|---|
401 | مفتاح خاطئ أو ملغى | افحص المفتاح؛ وتأكد ألّا تكون قد لصقت معه مسافة أو سطرًا جديدًا |
400 | طلب غير صالح | غالبًا اسم نموذج خاطئ أو نص أطول من النافذة السياقية |
403 | الوصول ممنوع | كثيرًا ما يكون تقييدًا بحسب المنطقة؛ جرّب من خادم آخر |
429 | تجاوز الحد | أعد المحاولة بفاصل متزايد أو افحص الرصيد |
500 إلى 503 | مشكلة من جهة الخدمة | انتظر ثوانيَ ثم أعد المحاولة |
0 | لم يتم الاتصال | شبكة الخادم أو جدار الحماية أو انتهاء المهلة |
إعادة المحاولة بفاصل متزايد#
للخطأ 429 وأخطاء 5xx:
function ai_ask_retry(string $question, string $apiKey, int $tries = 3): array
{
$result = ['ok' => false, 'status' => 0, 'error' => 'not started'];
for ($i = 0; $i < $tries; $i++) {
$result = ai_ask($question, $apiKey);
if ($result['ok']) {
return $result;
}
$retryable = in_array($result['status'], [0, 429, 500, 502, 503], true);
if (! $retryable) {
return $result;
}
sleep(2 ** $i); // 1, 2, 4 seconds
}
return $result;
}لا تعِد محاولة الخطأين 401 و400. لا يُصلحهما التكرار.
على الاستضافة المشتركة#
- ضع الطلب في طابور. إجابة الذكاء الاصطناعي تستغرق من بضع ثوانٍ إلى عشرات الثواني. إذا انتظر الزائر وجاء عدة أشخاص في الوقت نفسه فستصطدم بسقف المعالجة في الاستضافة.
- افحص
max_execution_time. إذا كان 30 ثانية ومهلة cURL ستين، فإن PHP ينتهي قبل cURL. - تحقق من المخرجات. إجابة النموذج تُعدّ مدخلًا من المستخدم: نقِّها (escape) قبل العرض ولا تضعها أبدًا مباشرة في استعلام أو
eval.
متابعة المسار#
إذا أفادك هذا المقال، فهذه المقالات تتعمق في الموضوع نفسه بصورة أكثر عملية:
3 از 3 مقاله منتشر شده است
- حساب تكلفة API الذكاء الاصطناعي وتقليلها
- الحصول على مخرجات منظمة (JSON) من الذكاء الاصطناعي
- عرض إجابة الذكاء الاصطناعي تدريجيًا (Streaming) في موقعك
الخلاصة#
- اختبر أولًا اتصال الخادم بالخدمة، ثم اكتب الكود.
- المفتاح في جهة الخادم فقط، خارج جذر الويب وخارج جيت.
- ضع سقف الإنفاق و
max_tokensوتسجيل الاستهلاك والتخزين المؤقت من اليوم الأول. - أعد محاولة
429و5xxبفاصل متزايد؛ ولا تعِد401و400. - اعتبر إجابة النموذج مدخلًا غير موثوق مثل مدخل المستخدم.