اجرای ابزار در ایجنت جایی است که حرف به عمل تبدیل میشود. اما یک نکته را فراموش نکنید: وقتی مدل نام یک تابع را تولید میکند، هنوز هیچ کار واقعی انجام نشده است. برنامه باید ورودی را بررسی کند، ابزار درست را اجرا کند و نتیجه یا خطا را به شکلی قابلفهم برگرداند.
در قسمتهای قبل دیدیم function calling چطور کار میکند و ابزار را چطور تعریف کنیم. در این قسمت از مجموعهی آموزش هوش مصنوعی تخته سبز، همان مسیر را از نگاه قابلیت اطمینان بررسی میکنیم. فاصلهی میان «مدل گفت این ابزار را اجرا کن» و «ابزار درست و امن اجرا شد» دقیقاً همان جایی است که بیشتر ایجنتها شکست میخورند.
الگوی طراحی استفاده از ابزار
الگوی استفاده از ابزار (Tool Use) به مدل زبانی توانایی تعامل با ابزارهای بیرونی را برای رسیدن به هدف میدهد. ابزارها کدهاییاند که ایجنت اجرا میکند. میتوانند یک تابع ساده مثل ماشینحساب باشند یا فراخوانی API یک سرویس بیرونی، مثل استعلام قیمت یا وضعیت هوا.
کاربردهای رایج
این الگو در سناریوهای مختلفی به کار میرود:
- بازیابی اطلاعات زنده: پرسوجو از API یا پایگاه داده برای گرفتن دادهی بهروز.
- اجرا و تفسیر کد: حل مسئلهی ریاضی، تولید گزارش یا شبیهسازی.
- خودکارسازی گردش کار: ترکیب زمانبند، سرویس ایمیل و خط لولهی داده.
- پشتیبانی مشتری: کار با سیستم مدیریت مشتری، سامانهی تیکت و پایگاه دانش.
- تولید و ویرایش محتوا: بررسی دستور زبان، خلاصهسازی یا ارزیابی ایمنی محتوا.
در همهی این موارد، ایجنت کاری انجام میدهد که پیامد واقعی دارد. پس کیفیت اجرای ابزار مستقیم روی اعتماد کاربر اثر میگذارد.
شش جزء لازم برای پیادهسازی
برای پیادهسازی این الگو شش جزء لازم است. طرحوارهی ابزار تعریف دقیق نام، هدف، پارامترها و خروجی مورد انتظار است. منطق اجرا تعیین میکند کی و چطور ابزار بر اساس نیت کاربر استفاده شود. سیستم مدیریت پیام جریان میان ورودی کاربر، پاسخ مدل، فراخوانی ابزار و خروجی آن را مدیریت میکند.
سه جزء دیگر به قابلیت اطمینان مربوطاند. چارچوب یکپارچهسازی ایجنت را به ابزارها وصل میکند. مدیریت خطا و اعتبارسنجی با شکست اجرا، پارامتر نامعتبر و پاسخ غیرمنتظره روبهرو میشود. مدیریت وضعیت هم زمینهی گفتوگو و تعاملهای قبلی با ابزارها را نگه میدارد. این مقاله بیشتر روی همین سه جزء آخر تمرکز دارد.
خط لولهی اجرای امن ابزار
اجرای ابزار را بهتر است به شکل یک خط لوله دید، نه یک فراخوانی ساده. هر مرحله یک بررسی دارد که اگر شکست بخورد، اجرا متوقف میشود و خطای روشنی برمیگردد. نمودار زیر این خط لوله را نشان میدهد.

