يعرض واجهة برمجة التطبيقات (API) الخاصة بك رمز 400 Bad Request مع نص {"error": "invalid input"}. يفتح المطور البشري الوثائق، ويتحقق من حمولة الطلب، ويحدد الحقل المفقود، ويصلحه في دقيقة واحدة. يقرأ الوكيل نفس الكلمتين، ولا يجد شيئًا ليتصرف بناءً عليه، ويفعل الشيء الوحيد الذي يمكنه فعله: يرسل نفس الطلب مرة أخرى. ثم مرة أخرى. ثم يستسلم ويخبر المستخدم أن واجهة برمجة التطبيقات معطلة.
استجابات الأخطاء هي الجزء الذي تعتمد عليه الوكلاء في واجهة برمجة التطبيقات أكثر من غيره، والذي تصممه الفرق أخيرًا. يخبر الخطأ الجيد المتصل بما حدث خطأ، وما إذا كانت إعادة المحاولة يمكن أن تساعد، وما الذي يجب تغييره. يمكن للوكيل التصرف بناءً على هذه النقاط الثلاث جميعها. يحول الخطأ الغامض مشكلة قابلة للاسترداد إلى مهمة فاشلة.
كُتب هذا الدليل لجانب واجهة برمجة التطبيقات من العلاقة. تغطي مشاركتنا حول استعادة أخطاء الوكيل ما يجب على العميل فعله فيما يتعلق بإعادة المحاولات، والتراجع (backoff)، وقواطع الدائرة. ويغطي هذا الدليل ما يجب على واجهة برمجة التطبيقات الخاصة بك إرجاعه لكي يعمل منطق العميل هذا على الإطلاق.
يهم Apidog هنا لأن استجابات الأخطاء هي الجزء الأقل اختبارًا في معظم واجهات برمجة التطبيقات. يمكنك تعريفها في المواصفات، ومحاكاتها، والتأكد منها في نفس المكان الذي تختبر فيه المسار السليم.
الأسئلة الثلاثة التي يجب أن يجيب عليها الخطأ
يجب أن تتيح كل استجابة خطأ يتلقاها الوكيل له الإجابة على ثلاثة أشياء دون تخمين.
هل هذا خطئي أم خطأك؟ يشير 4xx إلى أن الطلب كان خاطئًا وأن تكراره دون تغيير سيفشل مرة أخرى. يشير 5xx إلى حدوث خطأ ما في الخادم وقد ينجح نفس الطلب لاحقًا. الوكلاء الذين لا يستطيعون التمييز بين هذه الأمور إما يعيدون المحاولة إلى الأبد عند حدوث خطأ في التحقق من الصحة أو يستسلمون عند حدوث خلل عابر.
هل يجب علي إعادة المحاولة، ومتى؟ بعض أخطاء 4xx قابلة لإعادة المحاولة وبعضها ليس كذلك. 429 قابل لإعادة المحاولة بعد الانتظار. قد يكون 409 قابلًا لإعادة المحاولة بعد إعادة قراءة الحالة. 422 غير قابل لإعادة المحاولة دون تغيير الحمولة. اذكر ذلك صراحةً.
ما الذي يجب أن أغيره بالضبط؟ هذا هو الحقل الذي تغفله معظم واجهات برمجة التطبيقات. "فشل التحقق من الصحة" عديم الفائدة. "الحقل customer.postal_code مطلوب عندما تكون country هي US" هو إصلاح يمكن للوكيل تطبيقه في المحاولة التالية.
ضع هذه الثلاثة في كل خطأ وستختفي معظم عواصف إعادة محاولة الوكيل.
استخدم تنسيق خطأ منظم
لا تخترع شكلاً. RFC 9457, تفاصيل المشكلة لواجهات برمجة تطبيقات HTTP، يحدد واحدًا وهو مدعوم جيدًا:
{
"type": "https://api.example.com/errors/validation-failed",
"title": "Validation failed",
"status": 422,
"detail": "The field 'customer.postal_code' is required when 'country' is 'US'.",
"instance": "/v1/orders",
"errors": [
{
"field": "customer.postal_code",
"code": "required_conditional",
"message": "Required when country is US. Provide a 5-digit or 9-digit US postal code.",
"example": "94107"
}
],
"retryable": false,
"next_action": "Add customer.postal_code to the request body and send again."
}
تحمل أربعة أجزاء العبء على عاتق الوكيل.
detail هي جملة كاملة تسمي الحقل الفعلي والقاعدة الفعلية. ليست فئة. الشيء المحدد الذي فشل في هذا الطلب.
المصفوفة errors قابلة للقراءة آليًا، تتضمن إدخالًا واحدًا لكل مشكلة، مع مسار حقل يمكن للوكيل ربطه بالحمولة التي أرسلها. أعد كل الأخطاء دفعة واحدة. إرجاعها واحدًا تلو الآخر يحول إصلاحًا واحدًا إلى خمس رحلات ذهاب وعودة.
retryable هي قيمة منطقية (boolean)، وليست شيئًا يُستدل عليه من رمز الحالة. هذا هو الامتداد الذي يساعد الوكلاء أكثر من غيره، ويكلف حقلًا واحدًا.
next_action هو نص تعليمات واضح. تتبع النماذج التعليمات الصريحة في نص الاستجابة بشكل أكثر موثوقية مما تستنتجه من رموز الأخطاء، وغالبًا ما تحول جملة واحدة هنا مهمة فاشلة إلى مهمة مكتملة.
يصل دليل تصميم أخطاء واجهة برمجة تطبيقات Google إلى استنتاجات مماثلة من اتجاه مختلف، وتحديداً أن تفاصيل الأخطاء يجب أن تكون في قائمة منظمة بدلاً من نص نثري.
اذكر متى يجب العودة
لأي شيء مؤقت، اذكر متى. الوكيل الذي يعرف أن ينتظر 30 ثانية سينتظر 30 ثانية. الوكيل الذي لا يعرف سيختار شيئًا ما، وعادة ما يكون هذا الشيء قصيرًا جدًا.
HTTP/1.1 429 Too Many Requests
Retry-After: 30
Content-Type: application/problem+json
{
"type": "https://api.example.com/errors/rate-limited",
"title": "Rate limit exceeded",
"status": 429,
"detail": "You have used 1000 of 1000 requests in the current minute window.",
"retryable": true,
"retry_after_seconds": 30,
"next_action": "Wait 30 seconds before sending this request again. Do not retry sooner."
}
يقبل عنوان Retry-After إما تأخيرًا بالثواني أو تاريخ HTTP؛ والثواني هي الأسهل للعميل للتصرف بناءً عليها. أرسله كعنوان للعملاء القياسيين وكرره في النص للنموذج. التكرار رخيص ويحصل كلا المستهلكين على ما يقرأونه بشكل أفضل. يتم تغطية تفاصيل حدود المعدل في دليل تجاوز حدود المعدل وفي كيفية تطبيق تحديد معدل واجهة برمجة التطبيقات إذا كنت في جانب الخادم من ذلك.
ينطبق نفس النمط على 503 أثناء الصيانة وعلى 409 على مورد مقفل. يجب أن يحمل أي خطأ يكون الانتظار هو الاستجابة الصحيحة له رقمًا.
لا تسرب التفاصيل الداخلية أبدًا، ولا تُرجع شيئًا أبدًا
هناك نمطان للفشل يقعان في أقصى الحدود المعاكسة، وكلاهما يضر بالوكلاء.
الأول هو تتبع المكدس (stack trace). يعرض إرجاع نص الاستثناء الداخلي إصدارات الأطر، ومسارات الملفات، وأحيانًا أجزاء الاستعلام. إنها مشكلة أمنية قبل أن تكون مشكلة وكيل، وتطبق المخاوف الواردة في مشاركتنا حول اختبار واجهات برمجة التطبيقات ضد المدخلات غير الموثوق بها مباشرة. كما أنها تغمر نافذة السياق بنص لا يمكن للنموذج التصرف بناءً عليه.
الثاني هو الخطأ الفارغ: 500 بدون نص، أو {"error": true}. لا يتعلم الوكيل شيئًا، وخياراته الوحيدة هي إعادة المحاولة أو الإقلاع.
المسار الأوسط هو خطأ عام مستقر مع معرف ارتباط (correlation ID):
{
"type": "https://api.example.com/errors/internal",
"title": "Internal error",
"status": 500,
"detail": "The order could not be created due to an internal error. No order was created.",
"retryable": true,
"retry_after_seconds": 5,
"request_id": "req_01J8ZK3M2Q",
"next_action": "Retry once after 5 seconds. If it fails again, stop and report request_id req_01J8ZK3M2Q."
}
جملة "لم يتم إنشاء طلب" هي الجزء الأكثر قيمة. يتعين على الوكلاء الذين يواجهون عملية كتابة غامضة أن يقرروا ما إذا كانت إعادة المحاولة تنطوي على خطر التكرار، ومعظمهم يتخذ قرارات سيئة. أخبرهم بالحالة التي أنت فيها. عندما لا يمكنك الوعد بذلك، اجعل العملية قابلة للتكرار (idempotent) واذكر ذلك، وهو النمط الموجود في مشاركتنا حول مفاتيح التكرارية لوكلاء الذكاء الاصطناعي.
يمنحك request_id القدرة على تتبع السجل إلى سجلاتك عندما يقرأ إنسان النسخة النهائية. ادمجها مع الممارسات في دليل قابلية ملاحظة واجهة برمجة التطبيقات (API observability) الخاص بنا بحيث يتم حل المعرف بالفعل إلى شيء ما.
الأخطاء يجب أن تكون في المواصفات
إذا لم يكن شكل الخطأ موجودًا في مستند OpenAPI الخاص بك، فإنه غير موجود بالنسبة للعملاء المولدين، والمحاكيات، وأدوات الوكيل. تصف معظم المواصفات رمز 200 بالتفصيل ثم تشير إلى كل شيء آخر.
responses:
'201':
description: Order created
content:
application/json:
schema: { $ref: '#/components/schemas/Order' }
'422':
description: >
Validation failed. Not retryable without changing the request body.
The errors array names each invalid field.
content:
application/problem+json:
schema: { $ref: '#/components/schemas/Problem' }
'429':
description: >
Rate limited. Retryable. Wait for retry_after_seconds before sending again.
content:
application/problem+json:
schema: { $ref: '#/components/schemas/Problem' }
هذه الأوصاف ليست للزينة. عندما تقوم بإنشاء أدوات وكيل من المواصفات، كما هو الحال في دليلنا حول تحويل مواصفات OpenAPI إلى أدوات وكيل، يصبح هذا النص ما يقرأه النموذج عن حالة الفشل. وصف يقول "قابل لإعادة المحاولة، انتظر أولاً" ينتج سلوكًا أفضل من وصف يقول "عدد كبير جدًا من الطلبات".
اختبر الأخطاء، وليس فقط النجاحات
مسارات الأخطاء هي المكان الذي ينهار فيه تغطية الاختبار، لأن تفعيلها يتطلب جهدًا. المحاكاة تزيل هذا الجهد.

