یک فراخوانی سادهی generateText وقتی هیچ سقفی برای منابع تعریف نشده باشد، چقدر میتواند هزینه داشته باشد؟ در ۲ اکتبر ۲۰۲۶، یک بررسی فنی عمیق فاش کرد که Vercel AI SDK به توسعهدهندگان اجازه میدهد فراخوانیهای نامحدودی به مدل زبانی بزرگ (LLM) — شبیه کتابخانهداری که میلیاردها صفحه را خوانده و حالا با همان لحن جواب میدهد — ارسال کنند؛ اتفاقی که اپلیکیشنها را در معرض توقف کامل و جهشهای مالی شدید قرار میدهد. در واقع، این نقص فنی میتواند یک فراخوانی سادهی تابع را به یک صورتحساب نامحدود تبدیل کند.
این ریسک درست زمانی رخ میدهد که توسعهدهندگان از پرامپتهای ساده به سمت گردشهای کاری عاملمحور (Agentic) حرکت میکنند. همانطور که در تحلیل قبلی ما دربارهی تفاوت استدلال مدلها با سیستمهایی مثل AlphaGo اشاره کردیم، چالش فعلی صنعت کمتر به منطق مربوط است و بیشتر به «لولهکشی» هوش مصنوعی در محیط عملیاتی برمیگردد. در یک محیط واقعی، یک مدل پرحرف یا یک حلقهی تکرار ساده میتواند منابع را سریعتر از هر مهاجم بدخواشی تخلیه کند. این چالشهای عملیاتی اغلب با محدودیتهای زیرساختی گره خوردهاند؛ برای مثال، گلوگاه پهنایباند حافظه یکی از دلایل اصلی شکست مقیاسدهی سنتی در مدلهای زبانی است که هزینههای استنتاج را افزایش میدهد.
زمینه و تحلیل مصرف نامحدود
به نقل از مستندات فنی این بررسی، در زبان TypeScript، فراخوانی generateText تنها با یک مدل و پرامپت، معتبر شناخته میشود. سیستم تایپینگ اهمیتی نمیدهد که چه تعداد توکن (Token) — تکههای کوچکی از متن شبیه برشهای کیک که مدل میخورد — بازگردانده میشود، فرآیند چقدر زمان میبرد یا در نهایت چه کسی هزینه این نتیجه را پرداخت میکند.
این وضعیت نمونهای خاص از استاندارد OWASP LLM10 است که با عنوان «مصرف نامحدود» (Unbounded Consumption) شناخته میشود. اگرچه این SDK از اجرای بینهایت حلقههای فراخوانی ابزار (Tool-calling loops) جلوگیری میکند (زیرا مقدار stopWhen را بهصورت پیشفرض روی stepCountIs(1) تنظیم کرده است)، اما سایر تخصیصهای منابع بدون پیکربندی صریح، کاملاً باز و بدون سقف میمانند. این ناکارآمدی در تولید متن، دقیقاً همان نقطهای است که معماریهای فعلی AI در تصمیمگیریهای سریع دچار کندی میشوند و باعث اتلاف منابع میگردند.
برای مقابله با این مشکل، پلاگین eslint-plugin-vercel-ai-security منتشر شد تا سه نقص خاص را که با استانداردهای CWE (ضعفهای رایج امنیتی) مطابقت دارند، شناسایی کند. اینها صرفاً ترجیحات استایلی یا زیباییشناسی کد نیستند، بلکه مرزهای امنیتی حیاتی هستند:
جزئیات سه نشت منبع
- خروجی بدون سقف (CWE-770): فراخوانی
generateTextبدون تعیینmaxOutputTokensیعنی مدل میتواند تا رسیدن به سختترین محدودیت داخلی خود، متن تولید کند. توسعهدهندگان اغلب این پارامتر را نادیده میگیرند چون اختیاری است و در «مسیر خوشبینانه» (Happy Path) بهندرت به آن نیاز است. اما چون صورتحسابها بر اساس توکن است، نبود سقف یک ریسک مالی مستقیم است. نکته مهم این است که در نسخه ۴، این پارامترmaxTokensنام داشت؛ بنابراین راهنماهای نوشته شده برای نسخه ۴ ممکن است در بازبینی کد درست به نظر برسند، اما در عمل هیچ محدودیتی ایجاد نمیکنند. - درخواستهای بینهایت (CWE-400): این SDK هیچ مهلت زمانی (Timeout) پیشفرضی را تعریف نکرده است. در حالی که APIهایی با ساختار fetch معمولاً باید تایماوت داشته باشند، این مورد ندارد. اگر ارائهدهنده مدل بهجای خطا دادن، متوقف (Hang) شود، درخواست برای همیشه باز میماند. از نسخه ۶.۰.۱۴، پارامتر
timeoutبه عنوان یک پارامتر درجه اول اضافه شده است که ازtotalMs،stepMs،chunkMsوtoolMsپشتیبانی میکند. اگر از نسخههای قدیمیتر استفاده میکنید، باید بهصورت دستی یکAbortControllerپیادهسازی کنید. - جریانهای زامبی (CWE-404): استفاده از
streamTextبدونabortSignalباعث ایجاد یک باگ رهاسازی (Release bug) میشود. وقتی کلاینت ارتباطش را قطع میکند، سرور همچنان به تولید توکن و صورتحساب برای خوانندهای که هرگز توکنها را نخواهد دید، ادامه میدهد. این مورد در دسته CWE-404 قرار میگیرد زیرا منبع بهدرستی تخصیص یافته اما هرگز آزاد نشده است و اجازه میدهد هندلِ درخواست، طولانیتر از خودِ درخواست زنده بماند.

