تصور کنید برنامهنویسی هستید که یک سرور حرفهای بر اساس پروتکل زمینهٔ مدل (MCP) ساخته است، اما سیستم در سادهترین پرسوجوهای چندحسابی شکست میخورد چون شناسههای حساب را به جای آرگومانهای ابزار، به عنوان وضعیت نشست در نظر گرفته است. این شکست باعث شد مایکل کامینسکی در ۷ سپتامبر ۲۰۲۶ به یک نتیجه کلیدی برسد: ابزاری که متغیری را که کاربر واقعاً تغییر میدهد پنهان کند، ابزار نیست، بلکه فقط یک دموی نمایشی است.
بسیاری از توسعهدهندگان با عاملهای هوش مصنوعی مثل انسانی برخورد میکنند که پشت یک ترمینال نشسته است و فرض میکنند عامل در یک نشست (Session) واحد باقی میماند. اما ارزش اصلی یک عامل (Agent) — شبیه دستیاری که میتواند همزمان چندین پرونده را باز کند و بین آنها مقایسه انجام دهد — در توانایی استدلال همزمان روی چندین منبع داده است. طبق گزارش کامینسکی، وقتی یک ابزار فاقد پارامتری صریح برای متغیر اصلی (مثل شناسه حساب) باشد، هیچ مقدار مهندسی پرامپت نمیتواند این شکاف معماری را پر کند.
شکاف پارامترها
کامینسکی دریافت که اگرچه سرور MCP او ۳۴ ابزار داشت، اما حیاتیترین آنها مانند get_account_positions ، get_account_summary و get_account_balances هیچ طرح پارامتری نداشتند و هیچ آرگومانی نمیپذیرفتند. این ابزارها در واقع ورودی نمیگرفتند. این موضوع نشان میدهد که استفاده از قراردادهای سختگیرانه در تعریف ابزارها تا چه اندازه میتواند نرخ خطای عاملها را در محیطهای عملیاتی کاهش دهد.
به دلیل اینکه سرور به هر حسابی که هنگام ورود فعال بود متصل میشد، عامل نمیتوانست پاسخ دهد که تفاوت یک صندوق مشمول مالیات با یک حساب Roth IRA یا یک حساب Traditional IRA چیست. او نمیتوانست مجموع نقدینگی را در حسابهای مختلف محاسبه کند یا تشخیص دهد کدام داراییها برای استراتژی Covered Call مناسب هستند.
برای حل این مشکل، او یک اسکریپت پایتون ۲۲۸ خطی نوشت که ساختار Client Portal API را بازسازی میکند. راهکار ساده است: اگر کاربر در هر فراخوانی، مقدار X را تغییر میدهد، X باید پارامتری باشد که مدل بتواند ببیند و پر کند، نه یک تنظیم پنهان، وضعیت نشست یا فرآیند ورود.
ارکستراسیون و پیشنیازها
طراحی مؤثر ابزار نیازمند مدیریت وابستگیها است. همانطور که در تحلیل قبلی ما دربارهی امنیت مدلهای بازمتن اشاره کردیم، مدیریت دسترسیها باید در لایهی زیرساخت باشد نه در لایهی دستورات. در API مورد بحث، ساختار به درستی طراحی شده است: ابتدا GET /portfolio/accounts تمام حسابهای زیر یک ورود را فهرست میکند و سپس GET /portfolio/{id}/summary و /ledger و /positions/{page} شناسه حساب را بهطور صریح دریافت میکنند.
با این حال، این API یک ترتیب سختگیرانه را تحمیل میکند. شما باید حتماً ابتدا /portfolio/accounts را فراخوانی کنید و سپس به سراغ هرگونه فراخوانی /portfolio/{id}/* بروید، در غیر این صورت سیستم خطای ۴۰۱ یا ۵۰۰ بازمیگرداند.
به جای اینکه مدل را مجبور کنیم این توالی را به خاطر بسپارد، پوشش ابزار (Tool Wrapper) باید پیشنیازها را بهطور خودکار مدیریت کند. این رویکرد در واقع نوعی لایه نگهبان برای جلوگیری از خطاهای پرهزینه ایجاد میکند تا مدل مستقیماً با پیچیدگیهای زیرساختی مواجه نشود. وقتی ابزاری به فراخوانی قبلی نیاز دارد، پیام خطا باید باعث شود Wrapper گام مفقود را اجرا کند تا عامل از شکستهای لولهکشی زیرساختی مصون بماند.
نرمالسازی برای تصمیمگیری
عاملها اغلب با دادههای خام دستوپنجه نرم میکنند. برای مثال، یک رکورد دارایی در یک کارگزاری ممکن است دهها فیلد داشته باشد و برای یک نماد معاملاتی (Ticker)، بسته به نوع دارایی، از سه نام مختلف استفاده کند.
کامینسکی پیشنهاد میکند متغیرهای تصمیمگیری در لحظهٔ استخراج داده پیشمحاسبه شوند. به جای اینکه از عامل بخواهیم محاسبه کند چند لوت ۱۰۰ سهمهای برای یک استراتژی Covered Call وجود دارد، اسکریپت این مقدار را قبل از رسیدن به مدل محاسبه میکند:
- محاسبه: برای هر دارایی با مقدار مثبت،
covered_call_lots = quantity // 100. - برچسبگذاری: فیلد
covered_call_candidateزمانی true میشود که مقدار لوت حداقل یک باشد.
با نامگذاری فیلدها بر اساس تصمیمی که پشتیبانی میکنند، احتمال خطای محاسباتی مدل کاهش مییابد. عاملی که بخواهد یک متغیر تصمیم را از ۶ فیلد خام استخراج کند، به اندازه انسانی که محاسبات را ذهنی انجام میدهد، دچار خطا میشود. فیلدهای خام باید برای بازرسی (Audit) در دسترس بمانند، اما متغیر تصمیم باید سیگنال اصلی باشد.
یک نکته در کد باقی مانده است: شمارش لوتها فقط بر اساس مقدار است و بررسی نمیکند که آیا آن نماد واقعاً زنجیره آپشن (Option Chain) لیست شده دارد یا خیر. بنابراین، دارایی بدون آپشن هم ممکن است به عنوان کاندید نمایش داده شود.
امنیت ساختاری در برابر پرامپت
یکی از خطرناکترین اشتباهات در طراحی عامل، تکیه بر متن برای اعمال امنیت است. سرور MCP مذکور ۹ ابزار نوشتنی (Write) داشت، از جمله create_order_instruction که در کنار ابزارهای خواندنی قرار داشت.
بسیاری از توسعهدهندگان در پرامپت سیستمی (System Prompt) مینویسند «معامله نکن»، اما متن قانونی است که به محض اضافه شدن یک مسیر نوشتنی جدید، اعتبارش را از دست میدهد. کامینسکی محیط را بهطور ساختاری «فقط خواندنی» کرد.
اسکریپت او اصلاً شامل توابعی برای ارسال سفارش نیست. با استفاده از نقاط انتهایی (Endpoints) فقط GET، او تضمین میکند که هیچ تزریق پرامپت (Prompt Injection)، فراخوانی اشتباه ابزار یا تغییر در دستورات نمیتواند منجر به جابجایی پول شود. اگرچه این کار باعث ایجاد اصطکاک میشود — مثلاً برای تنظیم یک هشدار قیمت ساده نیاز به کدنویسی جدید است — اما این اصطکاک بسیار ارزانتر از ریسکهای جایگزین است.
مدیریت داخلی شکستها
مسیر عملیاتی به یک گیتوی محلی در https://localhost:5000 وابسته است که دارای گواهینامه self-signed و نشستی است که منقضی میشود. برای جلوگیری از این مورد، اسکریپت در هر اجرا یک درخواست POST به /tickle میفرستد تا نشست زنده بماند.
وقتی سیستم باز هم شکست میخورد، ابزار خطا را مدیریت میکند، نه عامل. اگر عامل مدیریت شکست را بر عهده بگیرد، یک نوبت کامل از استنتاج (Inference) — یعنی همان لحظهای که مدل جواب تولید میکند — را صرف لولهکشی زیرساخت میکند و ممکن است تصمیمات متناقضی بگیرد. این وضعیت دقیقاً همان جایی است که پیامهای خطای خام به عنوان پرامپت عمل کرده و باعث ایجاد حلقههای تکرار بیپایان در رفتار عامل میشوند. به جای آن، منطق جایگزین در کد ابزار قرار دارد:
- تلاش مجدد: ۵ مرتبه با تأخیر نمایی محدود شده (۲، ۴، ۸ و ۱۵ ثانیه).
- مسیر جایگزین: استفاده از Flex Web Service، یک فراخوانی REST با احراز هویت توکنی که صورتحساب XML بازمیگرداند.
- پایش: سرویس Flex تا ۱۰ بار در فواصل ۵ ثانیهای بررسی میشود تا گزارش تولید شود.
- شفافیت: فایل خروجی دارای فیلد منبع (
cpapi_liveیاflex_backup) است تا مصرفکننده بداند دادهها زنده هستند یا مربوط به پایان روز.
واقعیت احراز هویت
حتی کاملترین ابزارها هم اگر محیط احراز هویت را نادیده بگیرند، شکست میخورند. کامینسکی اشاره کرد که تا ۶ سپتامبر ۲۰۲۶، اسکریپت او حتی یک بار استخراج داده را کامل نکرده بود چون دایرکتوری data/ هرگز ساخته نشده بود.
دلیل آن احراز هویت بود. گیتوی نیاز به ورود از طریق مرورگر با احراز هویت دو مرحلهای (2FA) دارد و نشست پس از عدم فعالیت میمیرد. یک شغل زمانبندیشده (Scheduled Job) نمیتواند این نیاز را برآورده کند و جایگزین Flex هم بدون استفاده ماند چون توکن و Query ID آن در تنظیمات رشتههای خالی بودند.
او نتیجه گرفت که طراحی درست برای یک عامل زمانبندیشده، اولویت دادن به مسیری است که هرگز از انسان درخواست تایید دوم نکند. برای عاملی که ساعت ۹ صبح روزهای کاری اجرا میشود، دادههای درونروزی کمتر از مسیری است که واقعاً بهصورت بدون سر (Headless) کار کند.
این چرخش از «اولیت با داده زنده» به «اولیت با داده دستهای»، درس نهایی در طراحی برای محیط واقعی است، نه محیط ایدهآلی که توسعهدهنده تصور میکند.
گام بعدی شما
- پارامترهای ابزارهای خود را بررسی کنید؛ هر متغیری که کاربر تغییر میدهد باید به صورت صریح در طرح ابزار باشد.
- منطق مدیریت خطا و تلاش مجدد (Retry) را از پرامپت به کد Wrapper منتقل کنید.
- برای ابزارهای حساس، دسترسیهای نوشتنی را بهطور کامل از کد حذف کنید تا امنیت ساختاری ایجاد شود.
اما داستان سختافزاری این تحول حتی شگفتانگیزتر است — به تحلیل ما دربارهی تراشههای Blackwell مراجعه کنید.




گفتگو