حدد كل استجابة خطأ في مشروع واجهة برمجة التطبيقات الخاص بك، ثم قم بمحاكاتها بحيث يمكن للوكيل مواجهة كل حالة عند الطلب. في Apidog، يمكنك إضافة استجابات الفشل إلى تعريف نقطة النهاية والتبديل بين المحاكيات، مما يمنحك طريقة قابلة للتكرار لتشغيل الوكيل مقابل 422 و 429 و 500 دون كسر أي شيء حقيقي. تغطي مشاركتنا حول تشغيل الوكلاء مقابل المحاكيات بدلاً من الإنتاج هذه العادة الأوسع.
خمس حالات يجب بناؤها:
- فشل التحقق من الصحة مع عدة حقول خاطئة في وقت واحد. تأكد من أن كل مشكلة تعود في استجابة واحدة، وأن محاولة الوكيل التالية تصلح جميعها بدلاً من واحدة فقط.
- حد معدل الطلبات مع انتظار. تأكد من أن الوكيل ينتظر على الأقل
retry_after_secondsبدلاً من المراسلة المتكررة. - خطأ في الخادم عند عملية كتابة. تأكد من أن الوكيل لا يقوم بإنشاء نسخة مكررة بصمت عند إعادة المحاولة.
- فشل المصادقة. تأكد من أن الوكيل يتوقف بدلاً من إعادة المحاولة، حيث لا يوجد قدر من الانتظار يصلح رمزًا غير صالح. تغطي مشاركتنا حول مفاتيح API بأقل امتياز للوكلاء جانب بيانات الاعتماد.
- نص خطأ مشوه. أرجع شيئًا ليس بتنسيق JSON صالح وتأكد من أن الوكيل يتعامل مع المشكلة بلطف. الوكلاء الوسيطون (Upstream proxies) سيفعلون ذلك بك في النهاية.
احفظ المجموعة كسيناريوهات لتشغيلها في CI. تتراجع معالجة الأخطاء بصمت، عادةً عندما يقوم شخص ما بإعادة هيكلة أداة التسلسل (serializer)، ولن تلاحظ مجموعة المسار السليم ذلك.
قيمة الأخطاء الأفضل
تظهر القيمة في ثلاثة أماكن، ومن السهل قياسها بمجرد النظر.
عدد أقل من المحاولات الضائعة. الوكيل الذي يواجه {"error": "invalid input"} عادة ما يعيد محاولة نفس الحمولة مرتين أو ثلاث مرات قبل الإقلاع. تكلف كل محاولة دورًا للنموذج والمحادثة الكاملة كسياق. الاستجابة التي تحدد الحقل المفقود عادة ما تنتج محاولة مصححة واحدة. هذا هو الفرق بين أربع مكالمات واثنتين عند حدوث خطأ بسيط في التحقق من الصحة.
تصعيد أقل. الوكلاء الذين لا يستطيعون الاسترداد يسلمون المهمة إلى إنسان. كل تسليم يمكن تجنبه هو نتيجة مكلفة كان من المفترض أن يمنعها الوكيل. الأخطاء التي تحدد إصلاحًا تحافظ على التشغيل داخل الأتمتة.
تصحيح أخطاء أقصر. عندما يحتاج الأمر إلى شخص، فإن request_id بالإضافة إلى detail دقيق يحول البحث في السجلات إلى عملية بحث واحدة. هذه هي نفس الحجة التي يقدمها دليل قابلية ملاحظة واجهة برمجة التطبيقات (API observability) الخاص بنا حول الارتباط، وتطبق على اللحظة التي يتعطل فيها التشغيل.
هناك فائدة رابعة من السهل إغفالها: نفس التحسينات تساعد المطورين البشريين. لم يشتكِ أحد أبدًا من أن رسالة الخطأ كانت محددة جدًا بشأن الحقل الخاطئ.
صمم من أجل التصعيد أيضًا
بعض الأخطاء لا يمكن للوكيل استردادها حقًا. نطاق مفقود، حساب مغلق، قاعدة تحتاج إلى قرار بشري. بالنسبة لهذه الأخطاء، تتمثل مهمة الخطأ في تسليم المهمة بشكل نظيف: قل ما حدث، وقل ما يحتاجه الشخص للقيام به، واحمل معرف الارتباط الذي يجعل التسليم رخيصًا.
يجب أن تصل هذه الردود إلى مكان يقرأه إنسان. إذا كان الوكيل عبارة عن وقت تشغيل برمجي يعمل على مهام معينة، فإن المنصة المحيطة هي عادةً المكان الذي تصل إليه. يحتفظ Sharkly بنتائج الوكيل وتتبع التنفيذ على المهمة ويوجه العناصر التي تحتاج إلى رد أو مراجعة إلى صندوق الوارد، بحيث يكون التشغيل المحظور مرئيًا كعمل بدلاً من سطر في سجل. نص الخطأ الخاص بك هو ما يجعل هذا التسليم مفيدًا، لأن رسالة تقول "مدخلات غير صالحة" لا تقدم للمراجع أكثر مما قدمته للوكيل.

