اگر برای مدیریت یک سامانهٔ چندعاملی (Multi-agent system) هزینه میپردازید، احتمالاً نیمی از بودجهٔ استنتاج شما بهدلیل یک اشتباه ساده در ترتیب کلمات دور ریخته میشود. این نقص ساختاری در چیدمان دستورات، باعث میشود مدلها هر بار مجبور به بازخوانی کل متن شوند، حتی اگر آن متن در درخواست قبلی دقیقاً تکرار شده باشد. در حالی که توسعهدهندگان برای تعریف شخصیت عاملها به روشهای استاندارد SDK اتکا میکنند، یک باگ ساختاری در نحوه ترتیببندی این پرامپتها بهطور نامحسوسی صورتحسابهای استنتاج را برای سیستمهای چندعاملی افزایش میدهد.
به گزارش وبسایت dev.to در تاریخ ۱۱ آگوست ۲۰۲۶، یک گزارش فنی فاش کرد که بسیاری از توسعهدهندگان بهطور ناخودآگاه «مسمومیت پیشوند» (Prefix Mismatch) ایجاد میکنند. این اتفاق باعث میشود حافظه پاداش (Prompt Caching) — که برای صرفهجویی در هزینهها با ذخیره نتایج بلوکهای متنی طولانی و تکراری طراحی شده است — کاملاً بی اثر شود.
برای درک بهتر، حافظه پاداش را مانند کتابخانهای تصور کنید که کتابدار در آن، ده صفحه اول هر کتابی را که درخواست میدهید به خاطر میسپارد؛ اگر ده صفحه اول در درخواستهای مختلف یکسان باشد، کتابدار مجبور نیست آنها را دوباره بخواند. این دقیقاً همان روشی است که ارائهدهندگان سرویس استنتاج (Hosted Inference Providers) توکنها را مدیریت میکنند.
همانطور که در تحلیلهای پیشین ما دربارهی بهینهسازی هزینههای مدلهای زبانی اشاره کردیم، بهرهوری در مقیاس بالا تنها به انتخاب مدل ارزانتر نیست، بلکه به مدیریت هوشمندانه توکنها بازمیگردد. مشکل اینجاست که ارائهدهندگان سرویس، حافظه را از اولین توکن به بعد میسنجند؛ یعنی هرگونه تغییر در ابتدای جریان متن، بقیه درخواست را «مسموم» میکند. این یعنی دادههای یکسانی که پشت یک شخصیت (Persona) منحصربهفرد قرار دارند، هر بار به عنوان دادهای کاملاً جدید پردازش میشوند.
بسیاری از برنامهنویسان از این الگو پیروی میکنند: ابتدا یک پرامپت سیستمی (System Prompt) منحصربهفرد برای تعریف شخصیت هر عامل مینویسند و سپس حجم زیادی از دادههای مشترک را قرار میدهند. چون شخصیت هر عامل متفاوت است، پیشوند درخواستها در همان توکن اول تغییر میکند و مدل تصور میکند با یک درخواست کاملاً جدید روبهرو است.
کالبدشکافی فنی شکست حافظه
در یک محیط که ۱۰ عامل مختلف باید یک سند واحد، دادههای بازار یکسانی و کلاً متریدهای مشابهی را تحلیل کنند، هدف این است که هزینهٔ پردازش آن بستر متنی (Context) گرانقیمت را فقط یکبار بپردازید و ۹ بار دیگر با کسری از آن هزینه بخوانید. اما نویسنده این گزارش دریافت که نرخ موفقیت حافظه (Cache Hit Rate) در اکثر مدلها به زیر ۷٪ رسیده است. دلیل این شکست در ترتیب توکنها به شرح زیر است:
- پرامپت سیستمی: شامل شخصیت منحصربهفرد عامل است. این بخش از چند صد توکن تشکیل شده که نحوه استدلال یک عامل خاص را توصیف میکند. چون این بخش برای هر عامل متفاوت است، پیشوند تقریباً از همان توکن اول واگرا میشود.
- پرامپت کاربر: شامل بستر متنی (Context) مشترک و حجیم است. این بخش از چندین هزار توکن از مطالب منبع تشکیل شده که برای همه عاملها یکسان است.
وقتی این موارد به صورت یک جریان تخت از توکنها خوانده میشوند — که روش پردازش ارائهدهندگان سرویس است — شخصیت منحصربهفرد مانع از آن میشود که چندین هزار توکنِ بستر یکسانی که پشت آن قرار دارد، با حافظه تطبیق پیدا کنند. در نتیجه، سیستم ده نسخه یکسان از یک بستر متنی ایجاد میکند و باعث میشود ده بار قیمت کامل پرداخت شود.
اثبات ریاضی Mismatch
نویسنده برای اینکه به حدس و گمان متکی نباشد، هر دو نیمه از هر فراخوانی برای یک آیتم کاری را هش (Hash) کرد و تعداد مقادیر متمایز را با استفاده از یک کوئری SQL شمرد:SELECT COUNT(DISTINCT prompt_sha256) AS distinct_user, COUNT(DISTINCT system_sha256) AS distinct_system FROM agent_calls WHERE item_id = ?.
نتایج قطعی بود: distinct_user = 1 و distinct_system = 10. این تایید کرد که نیمه گرانقیمت پرامپت در تمام ۱۰ فراخوانی از نظر بایتی یکسان بوده است، در حالی که نیمه ارزانقیمتی که در جلو قرار داشت، در هر بار متفاوت بود.
این شکست ساختاری در گزارشهای مصرف ارائهدهنده نیز منعکس شد که سهم توکنهای ورودی حافظهشده (Cached) را در پنج مدل مختلف نشان میداد:
- مدل A: ۰.۰٪
- مدل B: ۰.۰٪
- مدل C: ۳.۴٪
- مدل D: ۶.۲٪
- مدل E: ۱۱.۰٪
این اعداد پایین و غیرصفر، به عنوان برخوردهای تصادفی (Incidental Collisions) بین فراخوانیهای نامربوط شناسایی شدند و نه بازیافت ساختاری تعمدی که برای کارآمدی سیستم لازم است. اگر طراحی درست بود، باید ۹ مورد از ۱۰ خواندن بستر متنی، Cache Hit میشدند.
راهکار اصلاح ساختار
برای بازیابی نرخ موفقیت حافظه، ترتیب پرامپت باید از «بیشترین اشتراک» به «کمترین اشتراک» تغییر کند. راهکار عملی شامل معکوس کردن آرایه پیامهای استاندارد است تا ارائهدهنده یک پیشوند پایدار را هش کند:
۱. پرامپت سیستمی: بستر متنی مشترک و گرانقیمت (یکسان $\rightarrow$ کش میشود). این بخش در ابتدا قرار میگیرد تا اولین عامل قیمت کامل را بپردازد و حافظه را برای بقیه «گرم» کند.
۲. پرامپت کاربر: ترکیب شخصیت عامل و سؤال (مثلاً: f"{agent_persona}\n\n{question}"). این بخش متغیر است و در آخرین جایگاه قرار میگیرد.
در این چیدمان بازنگریشده، ۹ عامل باقیمانده بستر مشترک را با نرخهای حافظه میخوانند که معمولاً حدود ۵ برابر ارزانتر از یک خواندن تازه (Fresh Read) است. تنها بخش بدون حافظه، بلوک کوچک شخصیت در انتهای متن است که تنها بخشی است که کاربر باید برای آن قیمت کامل بپردازد.
موازنهٔ رفتاری و هزینهای
جابهجایی شخصیت از نقش سیستمی به نقش کاربر، تغییری بدون هزینه نیست. برخی مدلها به دستورات نقش سیستمی وزن بیشتری میدهند؛ بنابراین تنزل رتبه شخصیت به پرامپت کاربر ممکن است باعث شود مدل بیشتر «حاشیه» برود یا دستورات را با سختگیری کمتری دنبال کند. برای مثال، عاملی که صراحتاً دستور گرفته موضعی نامحبوب را دفاع کند، ممکن است اگر این دستور از پرامپت سیستمی به کاربر منتقل شود، این جسارت یا تندی را از دست بدهد.
از آنجایی که خروجی همچنان خوشساخت و پذیرفتنی خواهد بود، این موازنه بین هزینه و رفتار ممکن است نادیده گرفته شود. برای کاهش این اثر، نویسنده توصیههای زیر را ارائه میدهد:
- تست A/B: مقایسه نمونهای از آیتمها برای مشاهده اینکه آیا تصمیمات و خروجیهای واقعی بر اساس چیدمان تغییر میکنند یا خیر (به جای اینکه فقط بررسی شود آیا پاسخ قابل تجزیه/Parse است یا نه).
- راهکار میانه: حفظ یک دستورالعمل کوتاه و پایدار در پرامپت سیستمی که برای همه عاملها یکسان باشد، و سپس انتقال تنها تمایزات خاص هر عامل به پیام کاربر.
این رویکرد ترکیبی، چارچوب نقش سیستمی را حفظ کرده و در عین حال یک پیشوند پایدار برای حافظه ایجاد میکند، هرچند اثربخشی آن به این بستگی دارد که چه مقدار از رفتار مدل به نقش سیستمی گره خورده باشد.
توصیههای عملیاتی
بهینهسازی باید روی دستهبندی (Batching) و ابزارگذاری (Instrumentation) متمرکز شود. حافظه پاداش به پیشوندهای پایدار پاداش میدهد و هر بایتی که در مراحل اولیه تغییر کند، حافظه را برای تمام موارد بعدی نابود میکند.
- استراتژی دستهبندی: درخواستها را بر اساس مدل گروهبندی کنید، نه بر اساس آیتم کاری. استفاده چرخشی (Round-robin) بین مدلها برای هر آیتم، باعث میشود حافظه در هر فراخوانی «راهاندازی سرد» (Cold Start) شود؛ اما گروهبندی بر اساس مدل، پیشوند را گرم نگه میدارد.
- ابزارگذاری: اجزای درخواستها را هش کنید و تعداد مقادیر متمایز را برای هر آیتم کاری بشمارید تا شکهای مبهم به باگهای ساختاری قطعی تبدیل شوند.
- پایش مستمر: بهطور منظم تفکیک توکنهای حافظهشده در مقابل توکنهای بدون حافظه را در گزارشهای مصرف بررسی کنید. نرخ نزدیک به صفر در یک حجم کاری با بستر مشترک بدیهی، یک باگ طراحی است، نه یک نوسان قیمتی.
این یافته نشان میدهد که اشکال پیشفرض پیامها که در اکثر آموزشهای SDK پیشنهاد میشود — یعنی شخصیت در سیستم و محتوا در کاربر — حافظه-ناآگاه (Cache-unaware) هستند. برای عملیات Fan-out که در آن شخصیتهای زیادی یک بستر مشترک دارند، این آموزشها در واقع نقشهراهی برای حداکثر کردن هزینهها هستند. در حالی که انتخاب مدلهای ارزانتر یک اهرم مفید است، اصلاح ساختار پیشوند میتواند فرصت بسیار بزرگتری برای کاهش هزینهها باشد.
گام بعدی شما
- ساختار پرامپتهای خود را بررسی کنید و دادههای حجیم و مشترک را به ابتدای جریان منتقل کنید.
- نرخ Cache Hit را در پنل ابری خود چک کنید؛ اگر زیر ۲۰٪ است، ترتیب توکنها را بازنگری کنید.
- برای مدلهایی که حساسیت بالایی به System Prompt دارند، از «راهکار میانه» برای حفظ کیفیت استفاده کنید.
اما تأثیر این بهینهسازی بر سرعت پاسخدهی (Latency) حتی چشمگیرتر از کاهش هزینه است. این موضوع در کنار چالشهای جابهجایی حافظه در مدلهای مختلف اهمیت مییابد؛ چنانکه در بررسی حافظههای موقت برداری و قابلیت انتقال آنها تحلیل کردیم که ساختار حافظه همواره با محدودیتهای فنی مواجه است. در تحلیل ما دربارهی KV Cache و تأخیر استنتاج بیشتر بخوانید.




گفتگو