استدعاء موثوق للأدوات في وكلاء الذكاء الاصطناعي 2026: المخرجات المنظمة والتحقق وإعادة المحاولة الآمنة

الاستخدام الصارم للأدوات يضمن شكل الاستدعاء لا معناه. ما الذي تغطيه المخرجات المنظمة وما لا تغطيه، وكيف تصمم الأدوات، وطبقة تنفيذ مُختبرة للتحقق ومنع التكرار وإعادة المحاولة والأخطاء المفيدة.

Lumis Editorial · 10 دقائق قراءة · October 7, 2026

Read this article in English

استدعاء موثوق للأدوات في وكلاء الذكاء الاصطناعي 2026: المخرجات المنظمة والتحقق وإعادة المحاولة الآمنة

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

ماذا تضمن المخرجات المنظمة؟

كل من Anthropic وOpenAI يقدمان الآن التوليد المقيَّد (constrained decoding): أثناء توليد النموذج لاستدعاء أداة أو إجابة JSON، تُمنع الوحدات النصية التي قد تكسر المخطط (schema). والنتيجة تُقرأ دائماً بدون أخطاء، وتطابق دائماً أنواع المخطط وحقوله الإلزامية.

  • Anthropic تقدم ميزتين متاحتين للجميع: مخرجات JSON ‏(output_config.format مع مخطط JSON) للإجابات المنظمة، والاستخدام الصارم للأدوات ‏("strict": true في تعريف الأداة) لضمان أن أسماء الأدوات ومدخلاتها تتبع المخطط. وتقبل حزم البرمجة أيضاً نماذج Pydantic أو Zod مباشرة.
  • OpenAI أطلقت Structured Outputs في أغسطس 2024، مع strict: true لاستدعاء الدوال، وصيغة استجابة json_schema. وفي اختباراتها الداخلية، سجّل النموذج الجديد مع هذه الميزة 100% في مطابقة المخطط، مقابل أقل من 40% لنموذج أقدم بدونها.

قبل هذه المزايا، كانت الفرق تكتب تعابير نمطية (regex) لإصلاح JSON المكسور، وتعيد المحاولة عند أخطاء القراءة. هذا النوع كله من الأخطاء أصبح قابلاً للتجنب. فاستخدمه.

ما الذي لا تضمنه؟

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

  • شكل صحيح وقيم خاطئة. إعلان OpenAI يقول بوضوح إن الميزة لا تضمن دقة القيم داخل JSON. استدعاء بتنسيق مثالي قد يحمل رقم عميل غير موجود أصلاً.
  • ليست كل القيود مطبّقة. توثيق Anthropic يذكر مزايا في JSON Schema لا يدعمها الوضع الصارم، منها minimum وmaximum وminLength وmaxLength. أدوات حزم البرمجة تنقل هذه القواعد إلى وصف الحقل بدلاً من ذلك، فيُطلب من النموذج اتباعها دون أن يُجبر عليها. وقيمة party_size تساوي ‎-4 تبقى عدداً صحيحاً سليماً من ناحية النوع.
  • الحالات الطرفية. إذا رفض النموذج لأسباب تتعلق بالأمان (stop_reason: "refusal") أو نفدت وحداته النصية ("max_tokens")، فقد لا تطابق المخرجات المخطط. وتنبّه Anthropic أيضاً إلى عدم ضمان حالة الأحرف الكبيرة والصغيرة في قيم enum، فقارنها دون اعتبار لحالة الأحرف.
  • الآثار الجانبية. لا شيء في المخطط يمنع استدعاءً مكرراً من إنشاء حجز ثانٍ، أو خصم المبلغ من البطاقة مرتين، أو إرسال البريد مرة أخرى.

لذلك القاعدة في 2026 بسيطة: دع النموذج يضمن الشكل، ودع الكود الخاص بك يضمن المعنى.

صمّم أدوات يستطيع النموذج استخدامها جيداً

