فاز 14 · درس 36

قرارداد دامنه و مرزبندی تسک‌ها در ایجنت‌های هوش مصنوعی

نوع
ساختنی
زمان
حدود 50 دقیقه
زبان‌ها
Python (stdlib)
پیش‌نیاز
فاز 14 · 32 (میز کار کمینه)، فاز 14 · 33 (قوانین به‌مثابه قیود)
طرح شماتیک یک میز کار مهندسی با نقشه‌ای فنی که دامنه‌ی مشخصی را با خطوط قرمز و سبز مرزبندی کرده است
فهرست مطالب
  1. اهداف یادگیری
  2. صورت مسئله
  3. مفاهیم پایه
  4. محتوای قرارداد دامنه
  5. استفاده از گلاب به‌جای مسیرهای مستقیم
  6. بازگشت به عقب، بخشی از دامنه است
  7. بررسی دامنه یعنی بررسی diff
  8. دو سطح از دامنه: فهرست قابلیت‌ها و قرارداد وظیفه
  9. پیاده‌سازی
  10. الگوهای کاربردی در محیط تولید
  11. کاربرد در عمل
  12. تحویل نهایی
  13. تمرین‌ها
  14. اصطلاحات کلیدی
  15. برای مطالعه‌ی بیشتر

ایجنت‌های کدنویسی اغلب کار را با نیت خیر گسترش می‌دهند؛ تسکی که صرفاً رفع یک باگ کوچک در صفحه ورود بوده، ناگهان به دست‌کاری تنظیمات پایگاه داده، اسکریپت‌های انتشار و فایل‌های مستندات ختم می‌شود. این پدیده که خزش دامنه (Scope Creep) نامیده می‌شود، با سخت‌گیرانه‌تر کردن پرامپت حل نمی‌شود؛ چون مدل زبانی چارچوب و انتهای مشخصی برای کار نمی‌شناسد.

راه‌حل مهندسی این مشکل، تدوین یک قرارداد دامنه (Scope Contract) در قالب فایلی ساختاریافته روی دیسک است. این فایل با مشخص کردن الگوهای مجاز و ممنوع، معیارهای پذیرش و برنامه‌ی بازگشت به عقب، تعهدات وظیفه را ثبت می‌کند. سپس ابزارهای بررسی خودکار، تغییرات فایل‌ها (diff) را با این قرارداد می‌سنجند و جلوی خروج ایجنت از مسیر اصلی را می‌گیرند.

مدل نمی‌داند کار کجا تمام می‌شود. «قرارداد دامنه» (Scope contract) فایلی به ازای هر وظیفه است که مشخص می‌کند کار از کجا شروع می‌شود، کجا پایان می‌یابد، و اگر فراتر رفت، چطور به عقب برگردد. این قرارداد، خواسته‌ی «در چارچوب دامنه بمان» را از یک آرزو به یک بررسیِ واقعی تبدیل می‌کند.

اهداف یادگیری

  • نوشتن یک قرارداد دامنه که ایجنت در ابتدای تسک و مدل اعتبارسنج (Verifier) در پایان تسک آن را بخوانند.
  • مشخص کردن فایل‌های مجاز، فایل‌های ممنوع، معیارهای پذیرش، طرح بازگشت به عقب (Rollback Plan) و مرزهای تأیید.
  • پیاده‌سازی یک بررسی‌کننده‌ی دامنه (Scope checker) که diff را با قرارداد مقایسه کند و موارد نقض را علامت بزند.
  • تبدیل خزش دامنه (Scope creep) به پدیده‌ای آشکار، خودکار و قابل‌بررسی.

صورت مسئله

ایجنت‌ها دچار خزش دامنه می‌شوند. وظیفه این است: «باگ ورود را برطرف کن». نتیجه‌ی diff اما علاوه بر مسیر لاگین، به ماژول کمکی ایمیل، درایور پایگاه داده، README و اسکریپت انتشار هم دست زده است. تغییر هر کدام در همان لحظه دلیل موجهی داشته؛ اما روی هم رفته، با تغییری کاملاً متفاوت از آنچه بازبینی شده بود روبه‌رو هستیم.