پیادهسازی و راهکارهای اصلاحی
طبق گزارش نویسنده این ابزار، رفع این مشکلات نیازمند تغییر رویکرد از «پارامترهای اختیاری» به «مرزهای اجباری» است. برای مثال، توسعهدهندگان باید maxOutputTokens را روی طولانیترین پاسخی تنظیم کنند که حاضرند هزینه آن را بپردازند. برای حل مشکل جریانهای زامبی، الگوی پیشنهادی این است که سیگنال درخواست به یک AbortController متصل شود:
const ac = new AbortController(); req.signal.addEventListener("abort", () => ac.abort()); const stream = streamText({ model, prompt, abortSignal: ac.signal });
این تغییر، فرض بنیادی توسعه هوش مصنوعی را عوض میکند: دیگر «مسیر خوشبینانه»، مسیر امن نیست. با متصل کردن این مسائل به OWASP LLM10، صنعت در حال تبدیل مدیریت توکن از یک «تنظیم کیفیت» به یک «اصول امنیتی» (Security Primitive) است.
حاکمیت و ابزارها
برای کسانی که بهجای لینتینگ ساده، مدیریت حاکمیتی (Governance) را بر عهده دارند، نویسنده پیشنهاد میکند به چارچوب NIST AI RMF ارجاع دهند. هدف این است که اطمینان حاصل شود هر تخصیص — چه توکن باشد، چه زمان ساعت-دیواری (Wall-clock time) یا طول عمر درخواست — یک سقف مرئی و تعریف شده داشته باشد.
توسعهدهندگان میتوانند این پلاگین امنیتی را از طریق دستور npm install --save-dev eslint-plugin-vercel-ai-security نصب کنند. این ابزار به Node 18+ نیاز دارد و از ESLint 8، 9 و ۱۰ پشتیبانی میکند. برای کسانی که از oxlint استفاده میکنند، این پلاگین از طریق jsPlugins: ["eslint-plugin-vercel-ai-security/oxlint"] قابل افزودن است، هرچند این قابلیت هنوز در مرحله آلفا است و تحت قوانین semver قرار ندارد.
گام بعدی شما
- اگر از Vercel AI SDK استفاده میکنید، فوراً پلاگین امنیتی مذکور را نصب کرده و کدهای خود را اسکن کنید.
- برای تمام فراخوانیهای
generateTextیک مقدار سختگیرانه برایmaxOutputTokensتعریف کنید. - در تمامی جریانهای متنی (
streamText)، پیادهسازیabortSignalرا برای جلوگیری از هزینههای پنهان اجباری کنید.
اما مدیریت هزینهها تنها بخشی از ماجراست؛ برای درک اینکه چگونه مدلهای کوچکتر میتوانند استنتاج را ارزانتر کنند، تحلیل ما درباره مدلهای SLM را بخوانید.




گفتگو