سلام رفقا!
اگر در چند ماه اخیر با کلاینتهای مدرن هوش مصنوعی یا سیستمهای کدنویسی بر پایه ایجنت (مثل Claude Code، Windsurf یا پلتفرمهای مجهز به Model Context Protocol) سر و کله زده باشید، احتمالاً با یک پدیده آزاردهنده روبرو شدهاید: کند شدن وحشتناک مدل و صورتحسابهای سنگین توکن قبل از اینکه حتی کار اصلی شروع شود.
وقتی پروتکل MCP (معماری متنباز آنتروپیک برای استانداردسازی اتصال ابزارها به مدل) معرفی شد، همه تصور کردند مشکل یکپارچهسازی ابزارها برای همیشه حل شده است. اما در پروداکشن، یک دیوار بتنی بزرگ وجود دارد: Tool Schema Flooding یا پر شدن پنجره کانتکست با تعریف ابزارهایی که شاید در کل نشست حتی یک بار هم اجرا نشوند.
در این مقاله میخواهیم بدون تعارف و تئوریهای پوچ، به عمق مسئله برویم: چرا MCP کانتکست را منفجر میکند و چطور در سطح معماری، کانتکست ۴۰ هزار توکنی را به ۴ هزار توکن برسانیم؟
۱. صورت مسئله: چرا سرورهای MCP کانتکست را میبلعند؟
در پروتکل MCP، سرورها لیست قابلیتهای خود را از طریق JSON Schema به کلاینت معرفی میکنند. وقتی شما ۳ سرور MCP (مثلاً گیتهاب، دیتابیس پستگرس، و سیستم فایل محلی) را متصل میکنید:
- انباشت اسکیمای خام: هر تابع نیاز به توضیح ورودی، ساختار JSON، نوع متغیرها و داکیومنت دارد. یک سرور معمولی گیتهاب حدود ۳۰ متد دارد که به تنهایی بیش از ۱۵ تا ۲۵ هزار توکن متن خام تولید میکند.
- سربار در هر رفت و برگشت: در مدلهای بدون کش یا با کش ناقص، این اسکیمای عظیم در هر پیام مجدداً به عنوان System Prompt ارسال میشود.
- تخریب توجه مدل (Attention Degradation): تحقیقات نشان داده با طولانی شدن کانتکست، توانایی استدلال مدل در انتخاب درست ابزارها افت پیدا میکند و دچار توهم پارامترها (Hallucination) میشود.
بیایید تفاوت بارگذاری ایستا و پویا را مقایسه کنیم:
[ معماری سنتی MCP ]
کاربر: "این فایل رو فرمت کن"
کانتکست ارسالی:
├─ سیستم پرامپت اصلی (۲,۰۰۰ توکن)
├─ ۳۰ ابزار گیتهاب (۱۸,۰۰۰ توکن)
├─ ۲۰ ابزار دیتابیس (۱۲,۰۰۰ توکن)
├─ ۱۵ ابزار سیستم فایل (۸,۰۰۰ توکن)
└─ دستور کاربر: ۴۰,۰۰۰+ توکن ارسال شد!
[ معماری Tool Filtering & Dynamic Injection ]
کاربر: "این فایل رو فرمت کن"
کانتکست ارسالی:
├─ سیستم پرامپت بهینه (۱,۲۰۰ توکن)
├─ فقط ۳ ابزار مربوط به سیستم فایل (۱,۸۰۰ توکن)
└─ دستور کاربر: ۳,۰۰۰ توکن ارسال شد! (کاهش بیش از ۹۰٪)
۲. راهکار اول: Dynamic Tool Discovery (اکتشاف پویای ابزار)
چرا باید اسکیماهای سرور Postgres را وقتی کاربر فقط میخواهد یک فایل پایتون را ریفکتور کند در کانتکست نگه داریم؟
راهکار درست در سطح ارکستریتور، افزودن یک لایه Meta-Tool به نام tool_search است. به جای اینکه ۵۰ ابزار را مستقیم به مدل تزریق کنید، فقط ۵ ابزار پایه بعلاوه متد جستجوی ابزار را اعلام میکنید:
// نمونه پیادهسازی لایه فیلترینگ ابزار در کلاینت MCP
interface MCPToolRegistry {
tools: Map<string, MCPToolDefinition>;
// به جای ارسال همه، متادیتای خلاصه در حافظه نگه داشته میشود
searchTools(query: string): MCPToolDefinition[] {
const scored = Array.from(this.tools.values()).filter(t =>
t.name.toLowerCase().includes(query.toLowerCase()) ||
t.description.toLowerCase().includes(query.toLowerCase())
);
return scored.slice(0, 5); // فقط ۵ ابزار مرتبط لود میشود
}
}
با این کار، مدل وقتی احساس نیاز به گیتهاب کرد، ابتدا دستور search_tools("commit pull request") را صدا میزند و ارکستریتور فقط اسکیمای همان ابزار خاص را به پیام بعدی تزریق میکند.
۳. راهکار دوم: تکنیک Prompt Caching و شکستن مرزها
سرویسهای Anthropic و Gemini امکان کش کردن پرامپت (Prompt Caching) را با تخفیف ۵۰ تا ۹۰ درصدی هزینه ورودی ارائه میدهند. اما یک مشکل مهندسی شایع وجود دارد: تغییر حتی یک کاراکتر قبل از نقطه کش، کل کش را میسوزاند.
اگر ابزارهای MCP شما بر اساس زمان، اطلاعات محیطی دائم یا وضعیت متغیر سیستم تزریق شوند، Cache Miss رخ میدهد.
قانون طلایی پایدارسازی کَش در MCP:
- بخش اول: پرامپت سیستم ثابت (Fixed Identity) -> نشانگر Cache Breakpoint
- بخش دوم: ابزارهای اصلی و ثابت MCP (Core Schema) -> نشانگر Cache Breakpoint دوم
- بخش سوم: ابزارهای متغیر داینامیک و کانتکست فایلها
- بخش چهارم: تاریخچه مکالمه و پیام کاربر
اگر این توالی را رعایت کنید، حتی با وجود ۱۵ هزار توکن اسکیما، فقط بار اول هزینه پردازش پرداخت میشود و درخواستهای بعدی با تأخیر نزدیک به صفر و هزینه ناچیز کش اجرا میشوند.
۴. راهکار سوم: فشردهسازی خروجی ابزارها (Payload Compaction)
مشکل دیگر، خروجی ابزارهاست. وقتی ابزار MCP یک کوئری SQL یا دستور Bash اجرا میکند، بازگشت ۴۰۰۰ سطر لاگ باعث انفجار فوری کانتکست در گامهای بعدی میشود.
یک سیستم پایدار باید لاگها را قبل از تحویل به مدل کپسوله کند:
# فیلتر کردن لاگهای حجیم ابزارها قبل از ارسال به پنجره مدل
def compact_tool_output(output: str, max_lines: int = 40) -> str:
lines = output.strip().splitlines()
if len(lines) <= max_lines:
return output
head = lines[:20]
tail = lines[-20:]
omitted = len(lines) - 40
return "
".join(head) + f"
[... {omitted} سطر خروجی تکراری نادیده گرفته شد ...]
" + "
".join(tail)
مدل برای عیبیابی به ۲۰ سطر اول و ۲۰ سطر آخر (خطا و استک تریس نهایی) نیاز دارد، نه هزار سطر لاگ نصب پکیجهای پایتون!
جمعبندی: ایجنت سریع، ارزان و متمرکز
پروتکل MCP بدون معماری مدیریت کانتکست، تبدیل به یک باتلاق هزینهای و کندی پرفورمنس میشود. اگر در حال ساخت یا توسعه کلاینتهای هوش مصنوعی هستید:
- ابزارها را به صورت تنبل (Lazy / Search-based) بارگذاری کنید.
- با چینش درست کانتکست، از پایداری Prompt Cache مطمئن شوید.
- خروجی ابزارهای پرحرف را پیش از بازگشت به چرخه تعقل مدل هرس کنید.
این سه اصل تفاوت میان یک نمونه اسباببازی و یک ایجنت نرمافزاری واقعی در مقیاس پروداکشن است.