خزش دامنه کم‌نظارت‌ترین حالت شکست در کارهای مبتنی بر ایجنت است؛ چون ایجنت با حسن نیت تک‌تک مراحل را توجیه و گزارش می‌کند. راه‌حل این مشکل، پرامپت سخت‌گیرانه‌تر نیست؛ بلکه قراردادی ذخیره‌شده روی دیسک است که وعده‌ها را ثبت می‌کند، به همراه سازوکار کنترلی‌ای که نتیجه را با همان وعده می‌سنجد.

مفاهیم پایه

بلهخیروظیفهscope_contract.jsonحلقه‌ی ایجنتتغییرات نهاییscope_checker.pyدر دامنه است؟دروازه‌ی راستی‌آزماییمسدودسازی + ثبت پرسش

محتوای قرارداد دامنه

فیلد کاربرد
task_id پیوند به تسک روی بورد کاری
goal یک تک‌جمله که بازبین بتواند درستی‌اش را تأیید کند
allowed_files الگوهای گلاب (Globs) از فایل‌هایی که ایجنت اجازه‌ی نوشتن روی آن‌ها را دارد
forbidden_files الگوهای گلابی که ایجنت حتی اتفاقی نباید به آن‌ها دست بزند
acceptance_criteria دستورهای تست یا خطوط assertion که اتمام کار را اثبات می‌کنند
rollback_plan یک پاراگراف که اپراتور در صورت نیاز به توقف اجرا، بتواند پیاده‌اش کند
approvals_required اقدام‌های خارج از دامنه که تأیید صریح انسان را لازم دارند

قراردادی که forbidden_files نداشته باشد ناقص است؛ فضای منفی، نیمی از خود قرارداد است.

استفاده از گلاب به‌جای مسیرهای مستقیم

در مخازن کد واقعی، فایل‌ها جابه‌جا می‌شوند. قراردادها را با الگوهای گلاب ببندید (app/**/*.py، tests/test_signup*.py) تا ریفکتور میان نشست‌ها، اعتبار قرارداد را باطل نکند.

بازگشت به عقب، بخشی از دامنه است

ثبت نحوه‌ی بازگشت به عقب، نویسنده‌ی قرارداد را مجبور می‌کند به سناریوهای شکست فکر کند. قراردادی که بازگشت‌پذیر نباشد، اصلاً نباید تأیید شود.

بررسی دامنه یعنی بررسی diff

ایجنت یک diff می‌نویسد. ابزار بررسی، این diff، الگوهای گلاب مجاز و ممنوع، و فهرست دستورهای پذیرشِ اجراشده را می‌خواند. هر تخلف به‌شکل یک یافته‌ی برچسب‌خورده ثبت می‌شود که درگاه اعتبارسنجی می‌تواند آن را رد کند.

دو سطح از دامنه: فهرست قابلیت‌ها و قرارداد وظیفه

قرارداد دامنه فقط یک وظیفه را محدود می‌کند، نه کل پروژه را. ممکن است ایجنت کاملاً در چارچوب قراردادِ رفع باگ ورود بماند، اما در نوبت گفت‌وگو (Turn) بعدی تصمیم بگیرد که پروژه به یک صفحه‌ی تنظیمات، دکمه‌ی جابه‌جایی حالت تاریک و بازنویسی مسیریاب (Router) هم نیاز دارد. از این قرارداد هیچ‌وقت نپرسیده بودند چه کارهایی در دامنه‌ی کل پروژه می‌گنجد؛ فقط پرسیده بودند چه فایل‌هایی در دامنه‌ی این وظیفه هستند.

