الأدوات كواجهة
درس 2 من 6
2الأدوات كواجهة
الصورة الكبيرةالنموذج لا يرى كود أداتك. يرى اسمها ووصفها ومخطّط معاملاتها فقط، ومنها يقرّر متى يستدعيها وبماذا. الوصف هو الواجهة. أداة اسمها tool1 ووصفها «يجلب بيانات» تكسر الوكيل أكثر من نموذج أضعف، وأداة برسائل خطأ واضحة تجعله يصحّح نفسه.
ماذا تشاهد في الرسم: الطلب يمرّ أولًا على اسم الأداة ووصفها، فهما كل ما يختار به النموذج. لهذا ذهب سؤال موعد التوصيل إلى tool2 مع الأوصاف الغامضة، وإلى get_order_status مع الأوصاف الواضحة.
خارطة هذا الجزء
المفاهيم بالترتيب، اضغط أيًّا منها للقفز إليه:
طريقان إلى نفس الفكرة
الأداة بالنسبة للنموذج زر مكتوب عليه اسم وشرح قصير. لا يرى ما خلف الزر، بل يقرأ الملصق فقط. لو كتبت على الزر «افعل» دون شرح، سيضغطه في الوقت الخطأ. الملصق الواضح أهم من ذكاء النموذج نفسه.
تعريف الأداة اسم ووصف ومخطط معاملات JSON Schema. الوصف يذكر متى تُستخدم ومتى لا، وما تعيده، وأخطاءها الممكنة. الأدوات القليلة المحددة أفضل من كثيرة متداخلة، والأخطاء تُعاد للنموذج نصًا مفهومًا يستطيع أن يصحح منه.
قبل أن تبدأ
🤔متى يستحق الوكيل
تعرف أن كل أداة إضافية تكبّر السياق في كل خطوة، وأن الأقل يكفي غالبًا.
🧾مخطّط JSON
رأيت مخرجات منظّمة بمخطّط JSON يحدّد الحقول وأنواعها والمطلوب منها.
الفكرة الجوهرية
النموذج لا يرى كود أداتك، بل يرى اسمها ووصفها ومخطّط معاملاتها. في هذا الدرس تبني الثلاثة جيدًا، ثم تكتب رسائل خطأ يفهمها النموذج.
1الوصف هو الواجهة
النموذج يختار الأداة من كلماتها فقط. اسم مثل tool1 ووصف مثل «يجلب بيانات» لا يقولان له شيئًا، فيختار شبه عشوائيًّا.
في المثال، «نموذج» بسيط يختار الأداة التي تشترك مع الطلب في أكثر الكلمات. هذا تبسيط، لكن النماذج الحقيقية تعتمد على الوصف بنفس الطريقة.
def pick_tool(request, tools):
"""Stand-in for the model: picks the tool whose name and description share most words with the request."""
words = set(request.lower().replace("?", "").split())
def overlap(t):
return len(words & set((t["name"].replace("_", " ") + " " + t["description"]).lower().split()))
return max(tools, key=overlap)["name"]
vague = [
{"name": "tool1", "description": "Gets data."},
{"name": "tool2", "description": "Handles records from the system."},
]
clear = [
{"name": "get_order_status", "description": "Look up the shipping status and delivery date of a customer order by its order number."},
{"name": "search_help_articles", "description": "Search help centre articles for how-to questions, like resetting a password or changing an address."},
]
requests = ["what is the delivery date of my order?", "how do I reset my password?"]
for r in requests:
print(f"{r}\n vague tools -> {pick_tool(r, vague)} clear tools -> {pick_tool(r, clear)}")
مع الأدوات الغامضة، الاختيار عشوائي عمليًّا: tool2 اختيرت لسؤال التوصيل فقط لأن وصفها يحتوي «the». مع الأسماء والأوصاف الواضحة، كل طلب ذهب لأداته. الوصف الجيد يقول ماذا تفعل الأداة، ومتى تُستخدم، وبمثال على الطلب الذي يناسبها.
search_docs وfind_documents. النموذج لا يعرف الفرق لأنك لم تكتبه، فيختار عشوائيًّا. ادمجهما، أو اكتب في وصف كل منهما متى تُستخدم بدل الأخرى.2المخطّط والقيم الافتراضية
تعريف الأداة ثلاثة أجزاء: اسم بفعل ومفعول، ووصف يقول ماذا ومتى ومتى لا، ومخطّط JSON لمعاملاتها. النموذج يملأ المخطّط، وكودك يتحقّق منه قبل التنفيذ.
get_order_status = {
"name": "get_order_status",
"description": (
"Look up the shipping status and expected delivery date of one customer order. "
"Use it when the user asks where an order is or when it will arrive. "
"Do not use it for refunds; use get_refund_policy for that. "
"Example: 'where is my order 48213?' -> order_id='48213'."
),
"input_schema": {
"type": "object",
"properties": {
"order_id": {"type": "string", "description": "The 5-digit number on the receipt, digits only."},
"include_history": {"type": "boolean", "default": False,
"description": "Also return every tracking event. Rarely needed."},
},
"required": ["order_id"],
},
}
الوصف يقول ماذا ومتى ومتى لا، ويحيل إلى الأداة البديلة، ويعطي مثالًا. ومعامل واحد مطلوب، والثاني اختياري بقيمة افتراضية ووصف يقول إنه نادرًا ما يلزم. أسماء الحقول تختلف قليلًا بين المزوّدين (input_schema أو parameters)، والمحتوى نفسه.
انظر إلى الرسم: الوصف أوسع جزء، لأنه أهم سطر تكتبه لوكيل. وكل معامل اختياري بقيمة افتراضية معقولة يقلّل ما يجب أن يقرّره النموذج، ويقلّل أخطاءه.
3رسائل خطأ يفهمها النموذج
النموذج يقرأ نتيجة الأداة، بما فيها الخطأ. الاستثناء الخام يتركه يتخبّط، والخطأ الذي يقول ما حدث وما الخطوة التالية يجعله يصحّح نفسه.
انظر إلى الرسم: الأداة تعيد خطأً واضحًا، فيسأل النموذج المستخدم عن الرقم الصحيح، ثم يستدعي الأداة من جديد.
نسختان من نفس الأداة. الأولى تنهار عند أي مدخل غير متوقّع، والثانية تنظّف المدخل وتشرح الخطأ.
import json
ORDERS = {"48213": "shipped"}
def get_order_status_bad(order_id):
return ORDERS[order_id] # raises KeyError: the model sees a stack trace
def get_order_status(order_id, include_history=False):
order_id = str(order_id).strip().lstrip("#")
if not order_id.isdigit() or len(order_id) != 5:
return {"error": f"order_id must be 5 digits, got {order_id!r}. Ask the user for the number on their receipt."}
if order_id not in ORDERS:
return {"error": f"No order {order_id}. Check the number with the user; do not guess another one."}
return {"order_id": order_id, "status": ORDERS[order_id]}
for arg in ["#48213", "4821", "99999"]:
try:
print("bad: ", get_order_status_bad(arg))
except Exception as e:
print("bad: crashed with", type(e).__name__, e)
print("good:", json.dumps(get_order_status(arg)))
النسخة السيئة انهارت حتى مع #48213، وهو رقم صحيح بعلامة # يكتبها الناس كثيرًا. النسخة الجيدة نظّفته ونجحت، وحين كان الرقم قصيرًا قالت للنموذج ماذا يطلب من المستخدم، وحين لم يوجد قالت «لا تخمّن رقمًا آخر». هذه الجملة الأخيرة تمنع سلوكًا حقيقيًّا: نماذج تجرّب أرقامًا قريبة حتى تجد شيئًا.
كيف يعمل، خطوة بخطوة: كيف يستدعي النموذج أداتك
يصل للنموذج اسم كل أداة ووصفها ومخطّط معاملاتها، لا كودها.
يختار الأداة التي يناسب وصفها الطلب، ويملأ معاملاتها بحسب المخطّط.
كودك ينظّف المعاملات ويتحقّق منها قبل التنفيذ، مثل حذف # من رقم الطلب.
تعود النتيجة أو رسالة خطأ تقول ما الخطأ وما الخطوة التالية، فيقرؤها النموذج ويقرّر.
أعمق قليلًا
وأعد من الأداة ما يحتاجه النموذج فقط. رد بخمسين حقلًا من قاعدة البيانات يملأ السياق بأرقام داخلية ومعرّفات لا معنى لها، ويكرّر في كل خطوة لاحقة. اختر الحقول التي تحضر، وأضف معامل detail اختياري لمن يحتاج أكثر.
مثال محلول
لنرَ ذلك مباشرة. «النموذج» هنا يختار الأداة التي تشترك كلماتها مع الطلب أكثر، وهذا تبسيط، لكن النماذج الحقيقية تعتمد على الوصف بنفس الطريقة في جوهرها.
جرّب بلا كود
get_weather، «تعيد درجة الحرارة وحالة الطقس اليوم لمدينة باسمها. استخدمها حين يسأل المستخدم عن الطقس، مثال: city='Riyadh'».خرافة مقابل حقيقة
| الخرافة | الحقيقة |
|---|---|
| النموذج يفهم ما تفعله الأداة من كودها. | لا يرى الكود أبدًا. الاسم والوصف والمخطّط هي الواجهة كلها. |
| إعادة كل الحقول أفضل، فالنموذج يختار منها ما يحتاج. | كل ما تعيده الأداة يبقى في التاريخ ويُعاد إرساله في كل خطوة، فيضيف تكلفة وتشتيتًا. |
| رسالة الخطأ للمطوّر فقط. | النموذج يقرأ نتيجة الأداة، فرسالة الخطأ تعليمات للخطوة التالية. خطأ واضح يجعله يصحّح نفسه. |
جرّب بنفسك
أداتك تعيد 50 حقلًا من قاعدة البيانات في كل استدعاء. ما المشكلة؟
كل ما تعيده الأداة يصير جزءًا من التاريخ. أعد ما يجيب عن السؤال الشائع، ووفّر معاملًا لمن يحتاج التفاصيل.
ما أفضل رد من أداة حين لا يوجد الطلب المطلوب؟
رسالة الخطأ تعليمات للخطوة التالية. أقرب طلب موجود أخطر خيار: قد يعطي المستخدم معلومات طلب شخص آخر.
بطاقات مراجعة سريعة
تحقق من فهمك
الوكيل يستدعي search_orders بنص السؤال كاملًا بدل رقم الطلب. أين المشكلة غالبًا؟
في الأداة لا في النموذج: الاسم يوحي ببحث نصّي حر، ووصف المعامل لا يقول «الرقم فقط» ولا يعطي مثالًا. أعد التسمية إلى get_order_status(order_id)، واكتب في وصف المعامل الشكل المطلوب بمثال، واجعل الأداة ترفض النص الحر برسالة تشرح الشكل الصحيح.
عندك ثلاث أدوات: get_customer وget_orders وget_shipments، وأغلب الأسئلة «أين طلبي؟». ما الذي تغيّره؟
تصمّم أداة حول مهمة المستخدم، مثل get_order_status(order_id)، تعيد ما يحتاجه السؤال الشائع مباشرة، فيوفّر الوكيل خطوتين وفرصتين للخطأ.
مصادر هذا الدرس
مرتّبة بالنوع. ابدأ بالتوثيق الرسمي إذا تبي المرجع الدقيق، وبالمقال أو الفيديو إذا تبي الشرح أولًا.
خلّصت الدرس؟
سجّل الدخول ليُحفظ تقدّمك.