اعتبارسنجی نام و آرگومان
اولین بررسی ساده است: آیا ابزاری که مدل خواسته، در فهرست ابزارهای مجاز هست؟ مدل گاهی نام ابزاری را میسازد که وجود ندارد. بررسی دوم، اعتبار آرگومانهاست. مدل ممکن است عدد را بهصورت متن بفرستد، پارامتر اجباری را جا بیندازد یا مقداری خارج از محدوده بدهد.
بهترین راه، تعریف طرحوارهی دقیق برای ورودی هر ابزار است. در پایتون کتابخانهی Pydantic این کار را ساده میکند. همان طرحواره هم برای ساخت توضیح ابزار برای مدل استفاده میشود و هم برای بررسی ورودی پیش از اجرا.
قرارداد خطا
ابزار باید در صورت شکست، خطایی ساختاریافته برگرداند؛ نه یک استثنای خام که برنامه را متوقف کند، و نه نتیجهای ساختگی. خطای خوب سه چیز دارد: نوع خطا، توضیح کوتاه و اینکه آیا تلاش دوباره فایده دارد یا نه.
با این قرارداد، مدل میتواند واکنش درستی نشان دهد. اگر شناسهی دوره اشتباه بود، از کاربر شناسهی درست را میپرسد. اگر سرویس موقتاً قطع بود، دوباره تلاش میکند یا صادقانه میگوید اطلاعات در دسترس نیست.
پیادهسازی ابزار قابلاعتماد با پایتون
حالا یک ابزار خواندن اطلاعات دوره میسازیم که همهی این اصول را رعایت میکند. این ابزار شناسهی دوره را اعتبارسنجی میکند، از پایگاه داده بهصورت فقطخواندنی میخواند، خطای روشن برمیگرداند و هر اجرا را ثبت میکند.
تعریف ورودی و اجرای محدود
کد زیر ورودی را با Pydantic تعریف میکند و پایگاه دادهی SQLite را در حالت فقطخواندنی باز میکند:
import json, logging, sqlite3, time
from pydantic import BaseModel, Field, ValidationError
log = logging.getLogger("tools")
class CourseQuery(BaseModel):
course_id: str = Field(pattern=r"^[A-Z]{2,4}-\d{3}$", description="شناسهی دوره، مثل PY-101")
def get_course(args: dict) -> dict:
started = time.perf_counter()
try:
query = CourseQuery(**args)
except ValidationError as e:
return {"ok": False, "error": "invalid_input", "detail": e.errors()[0]["msg"], "retry": False}
try:
db = sqlite3.connect("file:courses.db?mode=ro", uri=True, timeout=5)
row = db.execute("SELECT title, level, weeks FROM courses WHERE id = ?", (query.course_id,)).fetchone()
except sqlite3.OperationalError as e:
return {"ok": False, "error": "unavailable", "detail": str(e), "retry": True}
finally:
log.info(json.dumps({"tool": "get_course", "args": args, "ms": round((time.perf_counter() - started) * 1000)}))
if row is None:
return {"ok": False, "error": "not_found", "detail": f"دورهای با شناسهی {query.course_id} نیست", "retry": False}
return {"ok": True, "course": {"title": row[0], "level": row[1], "weeks": row[2]}}به سه نکته دقت کنید. پرسوجو پارامتری است و شناسه هرگز مستقیم در متن SQL قرار نمیگیرد. اتصال در حالت mode=ro باز میشود و امکان نوشتن ندارد. و هر اجرا، چه موفق چه ناموفق، با آرگومانها و زمان اجرا ثبت میشود.
اتصال به حلقهی ایجنت
در حلقهی ایجنت، بهجای اجرای مستقیم تابع، از یک دیکشنری ابزارهای مجاز استفاده میکنیم. اگر نام ابزار در این دیکشنری نباشد، خطای روشن برمیگردد:
TOOLS = {"get_course": get_course}
def run_tool(name: str, raw_arguments: str) -> str:
if name not in TOOLS:
return json.dumps({"ok": False, "error": "unknown_tool", "detail": name, "retry": False})
try:
args = json.loads(raw_arguments)
except json.JSONDecodeError:
return json.dumps({"ok": False, "error": "bad_json", "retry": False})
return json.dumps(TOOLS[name](args), ensure_ascii=False)خروجی run_tool همیشه یک JSON است؛ چه موفق و چه ناموفق. همین یکنواختی کار مدل را برای فهم نتیجه ساده میکند و در لاگ هم بهراحتی قابل جستجوست.
امنیت ابزارهای پایگاه داده
یکی از نگرانیهای رایج، اجازه دادن به مدل برای ساختن SQL است. خطر تزریق SQL یا اقدام مخرب، مثل حذف یا تغییر داده، واقعی است. این نگرانی درست است، اما با پیکربندی درست دسترسی قابل مدیریت است.
دسترسی فقطخواندنی و محیط امن
بیشتر پایگاههای داده اجازه میدهند اتصال در حالت فقطخواندنی باشد. سرویسهایی مثل PostgreSQL و Azure SQL میتوانند به برنامه نقش فقطخواندنی بدهند. SQLite را هم، همانطور که در کد دیدید، میتوان فقطخواندنی باز کرد.
اجرای برنامه در محیط امن هم لایهی دیگری از حفاظت است. در سازمانها معمولاً داده از سیستمهای عملیاتی استخراج و به یک پایگاه داده یا انبار دادهی فقطخواندنی با طرحوارهی ساده منتقل میشود. ایجنت فقط به همین نسخه دسترسی دارد و هرگز به سیستم اصلی نمیرسد.
ابزار پارامتری بهجای SQL آزاد
امنترین راه این است که اصلاً به مدل اجازهی نوشتن SQL آزاد ندهید. بهجایش ابزارهای پارامتری بسازید؛ مثل get_course(course_id) یا search_courses(level, topic). مدل فقط پارامتر میدهد و پرسوجو را کد شما میسازد.
این رویکرد انعطاف کمتری دارد، اما برای بیشتر دستیارهای کاربردی کافی است. SQL آزاد را فقط برای ابزارهای تحلیلی داخلی، با دسترسی فقطخواندنی و محدودیت زمان اجرا، نگه دارید. جدول زیر خطاهای رایج و واکنش درست به هر کدام را نشان میدهد.
| نوع خطا | علت نمونه | واکنش درست ایجنت |
|---|---|---|
| ابزار ناشناخته | مدل نام ابزاری را ساخته | انتخاب دوباره از فهرست مجاز |
| ورودی نامعتبر | شناسه با قالب اشتباه | پرسیدن شناسهی درست از کاربر |
| پیدا نشدن | دورهای با این شناسه نیست | اعلام صادقانه و پیشنهاد جستجو |
| سرویس در دسترس نیست | قطعی موقت پایگاه داده | تلاش دوباره با فاصله یا اعلام موقت |
| زمان اجرا تمام شد | پرسوجوی سنگین | کوچک کردن درخواست یا اعلام محدودیت |
ابزار در فریمورکهای ایجنت
فریمورکهای ایجنت بخشی از این کار را آماده دارند. در Microsoft Agent Framework، تابع پایتون با توضیح و نوع ورودی بهعنوان ابزار ثبت میشود و فریمورک خودش فراخوانی را مدیریت میکند. در Foundry Agent Service هم ابزارهایی مثل مفسر کد و توابع ابری آمادهاند و میتوان آنها را با ابزارهای اختصاصی در یک مجموعه ترکیب کرد.
اما فریمورک جای قرارداد خطا و اعتبارسنجی را نمیگیرد. فریمورک ابزار را صدا میزند؛ اینکه ابزار با ورودی بد یا سرویس قطع چه رفتاری دارد، همچنان مسئولیت کد شماست.
سناریوی عملی؛ خواندن اطلاعات دوره
ایجنت باید جزئیات یک دوره را از پایگاه داده بخواند و برای کاربر خلاصه کند. ورودی آزمون سه بخش دارد: شناسهی دوره، سطح دسترسی کاربر و درخواست او. یک نمونهی عادی و چند نمونهی مشکلدار آماده کنید؛ شناسهی نامعتبر، شناسهی ناموجود و پایگاه دادهی قطع.
معیار پذیرش
اقدام مورد بررسی، اعتبارسنجی شناسه و اجرای ابزار با پاسخ موفق یا خطای مشخص است. معیار پذیرش دو بخش دارد. خروجی ایجنت دقیقاً با همان دورهی درخواستی مطابقت داشته باشد، نه دورهای مشابه. و در لاگ ثبت شده باشد کدام ابزار واقعاً اجرا شده است.
بخش دوم مهم است. بدون لاگ نمیتوانید تشخیص دهید پاسخ ایجنت از ابزار آمده یا از حافظهی خود مدل. این همان تفاوتی است که در قسمت ساخت ایجنت از صفر با آن روبهرو شدیم.
نمونهی شکست؛ پاسخ فرضی هنگام خطا
شکستی که باید عمداً دنبالش بگردید این است: ایجنت هنگام قطع سرویس یا پیدا نشدن شناسه، پاسخ فرضی بسازد. کاربر میپرسد «دورهی PY-999 چند هفته است؟» و ایجنت بهجای «این دوره پیدا نشد»، با اطمینان میگوید «هشت هفته».
قرارداد خطای روشن اولین دفاع است. دفاع دوم، پیام سیستمی است که صریحاً بگوید اطلاعات دوره فقط باید از خروجی ابزار بیاید. این نمونه را در آزمون بگذارید و بعد از هر تغییر دوباره بسنجید.
تمرین عملی؛ ابزار با قرارداد خطا
خروجی این تمرین یک ابزار خواندن اطلاعات دوره است که قرارداد خطا و ثبت اجرا دارد:
- ابزار
get_courseرا با اعتبارسنجی Pydantic و اتصال فقطخواندنی پیاده کنید. - برای هر پنج نوع خطای جدول بالا یک آزمون بنویسید.
- لاگ اجرا را بررسی کنید و مطمئن شوید هر فراخوانی با آرگومان و زمان ثبت شده است.
مشخص کنید کدام بخش را واقعاً اجرا کردهاید و کدام هنوز فرض است. همین ابزار در قسمتهای بعد پایهی جستجوی چندمرحلهای و تأیید انسانی میشود.
سخن پایانی
اجرای ابزار در ایجنت فقط صدا زدن یک تابع نیست. ایجنت قابلاعتماد نام ابزار را با فهرست مجاز میسنجد، آرگومانها را اعتبارسنجی میکند، با دسترسی محدود اجرا میکند و نتیجه یا خطای ساختاریافته برمیگرداند. هر اجرا را هم ثبت میکند تا بعداً بتوان فهمید دقیقاً چه اتفاقی افتاده است. این چند خط کد اضافه، تفاوت یک نمایش جذاب با ابزاری است که میتوان به آن تکیه کرد.
در قسمت بعد سراغ Agentic RAG برای پرسشهای پیچیده میرویم؛ اصلاح جستجو و کنترل شکست.
این آموزش بر پایهی درس Tool Use Design Pattern از مجموعهی آزاد AI Agents for Beginners مایکروسافت (مجوز MIT) به فارسی بازنویسی و تکمیل شده است.
پرسشهای پرتکرار
الگوی طراحی استفاده از ابزار چیست؟
الگویی که به مدل زبانی اجازه میدهد برای رسیدن به هدف، ابزارهای بیرونی را فراخوانی کند. ابزارها کدهاییاند که ایجنت اجرا میکند؛ از یک تابع ساده مثل ماشینحساب تا فراخوانی API یک سرویس بیرونی.
چرا باید آرگومانهای ابزار را اعتبارسنجی کرد؟
چون مدل ممکن است آرگومان ناقص، با نوع اشتباه یا حتی مخرب بسازد. اعتبارسنجی پیش از اجرا جلوی خطا و سوءاستفاده را میگیرد و پیام خطای روشنی برمیگرداند که مدل بتواند با آن اصلاح کند.
آیا اجازه دادن به مدل برای نوشتن SQL خطرناک است؟
میتواند باشد، چون خطر تزریق یا حذف داده وجود دارد. راهحل، دسترسی فقطخواندنی به پایگاه داده، اجرای برنامه در محیط امن و ترجیحاً استفاده از ابزارهای پارامتری بهجای SQL آزاد است.
وقتی ابزار شکست خورد ایجنت چه باید بکند؟
ابزار باید یک خطای ساختاریافته و روشن برگرداند، نه نتیجهی ساختگی. ایجنت بر اساس آن یا ورودی را اصلاح میکند، یا راه دیگری امتحان میکند، یا صادقانه به کاربر میگوید اطلاعات در دسترس نیست.







دیدگاهها
هنوز دیدگاهی ثبت نشده است. شروعکننده باشید — پرسش و اصلاح را با آغوش باز میپذیریم.