الموثوقية تبدأ قبل تشغيل أي كود. توثيق Anthropic لاستخدام الأدوات يعتبر الوصف أهم عامل في أداء الأداة، ويوصي بثلاث أو أربع جمل على الأقل لكل أداة. قواعد عملية:

  • اذكر ماذا تفعل الأداة، ومتى تُستخدم، ومتى لا تُستخدم. "تنشئ حجزاً مؤكداً. استخدمها فقط بعد موافقة العميل على تاريخ ووقت محددين. لا تستخدمها للتحقق من المواعيد المتاحة؛ استخدم check_availability لذلك."
  • صِف كل معامل (parameter)، بما في ذلك صيغته (تاريخ ISO، عملة، نمط الرقم التعريفي) ومن أين يجب أن تأتي قيمته ("الرقم الذي تعيده find_customer").
  • أعطِ أمثلة. أدوات Anthropic تقبل input_examples: بضعة مدخلات صحيحة توضح للنموذج أي الحقول الاختيارية يضيف، وكيف تبدو الكائنات المتداخلة.
  • اجمع ما يمكن جمعه. أداة واحدة بمعامل action غالباً أوضح من خمس أدوات متشابهة، وكلما قلّت الأدوات قلّت الاختيارات الخاطئة.
  • أعِد أقل، لكن أفضل. أعِد الحقول التي يحتاجها النموذج مع أرقام تعريفية ثابتة، لا صف قاعدة البيانات كاملاً. كل حقل إضافي سياق إضافي يجب على النموذج قراءته.

تفصيل مهم في 2026: في أحدث نماذج Anthropic ‏(Claude Opus 5.5 وSonnet 5.5 وFable 5.1 وMythos 5.1)، قيم tool_choice التي تُجبر النموذج على أداة (any أو tool باسم محدد) غير مدعومة وتعيد خطأ. والتوثيق يوصي باستخدام auto مع الاستخدام الصارم للأدوات بدلاً منها. إذا كنت تحدّث وكيلاً قديماً كان يُجبر استدعاء الأدوات، فتحقق من هذا أولاً.

طبقة التنفيذ: أربع مهام

بين استدعاء النموذج للأداة ونظامك الحقيقي، ضع طبقة رفيعة تقوم بأربعة أشياء:

  • 1. التحقق من المعنى. افحص القواعد التي لا يستطيع المخطط التعبير عنها: الرقم التعريفي موجود، والتاريخ في المستقبل، والمبلغ ضمن الحدود، والمستخدم مسموح له بهذا الإجراء.
  • 2. جعل الإجراءات غير قابلة للتكرار (idempotent). أعطِ كل عملية كتابة مفتاحاً، بحيث ينتج الطلب نفسه مرتين نتيجة واحدة. النموذج سيعيد المحاولة، أحياناً بعد انتهاء مهلة كانت المحاولة الأولى فيها قد نجحت فعلاً.
  • 3. إعادة المحاولة فقط للأخطاء المؤقتة. انتهاء المهلة وأخطاء 503 تستحق بضع محاولات مع انتظار يتضاعف تدريجياً. أما أخطاء التحقق فلا: إعادة الإدخال الخاطئ نفسه تعطي الجواب نفسه.
  • 4. إعادة أخطاء مفيدة. أعِد حالات الفشل كنتيجة أداة مع is_error: true ورسالة تقول ما الخطأ وماذا يفعل بعد ذلك. ويذكر توثيق Anthropic أن Claude يعيد المحاولة عادةً مرتين أو ثلاثاً مع تصحيحات حين يحصل على خطأ واضح، قبل أن يخبر المستخدم.

مثال مُختبر

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

"""A reliable tool-execution layer for an AI agent (no API key needed).
The model's tool calls are scripted below so the run is reproducible.
Structured outputs guarantee the SHAPE of a call; this layer checks the
MEANING, makes retries safe, and turns failures into useful tool_results.
"""
import datetime as dt, hashlib, json, random, time

TODAY = dt.date(2026, 10, 7)
CUSTOMERS = {"C-1001": "Mariam", "C-1002": "Omar"}
BOOKINGS = {}                      # booking_id -> booking
random.seed(7)

class Transient(Exception):        # e.g. timeout or HTTP 503
    pass

def flaky_calendar_api(payload):
    """Pretend calendar service: fails 50% of the time, like a bad day."""
    if random.random() < 0.5:
        raise Transient("calendar service timeout")
    return {"ok": True}

