وقتی تعداد مهارتها (Skills) در یک سیستم مبتنی بر مدلهای زبانی افزایش مییابد، بارگذاری همزمان تمام دستورالعملها، اسکریپتها و فایلهای راهنما در پنجرهی کانتکست مدل عملاً ناممکن میشود. این کار علاوه بر مصرف شدید سقف کانتکست و افزایش تصاعدی هزینهها، تمرکز مدل را روی تسک فعلی بر هم میزند و کیفیت تصمیمگیری را بهشدت کاهش میدهد.
افشاسازی تدریجی (Progressive Disclosure) این چالش را در 3 لایه حل میکند: ابتدا تنها متادیتای خلاصه در کاتالوگ به مدل نشان داده میشود، پس از انتخاب مهارت، فقط دستورالعملهای بدنهی اصلی بارگذاری میشوند و در نهایت منابع تکمیلی و اسکریپتها صرفاً در صورت برقراری شرایط شاخهای و بر اساس نیاز وارد کانتکست میگردند.
در این درس میآموزید که چگونه یک پایپلاین کشف و شناسایی قطعی بسازید، اولویت دامنهها (پروژه، کاربر، سیستم) و برخورد نامهای تکراری را مدیریت کنید و با مهار مسیر (Path Containment) جلوی آسیبپذیریهای امنیتی نظیر پیمایش غیرمجاز فایلها را بگیرید.
یک مهارت حتی پیش از آنکه محتوای اصلیاش بارگذاری شود به کار میآید. نام و توضیحات آن جایی در کاتالوگ باز میکنند؛ اما فایلهای عمیقترش فقط زمانی وارد کانتکست میشوند که تسک واقعاً به آنها برسد.
اهداف یادگیری
- پیادهسازی پایپلاین شناسایی در سیستم فایل که دامنه (scope)، اعتبارسنجی، سیاست برخورد (collision policy) و انتشار کاتالوگ را از یکدیگر تفکیک کند.
- توضیح سه سطح افشاسازی: متادیتای کاتالوگ، دستورالعملهای فعال و منابع مخصوص تسک.
- طراحی ارجاعها بهگونهای که ایجنت بتواند بدون نیاز به بارگذاری کل پکیج، مستقیماً به جزئیات مورد نیازش دسترسی پیدا کند.
- بودجهبندی فضای کاتالوگ، مستقل از کانتکست مهارت فعال.
- رد کردن پیمایش غیرمجاز مسیر (path traversal) و خروج از ریشه از طریق پیوندهای نمادین (symlink escape) هنگام خواندن منابع داخلی مهارت.
صورت مسئله
فرض کنید ایجنت شما 200 مهارت نصبشده دارد. اگر در ابتدای نشست کاری، تمام فایلهای SKILL.md، فایلهای ارجاع، اسکریپتها و قالبها را بارگذاری کنید، تسک فعلی زیر انبوهی از دستورالعملهای نامربوط دفن خواهد شد. از طرف دیگر، اگر هیچچیزی بارگذاری نکنید، کاربر ناچار میشود مسیر دقیق فایلها در سیستم فایل را خودش حفظ کند.
راهکار میانهی معمول، استفاده از کاتالوگ است: شناسه و توصیف فشردهای از مسیر هدایت (routing) هر مهارت واجد شرایط را به مدل نشان میدهید، سپس متن کامل آن را تنها پس از انتخاب بارگذاری میکنید. همین رویکرد، دو چالش مهندسی تازه میآفریند:
نخست اینکه شناسایی، صرفاً یک جستوجوی بازگشتی در میان فایلها نیست. مهارتها ممکن است در دامنههای گوناگونی حضور داشته باشند: پروژه، کاربر، مدیر سیستم، پلاگین یا حتی بهصورت توکار (built-in). امکان دارد دو پکیج همنام باشند. ممکن است یک پیوند نمادین (symlink) به خارج از ریشهی مورد اعتماد اشاره کند. یا یک پکیج معیوب، فضای کاتالوگ را هدر دهد یا فراخوانیاش ناممکن شود.
دوم اینکه افشاسازی تدریجی ممکن است به «سردرگمی تدریجی» تبدیل شود. اگر در SKILL.md بنویسید «راهنمای مربوطه را بخوانید» و پکیج دوازده راهنما داشته باشد، مدل ناچار به حدس زدن میشود. اگر هر راهنما به سه فایل دیگر اشاره کند، بارگذاری به یک پیمایش نامحدود در گراف تبدیل خواهد شد.
یک محیط اجرای (runtime) کارآمد، شناسایی را قطعی و پیشبینیپذیر و فرایند افشاسازی را هدفمند میکند.
مفهوم اصلی
شناسایی، یک پایپلاین کامپایلری است
به سیستم فایل مثل ورودی سورس کد نگاه کنید. هرگز مسیرهای خام را مستقیماً در اختیار مدل نگذارید.
هر مرحله باید دادههای ساختاریافته و خطاهای ساختاریافته تولید کند. لاگ شناسایی باید به این پرسشها پاسخ دهد:
- کدام ریشهها جستوجو شدند؟
- چه پکیجهای کاندیدی پیدا شدند؟
- کدام کاندیدها رد شدند و چرا؟
- در صورت بروز برخورد، کدام پکیج برنده شد؟
- کدام ورودیهای کاتالوگ بهخاطر محدودیت بودجه کوتاه یا حذف شدند؟
بدون این شواهد، عیبیابی علت اینکه «چرا مدل از مهارت من استفاده نکرد» تقریباً ناممکن خواهد بود.
دامنه، سیاست محیط اجراست
مشخصات پرتابل (portable specification)، ساختار یک پکیج مهارت را تعریف میکند، نه یک مسیر نصب سراسری واحد یا ترتیبی برای اولویتها. این برنامهی میزبان (host) است که دربارهی دامنهی جستوجو تصمیم میگیرد.
یک محیط اجرای عمومی معمولاً چنین دامنههایی دارد:
| دامنه | نمونهی ریشه | مالکیت مورد نظر |
|---|---|---|
| فضای کاری (Workspace) | <repo>/.agents/skills/ |
نگهدارندگان پروژه |
| کاربر (User) | <user-data>/skills/ |
یک توسعهدهنده |
| مدیر سیستم (Administrator) | <system>/skills/ |
سیاستهای سیستم یا سازمان |
| پلاگین (Plugin) | باندل امضاشدهی پلاگین | ناشر و نصبکنندهی پلاگین |
| توکار (Built-in) | پکیج محیط اجرا | ارائهدهندهی محیط اجرا |
تا تاریخ آگوست 2026، مستندات Codex برای شناسایی پروژه، مسیر $CWD/.agents/skills را از طریق دایرکتوریهای والد تا ریشهی مخزن بررسی میکند و علاوهبر آن، مسیرهای مربوط به کاربر، مدیر سیستم و مکانهای توکار را نیز در نظر میگیرد. این سیستم از دایرکتوریهای پیوند نمادین مهارتها پشتیبانی میکند. همچنین در صورت وجود نامهای تکراری، ممکن است بهجای ادغام، هر دو نمایش داده شوند. این رفتارها مخصوص Codex است و از الزامات فایل SKILL.md به شمار نمیرود؛ هنگام نوشتن یک تطبیقدهنده (adapter)، حتماً مستندات مهارتهای Codex را بررسی کنید.
هرگز اولویت را بر پایهی نام دایرکتوریها حدس نزنید. این اولویت را در قالب یک سیاست صریح اعلام و آن را تست کنید. در کارگاه این درس، برای هر Scope یک رتبهی عددی صریح در نظر گرفته شده تا مجموعهی کاندیدهای یکسان همیشه به نتیجهای واحد ختم شود.
برخورد نامها نیازمند شناختی فراتر از name است
وجود دو پکیج با نام release-readiness میتواند کاملاً منطقی باشد. یکی ممکن است بازنویسیِ اختصاصی در فضای کاری باشد و دیگری پیشفرضِ کاربر. بنابراین، هر ورودی کاتالوگ حداقل به این موارد نیاز دارد:
{
"name": "release-readiness",
"description": "Inspect a release candidate for this repository.",
"scope": "workspace",
"source": "/repo/.agents/skills/release-readiness",
"selected": true
}
سیاستهای متداول در مواجهه با برخورد نامها عبارتاند از:
| سیاست | مزیت | ریسک |
|---|---|---|
| نگهداشتن همهی کاندیدها | هیچچیزی پنهان نمیماند | مدل با نامهای مبهم روبهرو میشود |
| اولویت با بالاترین دامنه | فراخوانی ساده | پکیج محلی میتواند جای یک پکیج مورد اعتماد را بگیرد (shadowing) |
| رد کردن موارد تکراری | سایهاندازی پنهانی رخ نمیدهد | بازنویسیهای مجاز کار نخواهند کرد |
| اختصاصیکردن نامها بر اساس منبع | هویت صریح | نامهای دیدهشده توسط کاربر طولانیتر میشوند |
یک سیاست مشخص برای میزبان انتخاب کنید. کاندیدهای ردشده یا سایهخورده را در دادههای تشخیصی نگه دارید، حتی اگر در کاتالوگ ارائهشده به مدل غایب باشند.
سه سطح افشاسازی
استاندارد Agent Skills بارگذاری را بهصورت مرحلهبهمرحله تعریف میکند. نکتهی کلیدی اینجاست که هر سطح، هدف متفاوتی دارد.
سطح 1: متادیتای کاتالوگ
مدل فقط به اندازهای اطلاعات نیاز دارد که بتواند مهارت را از مهارتهای همسایه تشخیص دهد. طبق برآورد مشخصات استاندارد، برای هر ورودی کاتالوگ حدود 100 توکن لازم است؛ اما نحوهی دقیق سریالسازی و توکنسازی بر عهدهی میزبان است.
یک توصیف کارآمد از دو بخش تشکیل میشود:
description: Validate a release candidate and produce a readiness report. Use when the user asks whether a version, tag, or package is ready to publish.
بخش اول، توانمندی را بیان میکند. بخش دوم، مرز فعالسازی را مشخص میسازد. در درس 25 این مرز را با پرامپتهای مثبت و پرامپتهای تقریباً مرتبط (near-miss) ارزیابی میکنیم.
سطح 2: دستورالعملهای فعال
بدنهی مهارت پس از فعالسازی باید مثل نقشه و روند اجرایی عمل کند. استاندارد پیشنهاد میکند حجم SKILL.md زیر 500 خط نگه داشته شود. این عدد یک راهنمای طراحی است، نه هدفی که حتماً باید پر شود.
بدنهی مهارت باید شامل این موارد باشد:
- مرز وظیفه و تسک؛
- گردش کار پیشفرض؛
- شرطهای شاخهبندی؛
- ارجاع مستقیم به فایلهای عمیقتر؛
- قراردادهای مربوط به ابزارها و اسکریپتها؛
- رفتار سیستم در زمان شکست و توقف؛
- خروجی مورد انتظار و راستیآزمایی آن.
گردش کار اصلی را صرفاً برای کوتاهکردن فایل ورودی به فایلهای ارجاع منتقل نکنید. فعالسازی باید کانتکست کافی برای شروع درست کار را به مدل بدهد.
سطح 3: منابع پشتیبان
فایلهای ارجاع، متون توضیحی یا دادهها را تأمین میکنند. اسکریپتها محاسبات قطعی را انجام میدهند. داراییها (assets) فایلهایی هستند که بهجای استفاده بهعنوان دستورالعمل، کپی میشوند، مقادیرشان پر میشود یا به خروجی نهایی تبدیل میشوند.
| دایرکتوری | مدل آن را میخواند؟ | مدل آن را اجرا میکند؟ | محتوای متداول |
|---|---|---|---|
references/ |
بله، در صورت نیاز | خیر | اسکیماها، سیاستها، راهنماهای تخصصی |
scripts/ |
ممکن است بررسی کند | از طریق یک ابزار مجاز | اعتبارسنجها، مبدلها، جمعآوریکنندههای داده |
assets/ |
فقط اگر مفید باشد | خیر | قالبها، دادههای تستی (fixtures)، تصاویر، فایلهای اولیه |
این نامها فقط قرارداد هستند، نه قابلیتهایی جادویی. میزبان همچنان به دسترسی فایل و ابزار اجرا نیاز دارد.
ارجاعهای وابسته به شاخه بهتر از انباشتن اطلاعات است
فایل ورودی را مثل یک نقشهی تصمیمگیری بنویسید:
## Choose the path
- For a Python package, read `references/python-release.md`.
- For a container image, read `references/container-release.md`.
- For a documentation-only release, read `references/docs-release.md`.
- If the release combines artifact types, read only the guides for those artifacts.
با این کار، هر ارجاع یک شرط بارگذاری شفاف و قابل رصد خواهد داشت. جملهای مثل «برای اطلاعات بیشتر references/ را بخوانید» فاقد چنین امکانی است.
گراف ارجاعها را کمعمق نگه دارید. راهنمای رسمی توصیه میکند لینکها را مستقیماً از داخل SKILL.md بدهید و از زنجیرههای عمیق بپرهیزید. وقتی فاصلهی ارجاع تنها یک گام لغزش (hop) باشد، دسترسیپذیری فایلها بهسادگی تستپذیر میشود و احتمال اینکه یک محدودیت حیاتی هرگز وارد کانتکست نشود به حداقل میرسد.
بودجهی کاتالوگ و کانتکست فعال، دو بودجهی مجزا هستند
فرض کنید c_i هزینهی کاتالوگ سریالشده برای مهارت i، B_c کل بودجهی کاتالوگ، b_j هزینهی بدنهی فعال و r_k هزینهی منابعی باشد که عملاً بارگذاری شدهاند.
catalog_cost = sum(c_i for every published skill)
active_cost = sum(b_j for every activated skill) + sum(r_k for every disclosed resource)
کاهش یکی از این دو بودجه بهمعنای کاهش خودکار دیگری نیست. توصیفهای کوتاه میتوانند فضای کاتالوگ را ذخیره کنند، درحالیکه یک بدنهی فعال 900 خطی همچنان میتواند کانتکست تسک را ببلعد. خردکردن بدنه در قالب فایلهای ارجاع تنها زمانی هزینهی فعال را کم میکند که محیط اجرا و دستورالعملها واقعاً جلوی بارگذاری شاخههای نامربوط را بگیرند.
در حال حاضر Codex در صورتی که ابعاد پنجرهی کانتکست مشخص باشد، 2 درصد از آن را به لیست اولیهی مهارتها اختصاص میدهد. مقدار 8,000 کاراکتری فقط زمانی بهعنوان حالت پشتیبان وارد عمل میشود که اندازهی کانتکست مشخص نباشد؛ این مقدار سقف دومی در ترکیب با قاعدهی 2 درصد نیست. وقتی حجم کاتالوگ از بودجه فراتر برود، ممکن است توضیحات کوتاه یا حذف شوند. این ارقام را سیاست فعلی Codex در نظر بگیرید، نه ویژگی استاندارد Agent Skills.
مسیر منابع یک مرز اعتماد است
هر مهارت باید فقط فایلهای درون پکیج خودش را بخواند. بررسی صِرف پیشوند متنی (string-prefix) بههیچوجه کافی نیست:
references/../../../../.ssh/config
references/external-link -> /private/company-secrets
ریشهی پکیج و فایل کاندید را با قواعد سیستم فایل تحلیل و حل کنید (resolve)، مسیرهای ورودی مطلق را رد کنید و مطمئن شوید کاندید نهایی پس از ارزیابی، زیر ریشهی ارزیابیشده باقی میماند. پیش از شروع شناسایی تصمیم بگیرید که آیا پیوندهای نمادین مجاز هستند یا خیر. اگر مجازند، مقصد نهایی آنها را هر بار بازبینی کنید.
محدود بودن مسیر بهتنهایی سلامت محتوا را تضمین نمیکند. یک فایل ارجاع معتبر درون پکیج نیز میتواند حاوی دستورالعملهای مخرب باشد. درس 26 به این تهدید میپردازد.
بارگذاری باید قابل رصد باشد
رویدادهای افشاسازی را بدون لاگ کردن اطلاعات حساس ثبت کنید:
{
"event": "skill.resource.loaded",
"skill": "release-readiness",
"resource": "references/python-release.md",
"reason": "candidate contains pyproject.toml",
"bytes": 2840
}
دلیل بارگذاری، این تصمیمِ کانتکستی را به شواهدی مستند و قابل بررسی تبدیل میکند. همچنین دستورالعملهایی را مشخص میکند که باعث میشوند ایجنت فایلها را صرفاً «محض اطمینان» یکیپسازدیگری بارگذاری کند.
ساخت سیستم
فایل code/main.py یک موتور شناسایی و افشاسازی قطعی میسازد.
بخشهای مربوط به شناسایی عبارتاند از:
Scopeبرای متادیتای منبع و اولویت؛SkillCandidateبرای کاندید اعتبارسنجینشده از سیستم فایل؛discover_scope(scope)برای پیمایش دایرکتوریهای بیواسطهی مهارت؛resolve_collisions(candidates, precedence)برای اعمال سیاست برخوردِ تعریفشده؛CatalogEntryوbuild_catalog(...)برای انتشار متادیتای محدودشده؛CatalogBudgetبرای محاسبهی ورودیهای سریالشده، بدون آنکه کاراکترها را معادل جهانشمولِ توکنها فرض کند.
بخشهای مربوط به افشاسازی عبارتاند از:
load_skill_body(entry, ...)برای فعالسازی در سطح 2؛validate_reference(skill_dir, reference)برای مهار مسیر (path containment)؛load_reference(...)برای خواندن کنترلشده در سطح 3.
اجرای کارگاه عملی:
cd "$(git rev-parse --show-toplevel)"
cd phases/13-tools-and-protocols/24-skill-discovery-and-progressive-disclosure
python3 code/main.py
python3 -m unittest discover -s code/tests -v
این بخش به یک کلون محلی نیاز دارد و ریشهی مخزن را از هر دایرکتوری کاری در داخل آن کلون پیدا میکند.
این دمو دامنههای موقتی پروژه و کاربر را میسازد، یک برخورد نام میان آنها ایجاد میکند، کاتالوگی تحت بودجهای عمداً محدود میسازد، یکی از مهارتها را فعال میکند و در نهایت هم خواندن یک ارجاع معتبر و هم خروج غیرمجاز از مسیر را آزمایش میکند. هیچ فایل دائمی روی سیستم نصب نمیشود.
چرا شناسایی، کمعمق است؟
تابع discover_scope تنها دایرکتوریهای فرزند مستقیم را برای یافتن SKILL.md بررسی میکند. این تابع بهصورت بازگشتی با هر SKILL.md تودرتو مثل پکیجی جداگانه رفتار نمیکند. با این کار، مرز پکیج حفظ میشود و نمونهها یا فیکسچرهای موجود در یک مهارت نصبشده بهاشتباه منتشر نخواهند شد.
چرا در این کارگاه از پارسر دلخواه YAML استفاده نمیکنیم؟
این کارگاه تنها از فرانتمترهای اسکالر مورد نیاز کاتالوگ پشتیبانی میکند. در محیط پروداکشن، باید از یک پارسر امن YAML با اسکیمای صریح، محدودیت حجم و غیرفعالسازی ساخت آبجکتهای سفارشی استفاده کرد. محدودیت استفاده از کتابخانهی استاندارد صرفاً یک قید آموزشی است، نه مجوزی برای پیادهسازی سلیقهای و ناقص گویشی از YAML.
راهنمای استفاده
این چکلیست را برای هر تطبیقدهندهی شناسایی به کار ببرید:
- تمام ریشههای پیکربندیشده و افراد دارای دسترسی نوشتن به آنها را فهرست کنید.
- موضع خود را دربارهی مجاز بودن پکیجهای مبتنی بر پیوند نمادین صریحاً مشخص کنید.
- نام پکیج، نام دایرکتوری، متادیتای اجباری و حجم فایل ورودی بدنه را اعتبارسنجی کنید.
- منبع و دامنه را در هویت داخلی حفظ کنید.
- رفتار سیستم در برابر نامهای تکراری را صریحاً تعریف و آن را تست کنید.
- اندازهی دقیق کاتالوگ سریالشدهی ارسالی به مدل را اندازه بگیرید.
- دلیل بارگذاری هر بدنه یا منبع را ثبت کنید.
- خواندن منابع را درون ریشهی ارزیابیشدهی پکیج نگه دارید.
- در صورت ناموجود بودن فایل مورد ارجاع، با پیامی شفاف با شکست متوقف شوید.
- با تغییر در پکیجهای نصبشده یا سیاستها، کاتالوگ را دوباره بازسازی کنید.
تحویل پروژه
این درس باندل skill-catalog-builder را تولید میکند. این ابزار ریشهها را با ترتیب اولویت صریح اسکن میکند، فایلهای اصلی با پیوند نمادین و ناهماهنگی بین نام و دایرکتوری را رد میکند، برخوردهای بیندامنهای را برطرف میسازد، نمونههای تکراری با اولویت برابر را نمیپذیرد و در نهایت متادیتای منتخب را در قالب بودجههای تعیینشده برای ورودی، توصیف و کاراکترهای سریالشده جای میدهد.
گزارش JSON خروجی شامل ورودیهای منتخب، کاندیدهای سایهخورده، ورودیهای حذفشده، خطاهای اعتبارسنجی، اولویتها و بودجهی مصرفی است. بارگذاری بدنه و ارجاعها همچنان عملیات مجزایی در محیط اجرا هستند؛ بنابراین بیلدرِ کاتالوگ نه اسکریپتی اجرا میکند و نه کل پکیج را بیدلیل وارد کانتکست میسازد.
تمرینها
- یک دامنهی پلاگین اضافه کنید و اولویت آن را بین دامنه کاربر و توکار قرار دهید. نتیجهی برخورد را با یک تست نشان دهید.
- سیاست برخورد را از بالاترین اولویت به نامهای اختصاصیشده (qualified names) تغییر دهید. هر دو ورودی را در کاتالوگ نگه دارید.
- یک محدودیت بایتی برای تابع
load_referenceاضافه کنید. فایلی دقیقاً هماندازهی محدودیت و فایلی با یک بایت اضافهتر را تست کنید. - دو توصیف بنویسید که شباهت زیادی به هم داشته باشند. سپس آنها را طوری بازنویسی کنید که مرزهای فعالسازی آنها همپوشانی نداشته باشد.
- یک مانیفست حاوی هش برای تمام فایلهای ارجاع و اسکریپتها اضافه کنید. پیش از بارگذاری، منابع تغییریافته را شناسایی کنید.
- دمو را طوری ابزاربندی کنید که تعداد بایتهای سطوح 1، 2 و 3 را بهصورت جداگانه گزارش دهد.
اصطلاحات کلیدی
| اصطلاح | معنای عامیانه | معنای دقیق فنی |
|---|---|---|
| شناسایی مهارت (Skill discovery) | «پیدا کردن تمام فایلهای SKILL.md» | جستوجو در دامنههای پیکربندیشده، اعتبارسنجی پکیجها، ثبت منشأ و سندیت و اعمال سیاست |
| کاتالوگ مهارت (Skill catalog) | «فهرست مهارتهای نصبشده» | متادیتای فشرده و قابل مشاهده برای مدل جهت هدایت فراخوانی پکیجهای واجد شرایط |
| سیاست برخورد (Collision policy) | «کدام مهارت تکراری برنده میشود» | قاعدهای صریح برای کاندیدهای همنام از منابع مختلف |
| افشاسازی تدریجی (Progressive disclosure) | «بارگذاری تنبل» | ورود مرحلهبهمرحله به کانتکست: از کاتالوگ به بدنه و سپس به منابع وابسته به شاخهها |
| گراف ارجاع (Reference graph) | «فایلهای لینکشده در مهارت» | ساختار منابع در دسترس و شرطهای بارگذاری مربوط به آنها |
| مهار مسیر (Path containment) | «ماندن در پوشه» | اطمینان از اینکه مقصد نهایی منابع پس از ارزیابی، درون ریشهی ارزیابیشدهی پکیج باقی بماند |
برای مطالعهی بیشتر
- مشخصات استاندارد Agent Skills برای ساختار پکیج و سطوح افشاسازی تدریجی.
- بهینهسازی توضیحات مهارت برای متادیتای هدایتکننده در کاتالوگ.
- بهترین شیوههای Agent Skills برای ارجاعهای مستقیم و حجم فایلهای ورودی.
- OpenAI: ساخت مهارتها برای دامنههای شناسایی و محدودیتهای کنونی کاتالوگ در Codex.
