حين تريد إدخال الذكاء الاصطناعي في موقعك أو تطبيقك، فلن تتعامل بعد الآن مع صفحة دردشة؛ بل مع واجهة API. الخبر الجيد أن الاتصال نفسه بسيط. والخبر السيئ أن معظم الشروحات تنتهي عنده ولا تتطرق إلى ما يسبب المتاعب فعلًا.

كُتبت أمثلة هذا المقال بالصيغة الشائعة التي قدّمتها OpenAI وتتوافق معها خدمات أخرى كثيرة. أما الخدمات ذات الصيغة المختلفة فيختلف فيها العنوان وأسماء الحقول، وبقية النصائح واحدة.

قبل الكود: تحتاج إلى ثلاثة أشياء#

  1. مفتاح API من لوحة تحكم الخدمة نفسها.
  2. رصيد في الحساب. واجهة API منفصلة عن اشتراك صفحة الدردشة وتُحاسَب على حدة.
  3. خادم يستطيع الاتصال بتلك الخدمة.

اختبر الأمر الثالث قبل كل شيء. فبعض الخدمات تقيّد الوصول بحسب البلد، وقد لا يتمكن بعض الخوادم من الاتصال بها. نفّذ هذا الأمر في طرفية الاستضافة:

Bash
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
<?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 حتى يمكن تسجيل الاستهلاك.

اضبط التكلفة#

التكلفة بحسب الرموز، منفصلةً للمدخلات والمخرجات. شرحنا ما هو الرمز ولماذا تستهلك العربية أكثر في الرموز والنافذة السياقية والهلوسة.

خمسة أعمال تمنع فاتورة مفاجئة:

  1. اضبط سقف الإنفاق الشهري في لوحة تحكم الخدمة. هذا أول عمل، قبل كتابة سطر كود واحد.
  2. ضع max_tokens دائمًا.
  3. سجّل استهلاك كل طلب. اكتب tokens_in وtokens_out في قاعدة البيانات أو في السجل.
  4. خزّن النتيجة مؤقتًا (Cache). إذا طُرح السؤال نفسه مرة أخرى فلا تدفع مرة ثانية.
  5. ضع سقفًا لكل مستخدم. نموذج عام بلا قيود دعوة مفتوحة لإساءة الاستخدام.

الأخطاء الشائعة#

الرمزالمعنىماذا نفعل
401مفتاح خاطئ أو ملغىافحص المفتاح؛ وتأكد ألّا تكون قد لصقت معه مسافة أو سطرًا جديدًا
400طلب غير صالحغالبًا اسم نموذج خاطئ أو نص أطول من النافذة السياقية
403الوصول ممنوعكثيرًا ما يكون تقييدًا بحسب المنطقة؛ جرّب من خادم آخر
429تجاوز الحدأعد المحاولة بفاصل متزايد أو افحص الرصيد
500 إلى 503مشكلة من جهة الخدمةانتظر ثوانيَ ثم أعد المحاولة
0لم يتم الاتصالشبكة الخادم أو جدار الحماية أو انتهاء المهلة

إعادة المحاولة بفاصل متزايد#

للخطأ 429 وأخطاء 5xx:

PHP
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 مقاله منتشر شده است

  1. حساب تكلفة API الذكاء الاصطناعي وتقليلها
  2. الحصول على مخرجات منظمة (JSON) من الذكاء الاصطناعي
  3. عرض إجابة الذكاء الاصطناعي تدريجيًا (Streaming) في موقعك

الخلاصة#

  • اختبر أولًا اتصال الخادم بالخدمة، ثم اكتب الكود.
  • المفتاح في جهة الخادم فقط، خارج جذر الويب وخارج جيت.
  • ضع سقف الإنفاق وmax_tokens وتسجيل الاستهلاك والتخزين المؤقت من اليوم الأول.
  • أعد محاولة 429 و5xx بفاصل متزايد؛ ولا تعِد 401 و400.
  • اعتبر إجابة النموذج مدخلًا غير موثوق مثل مدخل المستخدم.