الأدوات والموارد والتعليمات

أنماط الأدوات المتقدمة

5 دقيقة للقراءة

الأنماط التالية تجيب كلها عن سؤال واحد بصيغ مختلفة: كم من العمل ينبغي أن يجري داخل نداء أداة واحد، وكم منه يُترك للنموذج ينظّمه بنفسه؟

تركيب الأدوات

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

أداتان دقيقتان مقابل أداة واحدة مركّبة

دقيقةمركّبة«لخّص ما نعرفه عن سياسة ا…طلب واحد من المستخدمsearch_documentsالدور الأول: النموذج يستدعي ويق…النموذج يختار خمساًالدور الثاني: يستهلك سياقاً ليق…summarizeالدور الثالث: يلخّص أخيراًsearch_and_summarizeنداء واحد. الترتيب والاقتطاع يج…الإجابة

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

@mcp.tool()
async def search_and_summarize(query: str, max_results: int = 5) -> str:
    """البحث في المستندات وإرجاع ملخص لأفضل النتائج المطابقة."""
    results = await search_documents(query)
    return await generate_summary(results[:max_results])

القيمة الافتراضية موجودة في توقيع الدالة، فتظهر في المخطط المُولَّد وتُطبَّق حين يُغفل النموذج الوسيط. أما كتابة القيمة الافتراضية مرتين — مرة في المخطط ومرة في استدعاء .get(..., 5) — فهي الطريقة التي تفترق بها النسختان.

الإبلاغ عن التقدم في العمليات الطويلة

استدعاء الأداة يُرجع نتيجة واحدة فقط. لا يمكنك استخدام yield لإخراج نتائج جزئية من أداة — فالمولِّد غير المتزامن ليس قيمة إرجاع صالحة، والاستدعاء يفشل عند التحقق. لكن ما يمكنك فعله هو إرسال إشعارات تقدم بينما الاستدعاء الواحد ما يزال مفتوحاً:

from mcp.server.mcpserver import Context


@mcp.tool()
async def analyze_large_dataset(data: str, ctx: Context) -> str:
    """تحليل مجموعة بيانات على دفعات."""
    batches = await plan_batches(data)
    results = []

    for i, batch in enumerate(batches, start=1):
        results.append(await process(batch))
        await ctx.report_progress(
            progress=i,
            total=len(batches),
            message=f"تمت معالجة الدفعة {i} من {len(batches)}",
        )

    return json.dumps(results)

تفصيلان يستحقان الحفظ:

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

الإجراءات القابلة للتأكيد

للعمليات الخطرة، اطلب التأكيد:

@mcp.tool()
async def delete_all_files(directory: str, confirm: bool) -> str:
    """حذف كل ملف في مجلد. إجراء مدمر — لا يمكن التراجع عنه.

    اضبط confirm=true فقط بعد أن يوافق المستخدم صراحةً على هذا المجلد بعينه.
    """
    if not confirm:
        return "الإجراء غير مؤكد. اطلب من المستخدم تأكيد المجلد ثم أعد المحاولة بـ confirm=true."
    count = await delete_files(directory)
    return f"تم حذف {count} ملفاً من {directory}"

لاحظ أين وُضِعت التعليمات: في نص التوثيق، لأنه ما يقرأه النموذج قبل أن يقرر. وعلامة confirm التي يستطيع النموذج ضبطها بنفسه مطبٌّ للسرعة لا ضمانة؛ فالحماية الحقيقية هي أن يسأل المضيف إنساناً، وهذا ما وُجدت من أجله تعليقات الأدوات التوضيحية وآلية الموافقة في المضيف نفسه. اعتبر هذا النمط وسيلة لجعل الخطوة المدمرة مرئية، لا وسيلة للتفويض.

تبعيات الأدوات

بناء أدوات تعتمد على أدوات أخرى:

class ToolRegistry:
    def __init__(self):
        self.tools = {}

    def register(self, name, handler):
        self.tools[name] = handler

    async def call(self, name, arguments):
        return await self.tools[name](arguments)

registry = ToolRegistry()

async def get_user_handler(args):
    return await db.get_user(args["id"])

async def get_user_orders_handler(args):
    # يعتمد على get_user
    user = await registry.call("get_user", {"id": args["user_id"]})
    return await db.get_orders(user["id"])

registry.register("get_user", get_user_handler)
registry.register("get_user_orders", get_user_orders_handler)

في القسم التالي، سنستكشف أنماط الموارد المتقدمة. :::

اختبار

اختبار الوحدة 3: الأدوات والموارد والتعليمات

خذ الاختبار
هل كان هذا الدرس مفيدًا؟

سجّل الدخول للتقييم