این سطح دوم به یک مفهوم اولیه‌ی مستقل نیاز دارد: یک فایل feature_list.json که ایجنت در ابتدای هر نشست (Session) می‌خواند. این فایل همان بک‌لاگ پروژه به‌شکل مرتب‌شده و ماشین‌خوان است. ایجنت دقیقاً یک قابلیت با وضعیت todo را انتخاب می‌کند، شناسه‌ی (id) آن را درون قرارداد دامنه‌ی فعال می‌نویسد و اجازه‌ی شروع دومین قابلیت در همان نشست را ندارد. با این روش، «در هر بار فقط یک قابلیت» دیگر صرفاً جمله‌ای در پرامپت نیست که ایجنت دورش بزند؛ بلکه مقداری است که از دیسک می‌خواند و درگاه آن را اعمال می‌کند.

{
  "project": "knowledge-base",
  "active": "import-pdf",
  "features": [
    { "id": "import-pdf",   "status": "in_progress", "goal": "import a PDF into the library",        "done_when": "pytest tests/test_import.py && a sample PDF appears in the library view" },
    { "id": "full-text-search", "status": "todo",     "goal": "search document text and rank hits",   "done_when": "query returns ranked results with snippets" },
    { "id": "cite-answers", "status": "todo",         "goal": "answers carry source citations",        "done_when": "every answer renders at least one clickable citation" }
  ]
}
فیلد کاربرد
active تنها قابلیتی که نشست جاری مجاز به تغییر آن است؛ خالی بودن یعنی یکی را انتخاب و ثبت کن
features[].id شناسه‌ی متنیِ پایداری (Slug) که task_id در قرارداد دامنه به آن اشاره می‌کند
features[].status مقادیر todo، in_progress، done، blocked؛ هم‌زمان فقط یک مورد می‌تواند in_progress باشد
features[].goal یک تک‌جمله که بازبین بتواند درستی‌اش را تأیید کند
features[].done_when خط شرطِ پذیرش که وضعیت را از in_progress به done تغییر می‌دهد

دو قاعده باعث می‌شوند این فهرست نقش ستون باربر را بازی کند، نه این‌که صرفاً تزیینی باشد. اول اینکه، اصل «حداکثر یک قابلیت در حال انجام (in_progress)» خودش یک بررسی آغازین (فاز 14 · 33) است: اگر فهرست دو مورد فعال را نشان دهد، نشست تا زمان تعیین تکلیف توسط انسان اصلاً شروع نمی‌شود. دوم اینکه، فهرست قابلیت‌ها یک فایل است، نه یک پیام در چت؛ چرا که پیام‌ها با اسکرول شدن از بافت بیرون می‌روند، اما فایل بین نشست‌ها و ایجنت‌های مختلف باقی می‌ماند. فرایند تحویل کار (فاز 14 · 40) وضعیت قابلیت تکمیل‌شده را به done برمی‌گرداند تا نشست بعدی به‌جای تلاش مجدد برای استخراج کارهای باقی‌مانده، کارش را با بورد دقیقی آغاز کند.

قرارداد و فهرست با اصل حداقل دسترسی ترکیب می‌شوند، درست مانند منطقِ merge در ادامه: مقدار allowed_files در قرارداد وظیفه باید همیشه زیرمجموعه‌ای از فایل‌های مربوط به همان قابلیت فعال باشد، نه بیرون از آن.