لا تجعل الوكيل يحلل النصوص النثرية
نمط مضاد أخير، شائع في واجهات برمجة التطبيقات التي نمت بشكل عضوي. رمز الحالة صحيح، والنص جملة، وكل فشل مميز يحصل على صياغة مختلفة:
{ "message": "Sorry, that didn't work. Please check your details and try again." }
يمكن للوكيل فقط الاستجابة لذلك عن طريق التخمين. والأسوأ من ذلك، غالبًا ما تقوم الفرق بإقرانه بحالة 200، لذا فإن مكتبة العميل لا ترى أي فشل حتى.
قاعدتان تصلحانه. أعطِ كل فشل مميز رمزًا ثابتًا قابلاً للقراءة آليًا، بحيث يمكن للوكيل التفريع بناءً على insufficient_funds بدلاً من عبارة "غير كافٍ". ولا ترجع أبدًا فشلًا برمز حالة نجاح، مهما كانت حجة راحة جانب العميل. رمز 200 مع خطأ داخله يكون غير مرئي لكل سياسة إعادة محاولة، وكل لوحة تحكم، وكل تنبيه تمتلكه.
قائمة مرجعية للأخطاء القابلة للقراءة من قبل الوكيل
- يستخدم كل خطأ تنسيقًا منظمًا متسقًا عبر واجهة برمجة التطبيقات بأكملها.
- يحدد
detailالحقل أو الشرط المحدد، وليس فئة أبدًا. - تُرجع أخطاء التحقق من الصحة كل مشكلة في وقت واحد، مع مسارات الحقول.
- يظهر حقل
retryableالمنطقي (boolean) في كل خطأ. - تحمل الأخطاء القابلة لإعادة المحاولة فترة انتظار بالثواني، في العنوان والنص.
- توضح أخطاء الكتابة ما إذا تم إنشاء أو تغيير أي شيء.
- يحمل كل خطأ معرف ارتباط (correlation ID) يتم حله في سجلاتك.
- لا تتبعات مكدس، لا سلاسل إطار عمل، لا SQL.
- استجابات الأخطاء موثقة في المواصفات بأوصاف قابلة للقراءة من قبل الوكيل.
- توجد محاكيات لكل خطأ، ويتم تشغيل الاختبارات المحفوظة لها في CI.
الأخطاء هي واجهة. صممها للمتصل الفعلي لديك، والذي هو بشكل متزايد نموذج سيفعل بالضبط ما يخبره به نص استجابتك. قم بتنزيل Apidog لتعريف أشكال الأخطاء ومحاكاتها قبل أن يواجهها الوكيل على أرض الواقع.
أسئلة مكررة
هل يجب أن أستخدم RFC 9457 أم تنسيق الخطأ الخاص بي؟ استخدم RFC 9457 ما لم يكن لديك بالفعل تنسيق متسق في الإنتاج. الاتساق يتفوق على التوحيد القياسي: تغيير نصف نقاط النهاية الخاصة بك إلى شكل جديد أسوأ من الاحتفاظ بشكل واحد في كل مكان. أضف امتدادات retryable و next_action إلى أي منهما تستخدمه.
هل نص next_action آمن لوضعه في استجابة واجهة برمجة التطبيقات؟ نعم، عندما تقوم خدمتك بتوليده من مجموعة ثابتة من القوالب. لا تعكس أبدًا المحتوى الذي يوفره المستخدم في هذا الحقل، لأن الوكيل يقرأه كتعليمات وهذا مسار لحقن الأوامر. تغطي مشاركتنا حول اختبار واجهات برمجة التطبيقات ضد المدخلات غير الموثوق بها هذا الخطر.
هل يجب أن تكون أخطاء التحقق من الصحة 400 أو 422؟ استخدم 400 عندما يكون الطلب مشوهًا، مثل JSON مكسور، و 422 عندما يتم تحليل الطلب ولكنه يفشل في قواعد العمل. يستفيد الوكلاء من هذا التقسيم لأن الإصلاحات مختلفة. إذا كنت تستخدم واحدًا لكلاهما بالفعل، فوثقه بدلاً من تغييره.
كم من التفاصيل يعتبر أكثر من اللازم؟ توقف عند النقطة التي يكون فيها المتصل لديه ما يكفي للتصرف. اسم الحقل والقاعدة وقيمة مثال عادة ما تكون كافية. المعرفات الداخلية، نص الاستعلام، وإطارات المكدس تتجاوز الحد.
هل تحتسب رسائل الخطأ ضمن نافذة السياق؟ نعم، والخطأ المطول الذي يتكرر عبر المحاولات المتكررة يتراكم بسرعة. احتفظ بها تحت بضع مئات من الرموز المميزة. تنطبق مشاركتنا حول تقليص استجابات واجهة برمجة التطبيقات للوكلاء على حالات الفشل بنفس قدر انطباقها على حالات النجاح.
كيف أمنع الوكيل من إعادة محاولة خطأ غير قابل لإعادة المحاولة؟ اضبط retryable: false، واذكر ذلك في next_action، وافرضه في غلاف الأداة (tool wrapper) بحيث لا يكون حكم النموذج هو الحارس الوحيد. الاحتياطات المزدوجة هي الصحيحة هنا.