# --- 1. Semantic validation: rules a JSON schema can't express ------------
def validate(args):
    errors = []
    if args["customer_id"] not in CUSTOMERS:
        errors.append(f"customer_id {args['customer_id']} does not exist; "
                      "call find_customer first to get a valid id")
    day = dt.date.fromisoformat(args["date"])
    if day < TODAY:
        errors.append(f"date {args['date']} is in the past; today is {TODAY}")
    if not 1 <= args["party_size"] <= 8:
        errors.append("party_size must be between 1 and 8; "
                      "for larger groups, hand off to a person")
    return errors

# --- 2. Idempotency: the same request never books twice -------------------
def idempotency_key(args):
    raw = json.dumps(args, sort_keys=True).encode()
    return "bk_" + hashlib.sha256(raw).hexdigest()[:10]

# --- 3. Retries with backoff, only for transient errors ------------------
def with_retries(fn, payload, attempts=4, base=0.05):
    for i in range(1, attempts + 1):
        try:
            return fn(payload), i
        except Transient as e:
            if i == attempts:
                raise
            time.sleep(base * 2 ** (i - 1))      # 0.05s, 0.1s, 0.2s ...

def create_booking(args):
    errors = validate(args)
    if errors:
        return {"is_error": True, "content": "Invalid request: " + " | ".join(errors)}
    key = idempotency_key(args)
    if key in BOOKINGS:
        return {"is_error": False, "content": f"Already booked as {key} (no duplicate created)"}
    try:
        _, tries = with_retries(flaky_calendar_api, args)
    except Transient:
        return {"is_error": True, "content": "Calendar unavailable after 4 attempts. "
                "Tell the customer you'll confirm by message; do not retry now."}
    BOOKINGS[key] = args
    return {"is_error": False, "content": f"Booked {key} for {CUSTOMERS[args['customer_id']]} "
            f"on {args['date']} (calendar attempts: {tries})"}

# --- Scripted tool calls (all of them pass a strict JSON schema) ----------
calls = [
    ("valid booking",        {"customer_id": "C-1001", "date": "2026-10-12", "party_size": 2}),
    ("model retries same",   {"customer_id": "C-1001", "date": "2026-10-12", "party_size": 2}),
    ("invented customer id", {"customer_id": "C-9999", "date": "2026-10-12", "party_size": 2}),
    ("date in the past",     {"customer_id": "C-1002", "date": "2026-09-30", "party_size": 3}),
    ("negative party size",  {"customer_id": "C-1002", "date": "2026-10-15", "party_size": -4}),
]
for label, args in calls:
    r = create_booking(args)
    print(f"{label:21} is_error={str(r['is_error']):5} {r['content']}")
print(f"\nbookings stored: {len(BOOKINGS)}")

النتيجة، عند التشغيل بتاريخ 2026-10-07:

valid booking         is_error=False Booked bk_63413a6eac for Mariam on 2026-10-12 (calendar attempts: 3)
model retries same    is_error=False Already booked as bk_63413a6eac (no duplicate created)
invented customer id  is_error=True  Invalid request: customer_id C-9999 does not exist; call find_customer first to get a valid id
date in the past      is_error=True  Invalid request: date 2026-09-30 is in the past; today is 2026-10-07
negative party size   is_error=True  Invalid request: party_size must be between 1 and 8; for larger groups, hand off to a person

bookings stored: 1

ماذا حدث:

  • الحجز الصحيح نجا من خدمة غير مستقرة. انتهت مهلة التقويم مرتين، ونجحت المحاولة الثالثة بفضل إعادة المحاولة مع الانتظار المتزايد، دون أن يرى النموذج حالات الفشل أصلاً.
  • إعادة النموذج للمحاولة لم تحجز مرتين. الطلب نفسه أعاد الحجز الموجود. بدون مفتاح منع التكرار، كان سيوجد حجزان وعميل منزعج.
  • ثلاثة استدعاءات سليمة الشكل رُفضت بسبب المعنى: رقم عميل مختلَق، وتاريخ مضى، وعدد أشخاص سالب (قاعدة نطاق لا يطبقها الوضع الصارم). وكل خطأ يخبر النموذج بالضبط كيف يتعافى: ابحث عن العميل، أو استخدم تاريخاً مستقبلياً، أو حوّل المحادثة إلى شخص.
  • حُفظ حجز واحد فقط، وهو العدد الصحيح الوحيد.