قرارداد دامنهبرخورد و بازگشت یک diff از الگوی ممنوعه
SCOPE CONTRACTThe contract lists where the task may write and where it must not. A diff that lands inside the allowed glob passes; a diff that drifts toward a forbidden path hits the contract boundary, bounces, and becomes a named violation with a rollback plan, caught by the checker rather than by a reviewer two days later.مجازsrc/auth/**ممنوعdb/** · release/**تغییرات Aتغییرات Bنقض: دستکاری db/**، بازگردانی شدscope_contract.jsonمجاز + ممنوع + بازگشت به عقب
قرارداد مشخص می‌کند تسک در کجا اجازه نوشتن دارد و به کجا نباید دست بزند. یک diff که درون الگوی مجاز قرار گیرد تایید می‌شود؛ diff دیگری که به سمت یک مسیر ممنوعه منحرف شود، به مرز قرارداد برخورد کرده، برمی‌گردد و تبدیل به یک نقض مشخص همراه با طرح بازگشت به عقب (Rollback Plan) می‌شود که توسط بررسی‌کننده شناسایی می‌گردد، نه اینکه دو روز بعد بازبین آن را ببیند.

پیاده‌سازی

فایل code/main.py این بخش‌ها را پیاده‌سازی می‌کند:

  • اسکیمای scope_contract.json (زیرمجموعه‌ای از JSON Schema، آرایه‌هایی از الگوهای گلاب).
  • یک پارسر diff که فهرستی از فایل‌های تغییرکرده به همراه دستورهای اجراشده را به شیء RunSummary تبدیل می‌کند.
  • تابع scope_check که نتیجه‌ی مقایسه با قرارداد را به‌صورت (violations, in_scope, off_scope) برمی‌گرداند.
  • دو اجرای نمایشی: یکی که در دامنه باقی می‌ماند و دیگری که دچار خزش می‌شود. بررسی‌کننده مورد خزش را با ذکر دقیق فایل و علت تخلف پرچم‌گذاری می‌کند.

اجرای برنامه:

python3 code/main.py

خروجی: متن قرارداد، دو اجرا، احکام صادرشده برای هر اجرا و فایل ذخیره‌شده‌ی scope_report.json.

الگوهای کاربردی در محیط تولید

یکی از برنامه‌نویسانی که از رویکرد «مشخصات‌محوریِ حداکثری» (specsmaxxing؛ یعنی نوشتن قراردادهای دامنه در فرمت YAML پیش از فراخوانی ایجنت) استفاده کرده، گزارش می‌دهد که نرخ افتادن در چرخه‌ی بیراهه و هدررفت کار در عرض سه هفته، بدون دست زدن به مدل ایجنت، از 52% به 21% کاهش یافته است. قرارداد این تفاوت را رقم زد، نه خود مدل. سه الگو این دستاورد را پایدار نگه می‌دارند:

بودجه‌ی نقض به‌جای شکست دودویی. ابزار agent-guardrails (درگاه merge متن‌بازی که با ابزارهایی مانند Claude Code، Cursor، Windsurf، و Codex از طریق پروتکل MCP استفاده می‌شود) قابلیتی به نام violationBudget به ازای هر وظیفه دارد: انحراف‌های جزئیِ داخل سقف بودجه صرفاً به‌شکل هشدار نمایش داده می‌شوند؛ تنها زمانی که از بودجه فراتر برود، درگاه مانع merge خواهد شد. این قابلیت را با violationSeverity: "error" | "warning" همراه کنید. همین بودجه است که فرق میان گاردریل (ریل ایمنی) پایدار در خط لوله‌ی تحویل را با گاردریلی رقم می‌زند که اعضای کلافه‌شده‌ی تیم غیرفعالش می‌کنند.

عدم تقارن سطح حساسیت بر اساس دسته‌ی مسیرها. تغییرات خارج از دامنه در مسیر docs/** معمولاً در حد warn است؛ اما تغییر خارج از دامنه در scripts/**، migrations/**، یا config/prod/** همیشه سطح block می‌گیرد. این تفاوت در حساسیت باید در خود قرارداد تعیین شود نه درون محیط اجرا (Runtime)؛ چون مختص هر پروژه است و وظیفه به وظیفه تغییر می‌کند.

بودجه‌های زمانی و شبکه در کنار بودجه‌ی فایل. فیلد time_budget_minutes سقف زمان واقعی (wall clock) را مشخص می‌کند؛ اگر کار بیشتر طول بکشد، محیط اجرا بدون تأیید مجدد اجازه‌ی ادامه‌ی کار را نمی‌دهد. یک لیست مجاز با فیلد network_egress روی هاست‌ها مانع از آن می‌شود که ایجنت بی‌صدا با یک API خارجی نامربوط به تسک ارتباط برقرار کند. این موارد هم ابعاد دامنه هستند؛ الگوهای گلاب لازم‌اند، اما کافی نیستند.

منطقِ merge چند قرارداد بر اساس حداقل دسترسی. وقتی دو قرارداد دامنه هم‌زمان اعمال می‌شوند (مثلاً یک قرارداد در سطح پروژه به‌همراه یک قرارداد ویژه‌ی تسک)، ترکیب به این شکل انجام می‌شود: اشتراک فایل‌های مجاز (allowed_files یعنی هر دو قرارداد باید مسیر را مجاز بدانند)، اجتماع فایل‌های ممنوع (forbidden_files یعنی اگر یکی هم مسیر را منع کند کافی است)، انتخاب محدودترین مقدار (حداقل) برای time_budget_minutes و تجمیع موارد approvals_required. برای فیلد network_egress: مقدار None به‌معنی عدم اعمال محدودیت، [] به‌معنی رد همه‌چیز، و [...] به‌صورت لیست مجاز عمل می‌کند؛ هنگام ترکیب، None اولویت را به طرف دیگر می‌دهد، دو لیست با هم اشتراک گرفته می‌شوند و وضعیت رد همه‌چیز همچنان رد همه‌چیز باقی می‌ماند. این منطق را صریحاً در اسکیمای قرارداد بیاورید تا عملیات merge مکانیکی و قابل‌بازبینی باشد.

کاربرد در عمل

الگوهای استفاده در محیط تولید:

  • دستورات خط مورب در Claude Code. دستور /scope قرارداد را می‌نویسد و آن را در بافت نشست سنجاق می‌کند. ساب‌ایجنت‌ها قبل از اقدام، قرارداد را می‌خوانند.
  • پول‌ریکوئست‌های گیت‌هاب. فایل JSON قرارداد را در متن PR یا به‌صورت یک دست‌سازه (Artifact) اضافه و push کنید. ابزار CI بررسی‌کننده‌ی دامنه را روی diff عملِ merge اجرا می‌کند.
  • وقفه‌ها در LangGraph. هرگونه نقض دامنه یک وقفه (Interrupt) ایجاد می‌کند؛ گرداننده‌ی وقفه از انسان می‌پرسد که آیا دامنه‌ی قرارداد باید گسترش یابد یا این‌که ایجنت باید عقب‌نشینی کند.

قرارداد همیشه همراه با وظیفه پیش می‌رود. وقتی وظیفه بسته شد، قرارداد در مسیر outputs/scope/closed/ بایگانی می‌شود.

تحویل نهایی

فایل outputs/skill-scope-contract.md برای شرح یک وظیفه، قرارداد دامنه‌ای همراه با یک بررسی‌کننده‌ی آگاه به الگوهای گلاب تولید می‌کند که در CI روی تمام diffهای ایجادشده توسط ایجنت اجرا می‌شود.

تمرین‌ها

  1. یک فیلد network_egress اضافه کنید که فهرست هاست‌های خارجیِ مجاز را در خود نگه دارد. اجرای کارهایی را که به سایر هاست‌ها متصل می‌شوند رد کنید.
  2. ابزار بررسی را طوری تغییر دهید که نقض در مسیر docs/** را با تساهل رد کند (fail soft)، اما روی مسیر scripts/** واکنش سخت نشان دهد (fail hard). دلیل این عدم تقارن را توضیح دهید.
  3. کاری کنید قرارداد بتواند با استفاده از مجموعه‌ای از قوانین ایستا (بدون LLM)، فیلد allowed_files را از روی goal استخراج کند. در اولین حالت خاص (Edge case) چه مشکلی پیش می‌آید؟
  4. فیلد time_budget_minutes را بیفزایید و اگر زمان سپری‌شده از آن فراتر رفت، از ادامه‌ی کار جلوگیری کنید.
  5. دو قرارداد را روی یک diff یکسان اعمال کنید. در صورت اِعمال هم‌زمان هر دو، منطقِ merge درست چیست؟

اصطلاحات کلیدی

اصطلاح اصطلاح رایج افراد معنای دقیق فنی
Scope contract (قرارداد دامنه) «شرح وظیفه» فایل JSON به ازای هر تسک، شامل فایل‌های مجاز/ممنوع، معیارهای پذیرش و طرح بازگشت به عقب
Scope creep (خزش دامنه) «به فلان جا هم دست زد...» تغییر فایل‌های خارج از قرارداد در جریان انجام همان تسک
Rollback plan (طرح بازگشت به عقب) «می‌تونیم ریورت کنیم» دستورالعمل یک‌پاراگرافیِ اپراتور برای توقف کار
Approval boundary (مرز تأیید) «نیاز به تأیید داره» اقدامی که در قرارداد مشخص شده انجامش نیازمند تأیید صریح انسان است
Diff check (بررسی diff) «بررسی مسیرها» تطبیق فایل‌های تغییریافته با الگوهای گلابِ قرارداد

برای مطالعه‌ی بیشتر

خودآزمایی

به سؤال‌ها جواب بدهید تا ببینید چقدر از درس در ذهنتان مانده است.

  1. پیش از درسچرا خزش دامنه (Scope creep) کم‌نظارت‌ترین حالت شکست نامیده می‌شود؟
  2. پیش از درسدرس کدام فیلد قرارداد را نیمی از کل قرارداد می‌نامد؟
  3. حین درسچرا مجاز/ممنوع به الگوهای glob مقید می‌شوند تا مسیرهای خام؟
  4. حین درسالگوی «بودجه نقض» (violation budget) چه کاری انجام می‌دهد؟
  5. حین درسمتخصص specsmaxxing چه نتیجه‌ای گزارش کرد؟
  6. پس از درسمعناشناسی ادغام چند قرارداد بر اساس حداقل‌لازم (least privilege) چگونه است؟
  7. پس از درسچرا بودجه‌های زمانی و شبکه نیز به قرارداد تعلق دارند؟

سؤالات متداول

قرارداد دامنه (Scope Contract) چیست و چه بخش‌هایی دارد؟

یک فایل ساختاریافته (غالباً JSON یا YAML) به ازای هر تسک است که شامل هدف، الگوهای گلابِ فایل‌های مجاز و ممنوع، معیارهای پذیرش، سناریوی بازگشت به عقب و مرزهای نیازمند تأیید انسان می‌شود.

بررسی‌کننده‌ی دامنه (Scope Checker) چگونه کار می‌کند؟

این ابزار خروجی diff ایجادشده توسط ایجنت را می‌خواند و تک‌تک مسیرهای تغییریافته را با الگوهای گلاب مجاز و ممنوع در قرارداد تطبیق می‌دهد تا موارد نقض را پیش از merge شناسایی و مسدود کند.

چرا تعیین فایل‌های ممنوع (forbidden_files) در قرارداد الزامی است؟

فضای منفی نیمی از قرارداد است؛ بدون تعریف صریح فایل‌های ممنوع، ایجنت ممکن است به فایل‌های حساس مانند اسکریپت‌های استقرار، کانفیگ تولید یا مایگریشن‌ها دست بزند.

منطق ترکیب (Merge) چند قرارداد دامنه چگونه عمل می‌کند؟

بر اساس اصل حداقل دسترسی: فایل‌های مجاز به اشتراک گرفته می‌شوند، فایل‌های ممنوع اجتماع می‌یابند، محدودترین بودجه‌ی زمانی اعمال می‌شود و تأییدیه‌های انسانی تجمیع می‌گردند.

ما رو توی گوگل بیشتر ببین

با افزودن نکست ادمین به «منابع ترجیحی» گوگل، درس‌ها و مطالب ما را در بخش اخبار برتر جستجو بیشتر می‌بینید.