لقد اجتاز اختبارك يوم الاثنين: نفس الإدخال، نفس الكود، وtemperature=0. يوم الثلاثاء فشل الاختبار رغم أنك لم تغيّر شيئًا. السبب؟ فحصك يقارن سلسلة نصية مطابقة تمامًا، بينما أعاد النموذج الإجابة نفسها بمعنى صحيح لكن بصياغة مختلفة قليلًا. الاختبار أحمر، الوكيل يعمل، وأنت الآن تصحح مجموعة الاختبار بدلًا من المنتج. هذه مشكلة شائعة عند اختبار أي شيء يستدعي نموذج لغة، وهي وضع الفشل الثالث في دليلنا عن سبب فشل وكلاء الذكاء الاصطناعي في الإنتاج.
لماذا لا تعني temperature=0 حتمية؟
تتحكم درجة الحرارة في اختيار الرمز التالي. عند temperature=0 يختار النموذج عادةً الرمز الأكثر احتمالًا، لكن هذا لا يضمن مخرجات متطابقة على مستوى البايت.
السبب ليس في إعدادك فقط، بل في المكدس التشغيلي كاملًا:
- حسابات الفاصلة العائمة على GPU ليست ترابطية؛ ترتيب العمليات قد يغيّر النتيجة في منازل عشرية صغيرة.
- فرق صغير في احتمالات الرموز قد يغيّر الرمز التالي، ثم يتفرع باقي النص بالكامل.
- قد يغيّر الموفر تجميع الطلبات، العتاد، نواة الاستدلال، المنطقة، أو مكتبات التشغيل.
- قد تتغير الأوزان أو إعدادات الاستدلال من جهة المزود.
يوضح نقاش vLLM هذا لماذا لا تكفي البذور الثابتة وtemperature=0 لضمان قابلية تكرار على مستوى البتات.
القاعدة العملية: لا تعامل النص المتطابق باعتباره العقد. تعامل مع البنية، والحقائق، والقيود القابلة للتحقق باعتبارها العقد.
لماذا تجعل تأكيدات النص الدقيق اختباراتك متقلبة؟
هذا التأكيد يبدو منطقيًا في البداية:
expect(response.message).toBe("Your order total is $42.00.");
لكنه سيفشل إذا أعاد النموذج:
Your total comes to $42.00.
الإجابة صحيحة، لكن الاختبار فشل. ومع الوقت، تتعلم الفرق تجاهل الإخفاقات وإعادة تشغيل CI حتى يصبح أخضر. عندها يمكن أن يختبئ انحدار حقيقي وسط الضوضاء.
لقد تناولنا سابقًا أسباب الاختبارات المتقلبة ولماذا تنتشر بسرعة. المخرجات غير الحتمية من أسرع الطرق لإنشائها.
بدلًا من تثبيت النص أكثر عبر snapshots حرفية، اعكس الاتجاه: ثبّت ما يجب أن يبقى ثابتًا فعلًا.
أكّد على البنية والمعنى، لا على النص الدقيق
قد يعبّر وكيل دعم العملاء عن تأكيد الاسترداد بعشرات الصيغ، لكن الاستجابة الصحيحة يجب أن تحتفظ بالحقائق نفسها:
- مبلغ الاسترداد
- معرف الطلب
- حالة العملية
بدلًا من سؤال:
هل قال النموذج هذه الجملة حرفيًا؟
اسأل:
هل أعاد الاستجابة بالشكل الصحيح، والحقول المطلوبة، والقيم المقبولة؟
1. تحقق من الاستجابة مقابل مخطط JSON
إذا كان وكيلك يعيد بيانات مهيكلة، عرّف مخطط JSON ثم تحقق من كل استجابة مقابله.
مثال لمخطط استجابة استرداد:
{
"type": "object",
"required": ["order_id", "status", "amount"],
"properties": {
"order_id": {
"type": "string",
"pattern": "^ORD-[0-9]+$"
},
"status": {
"type": "string",
"enum": ["refunded", "pending", "denied"]
},
"amount": {
"type": "number",
"minimum": 0
}
},
"additionalProperties": false
}
هذا التحقق يلتقط أخطاء مهمة مثل:
- غياب حقل مطلوب
- إعادة نص بدل JSON
- إرسال
amountكسلسلة نصية بدل رقم - حالة غير مسموحة
- إضافة حقول غير متوقعة
حمّل مخطط الاستجابة إلى Apidog للتحقق من استجابات الوكيل الحية مقابل العقد. عند الفشل، ستعرف الحقل المخالف مباشرة بدل مقارنة نص طويل من مئات الأحرف.
2. اختبر استدعاء الأداة، لا الجملة التي سبقته
عندما يقرر الوكيل استدعاء أداة، لا تختبر تفسيره اللغوي فقط. اختبر الاستدعاء الصادر نفسه.
مثال: وكيل حجز يجب أن يستدعي:
POST /reservations
بحمولة مثل:
{
"guests": 2,
"date": "2025-06-15"
}
يمكنك التأكيد على:
- اختيار الأداة أو المسار الصحيح.
- استخدام طريقة HTTP الصحيحة.
- وجود المعلمات المطلوبة.
- صحة الأنواع والتنسيقات.
- عدم إرسال حقول مخترعة.
مثال تأكيد:
expect(toolCall.method).toBe("POST");
expect(toolCall.path).toBe("/reservations");
expect(toolCall.body.guests).toBeGreaterThan(0);
expect(toolCall.body.date).toMatch(/^\d{4}-\d{2}-\d{2}$/);
تشرح الطريقة الشاملة لاختبار استدعاءات API لوكيل الذكاء الاصطناعي كيفية التقاط مخططات الأدوات والتأكد منها.
3. استخدم نطاقات رقمية بدل القيم الدقيقة
لا تؤكد على رقم ثابت إذا كان الرقم مشتقًا من مدخلات أو سياق متغير. أكّد على نطاق منطقي.
بدلًا من:
expect(response.total).toBe(42.00);
اكتب:
expect(response.total).toBeGreaterThanOrEqual(0);
expect(response.total).toBeLessThanOrEqual(cartSubtotal + maxTax + maxShipping);
هذا يلتقط الأخطاء المهمة:
- إجمالي سالب
- قيمة أكبر من المتوقع بعشر مرات
- إجمالي صفر لعربة غير فارغة
- نوع قيمة غير صحيح
استخدم النطاقات أيضًا مع:
- درجات الثقة
- عدد العناصر
- استخدام الرموز
- زمن الاستجابة
- ميزانيات التكلفة
اختر أوسع حد يظل قادرًا على كشف خطأ حقيقي.
4. تحقق من الحقول المطلوبة والحقول المحظورة
هناك فحصان منخفضا التكلفة وعاليَا القيمة:
- الحقول التي تعتمد عليها موجودة وغير فارغة.
- الحقول التي يجب ألا تظهر لا تظهر أبدًا.
مثال:
expect(response.resolution).toBeTruthy();
expect(response).not.toHaveProperty("internal_notes");
expect(response).not.toHaveProperty("raw_prompt");
هذا مهم خصوصًا لوكلاء الدعم أو الأدوات التي تتعامل مع بيانات داخلية. فحص غياب الحقول يمنع تسرب محتوى مثل الملاحظات الداخلية أو نص التوجيهات الخام إلى العميل.
5. استخدم فحوصات دلالية وعتبات للنص الحر
أحيانًا تكون الاستجابة نصًا حرًا ولا يمكنك تحويلها إلى JSON. لا تستخدم تطابقًا حرفيًا؛ اختبر خصائص قابلة للقياس.
مثلًا:
expect(response.message).toContain(orderId);
expect(response.message.length).toBeLessThan(1000);
expect(response.message).not.toMatch(/كلمة_محظورة_1|كلمة_محظورة_2/i);
وعندما تحتاج إلى فحص المعنى، استخدم تشابه التضمين مع إجابة مرجعية:
expect(embeddingSimilarity(actual, expected)).toBeGreaterThan(0.85);
تعامل مع هذا الفحص كإشارة تقريبية، لا كحكم دقيق على صحة الحقائق. فهو قد يلتقط الاستجابة الخارجة عن الموضوع، لكنه لا يضمن غياب خطأ واقعي دقيق. لذلك اجمعه مع فحوصات البنية والحقول والنطاقات.
6. استخدم snapshots للنطاقات، لا للنص كاملًا
لا يزال للاختبارات باللقطات مكان، لكن اجعل اللقطة تمثل الأجزاء المستقرة فقط:
- مجموعة المفاتيح
- أنواع الحقول
- قيم التعداد
- الحدود الرقمية
- الحقول المطلوبة والمحظورة
بدل لقطة مثل:
{
"message": "Your order total is $42.00."
}
اجعلها توثق العقد:
{
"requiredKeys": ["order_id", "status", "amount"],
"statusValues": ["refunded", "pending", "denied"],
"amountRange": [0, 10000]
}
بهذا، يفشل الاختبار عند تغيير بنيوي يستحق المراجعة، لا عند تبديل مرادف بمرادف.
الحالة والذاكرة تجعل الاختبار أصعب
حتى الآن، افترضنا طلبًا واحدًا واستجابة واحدة. الوكلاء ذوو الحالة لا يعملون بهذه البساطة.
قد تعتمد الاستجابة على:
- ما استرجعه الوكيل من مصادر
- ما خزّنه في الذاكرة سابقًا
- ترتيب الأدوار السابقة
- ملخصات المحادثة
- نتائج البحث أو الترتيب
قد يتباعد تشغيلان للمحادثة نفسها لأن الاسترجاع رتّب المستندات بطريقة مختلفة، أو لأن ملخصًا في دور سابق أثّر في القرار الحالي. راجع كيف تعمل ذاكرة وكيل الذكاء الاصطناعي لفهم أماكن وجود هذه الحالة.
لتبقي الاختبارات قابلة للتشخيص:
ابدأ من حالة معروفة
أعد تهيئة ذاكرة الوكيل قبل كل اختبار.اختبر الثوابت المستقلة عن المسار
لا يجب أن يصبح الرصيد سالبًا.
يجب أن تنتهي محادثة حجز رحلة بحجز واحد فقط، مهما اختلف عدد الأدوار.
مثال:
expect(finalState.balance).toBeGreaterThanOrEqual(0);
expect(finalState.bookings).toHaveLength(1);
حاكِ التبعيات لكي يصبح الاختبار قابلاً للتكرار
لا تعتمد في اختباراتك على APIs خارجية حية. فهي قد:
- تفرض حدودًا على معدل الطلبات
- تغيّر بياناتها
- تتأخر أو تفشل مؤقتًا
- تضيف مصدرًا جديدًا للعشوائية
بدلًا من ذلك، حاكِ التبعيات وثبّت استجاباتها.
مثلًا، اجعل API الدفع يعيد الإيصال نفسه دائمًا:
{
"transaction_id": "txn_test_001",
"status": "approved",
"amount": 42
}
واجعل API البحث يعيد النتائج الثلاث نفسها في كل تشغيل:
{
"results": [
{ "id": "doc_1", "score": 0.98 },
{ "id": "doc_2", "score": 0.91 },
{ "id": "doc_3", "score": 0.87 }
]
}
الآن يصبح الجزء المتغير الوحيد هو منطق الوكيل الذي تريد مراقبته فعلًا. كما تتيح لك المحاكاة فرض حالات حافة، مثل استجابة دفع مرفوضة أو نتيجة بحث فارغة، ثم اختبار تصرف الوكيل.
استخدم Apidog لمحاكاة تبعيات الوكيل بأجسام استجابة ثابتة وقابلة للتحكم، ثم اربط ذلك بتأكيدات المخطط. هذه ممارسة أساسية ضمن اختبار وكلاء الذكاء الاصطناعي.
أين يتناسب Apidog، وأين لا يتناسب؟
كن واضحًا بشأن مسؤولية الأداة.
Apidog منصة لتصميم APIs واختبارها ومحاكاتها. ليس:
- إطار عمل لوكلاء الذكاء الاصطناعي
- مضيفًا للنماذج
- بيئة تشغيل للوكيل
- منسقًا لخطوات الوكيل
- منصة لتقييم منطق النموذج
لكن Apidog مناسب لطبقة API التي يتعامل معها وكيلك. استخدمه من أجل:
- التحقق من مخططات استجابات الوكيل
- اختبار الحقول المطلوبة والمحظورة
- فحص النطاقات الرقمية
- اختبار شكل حمولة استدعاءات الأدوات
- محاكاة خدمات الدفع والبحث والأنظمة الخارجية
- تثبيت التبعيات لجعل التشغيل قابلًا للتكرار
بكلمات أخرى: Apidog يختبر عقود الطلبات والاستجابات، لا النموذج الذي يولد النص.
اختبر العقد، لا الصياغة
عدم الحتمية ليست خطأً تعالجه بإعداد واحد. إنها خاصية لتشغيل النماذج اللغوية، وtemperature=0 لا يلغيها.
الاختبارات الموثوقة لوكلاء الذكاء الاصطناعي لا تطلب نصًا متطابقًا. بل تختبر:
- المخطط
- شكل الاستجابة
- الحقول المطلوبة والمحظورة
- أنواع البيانات
- القيم المسموح بها
- النطاقات الرقمية
- صحة استدعاءات الأدوات
- الثوابت عبر الحالة والذاكرة
اختر تأكيدًا متقلبًا واحدًا هذا الأسبوع، واستبدل مقارنة النص فيه بتحقق مخطط أو نطاق أو حقل مطلوب. ستصبح مجموعتك أكثر هدوءًا: تبقى خضراء عندما تتغير الصياغة، وتتحول إلى الأحمر عندما ينكسر العقد فعلًا.
Top comments (0)