في بيئة العمل الحقيقية، ولّد مفتاح منع التكرار من رقم طلب ينشئه تطبيقك مرة واحدة لكل إجراء من المستخدم، لا من المدخلات وحدها، حتى لا يُدمج حجزان منفصلان فعلاً بالتفاصيل نفسها. ومزوّدو الدفع مثل Stripe يستخدمون الفكرة نفسها عبر ترويسة مفتاح منع التكرار (idempotency key).

أخطاء يستطيع النموذج الاستفادة منها

قارن بين نتيجتي أداة للفشل نفسه:

"Error"

"customer_id C-9999 does not exist; call find_customer first to get a valid id"

الأولى تترك النموذج يخمّن، فقد يعتذر، أو يختلق رقماً آخر، أو يستسلم. والثانية تحدد المشكلة والخطوة التالية. رسائل الخطأ الجيدة تشترك في ثلاث صفات: تقول ما الذي فشل، ولماذا، وماذا يفعل الآن (بما في ذلك "لا تُعِد المحاولة؛ أخبر المستخدم" حين يكون هذا هو الصواب). ولا تضع أبداً تفاصيل أخطاء البرمجة الداخلية، أو أسماء الخوادم، أو الأسرار في نتيجة أداة: كل ما تعيده يصبح جزءاً من المحادثة.

ضوابط للأدوات التي تغيّر الأشياء

  • افصل أدوات القراءة عن أدوات الكتابة. قراءة المواعيد المتاحة آمنة حتى لو استُدعيت كثيراً، أما إنشاء حجز فلا. الأدوات المنفصلة تجعل الصلاحيات المختلفة سهلة.
  • موافقة بشرية على الإجراءات غير القابلة للتراجع أو المكلفة: المدفوعات، والمبالغ المستردة، والإلغاءات، والرسائل لعدد كبير من الناس.
  • الحدود في الكود، لا في التعليمات. عبارة "لا تسترد أكثر من 500 درهم أبداً" في تعليمات النظام طلب، أما القاعدة نفسها في طبقة التنفيذ فضمان.
  • تعامل مع مدخلات الأدوات كمدخلات غير موثوقة. النص الذي قرأه النموذج من بريد أو صفحة ويب قد يوجّهه. الصلاحيات والتحقق في الكود هي ما يجعل الاستدعاء المتلاعَب به غير ضار. (راجع أمان وكلاء الذكاء الاصطناعي وحقن الأوامر.)
  • سجّل كل استدعاء: المدخلات، ونتيجة التحقق، وعدد المحاولات، والنتيجة النهائية. حين يحدث خطأ، السجل هو طريقتك لمعرفة السبب.

اختبره قبل الإطلاق

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

الخلاصة

الاستخدام الصارم للأدوات والمخرجات المنظمة أزالا أكثر أنواع أخطاء الوكلاء إزعاجاً: JSON المكسور والحقول الناقصة. فعّلهما. ثم أضف الجزء الذي لا يستطيع أي مزوّد القيام به نيابة عنك: تحقق من أن القيم منطقية، واجعل كل عملية كتابة آمنة عند التكرار، وأعِد المحاولة فقط لما هو مؤقت، وأعِد أخطاء تخبر النموذج كيف يتعافى. هذه الطبقة الرفيعة هي الفرق بين وكيل يبدو جيداً في العرض، ووكيل تستطيع تركه يعمل.

المصادر: توثيق Anthropic عن المخرجات المنظمة، والاستخدام الصارم للأدوات، وتعريف الأدوات، والتعامل مع نتائج الأدوات (راجعناه في أكتوبر 2026)؛ OpenAI، "Introducing Structured Outputs in the API" ‏(6 أغسطس 2024)؛ توثيق Stripe عن الطلبات غير القابلة للتكرار (idempotent requests). المثال مستقل بذاته ويستخدم استدعاءات أدوات مكتوبة مسبقاً.

مقالات ذات صلة