تصور کنید برنامهنویسی هستید که عاملی ساخته تا رزروهای هتل را مدیریت کند، اما مدل بهجای ارسال کد رزرو، عبارت «همانی که قبلاً گفتم» را میفرستد؛ این خروجی از نظر فنی یک رشته متنی است، اما از نظر منطقی کاملاً بیفایده است. طبق راهنمای فنی منتشر شده در ۶ اوت ۲۰۲۶ توسط xgabriel.com، شکاف میان «شکل ساختاری» و «معنای منطقی» دقیقاً همان جایی است که اکثر فراخوانیهای ابزار در عاملهای هوش مصنوعی شکست میخورند.
بسیاری از توسعهدهندگان برای اطمینان از دریافت نوع داده درست، به کتابخانههایی مثل Zod تکیه میکنند. این ابزارها — که شبیه نگهبانی در ورودی هستند و فقط اجازه میدهند کسانی که کارت شناسایی درست دارند وارد شوند — مانع از کرش کردن سیستم میشوند، اما نمیتوانند تضمین کنند که آن داده واقعاً در پایگاهداده وجود دارد. وقتی مدل یک شناسه (ID) باورپذیر اما ساختگی میفرستد، سیستم معمولاً خطای کلی «یافت نشد» برمیگرداند که هیچ راهنمایی برای اصلاح خطا به مدل نمیدهد.

همانطور که در تحلیلهای قبلی ما دربارهی امنیت مدلهای بازمتن اشاره کردیم، مدیریت ورودیها اولین خط دفاعی در برابر رفتارهای پیشبینینشده است. در همین راستا، پیادهسازی چهار لایه دفاعی برای مهار تزریق پرامپت میتواند امنیت عاملهای TypeScript را در برابر ورودیهای مخرب افزایش دهد. برای حل این مشکل، توسعهدهندگان باید میان «خطاهای ساختاری» و «خطاهای معنایی» تمایز قائل شوند. خطاهای ساختاری مربوط به فرم هستند؛ مثلاً نبود یک فیلد، اشتباه بودن نوع داده، یا مقداری در یک Enum که در لیست تعریف شده نیست. Zod مالک این دسته از خطاهاست و آنها را بهطور کامل میگیرد. اما خطاهای معنایی به معنای داده در برابر واقعیتهای دنیای واقعی و قوانین کسبوکار مربوط میشوند. برای مثال، یک شناسه ممکن است فرم صحیحی داشته باشد اما به هیچ رکوردی اشاره نکند، یا تاریخی درست باشد اما مربوط به گذشته باشد. Zod نمیتواند اینها را ببیند چون به وضعیت لحظهای پایگاهداده دسترسی ندارد.
۵ حالت رایج شکست در فراخوانی ابزار
بر اساس بررسیهای xgabriel.com، پنج الگوی تکراری در فراخوانیهای شکستخورده دیده میشود:
- جایگزینهای ارجاعی: مدل بهجای شناسه واقعی، از عباراتی مثل «رزرو قبلی»، «همان قبلی» یا تگهایی مثل
<id>استفاده میکند. این اتفاق زمانی میافتد که طرحواره (Schema) فقط یک رشته متنی ساده مثلbookingId: z.string()تعریف شده باشد و هیچ محدودیت فرمتی روی آن نباشد. - تاریخهای زبان طبیعی: ارسال عباراتی مثل «سهشنبه آینده»، «دو هفته دیگر» یا «آخر ماه». در حالی که
z.string()اینها را میپذیرد، اما استفاده ازz.coerce.date()منجر به ایجاد یک شیء «تاریخ نامعتبر» (Invalid Date) میشود که با این حال همچنان شرطinstanceof Date === trueرا پاس میکند و از فیلتر ساختاری رد میشود. - مقادیر نزدیک به هدف: ارائه مقداری که درست به نظر میرسد اما در لیست فعلی پایگاهداده نیست. این مورد زمانی رخ میدهد که فیلدها بهجای استفاده از لیستهای ثابت در
z.enum، بهصورت رشتههای آزاد تعریف شده باشند چون مقادیر در دیتابیس پویا هستند. - فیلترهای بیش از حد گسترده: ارسال فیلترهایی مثل
{ status: undefined, limit: undefined }. این ورودی از نظر نحوی کاملاً معتبر است اما باعث اجرای یک اسکن کامل روی جدول (Full Table Scan) میشود که میتواند پنجره متنی (Context Window) را بهطور کامل اشغال کند — شبیه میز کاری که ناگهان با هزاران برگه کاغذ پوشانده شود و جای هیچچیز نماند. - شناسههای ساختگی باورپذیر: تولید شناسهای مثل
bk_00000000که پیشوند و طول درستی دارد اما وجود خارجی ندارد. این نوع خطا بدون جستوجو در دیتابیس، از یک شناسه معتبر قابل تشخیص نیست.
مقاومسازی طرحواره (Schema)
قبل از ساخت لایه معنایی، توسعهدهندگان باید تا حد ممکن محدودیتها را به درون طرحواره Zod منتقل کنند. اگر طرحواره JSON ابزار از شیء Zod تولید شود، این محدودیتها در زمان تولید خروجی توسط مدل اعمال میشوند.
برای مثال، استفاده از یک عبارت منظم (Regex) مثل /^bk_[0-9a-f]{12}$/ برای شناسهها، جایگزینهای ارجاعی را فوراً حذف میکند. جایگزینی z.coerce.date() با z.string().date()، ورودیهای زبان طبیعی مثل «سهشنبه آینده» را رد کرده و مدل را مجبور میکند از تاریخهای استاندارد ISO 8601 (مثلاً ۲۰۲۶-۰۸-۱۴) استفاده کند. همچنین، اضافه کردن .max(50) به فیلد limit، باعث میشود ارسال فیلترهای بیش از حد گسترده عملاً غیرممکن شود.

نکته حیاتی این است که پیام خطای داخل متد .regex() باید مخصوص مدل نوشته شود. بهجای یک خطای کلی، باید نوشت: «شناسه رزرو باید شبیه bk_a1b2c3d4e5f6 باشد. از خودتان چیزی نسازید؛ از شناسهای که توسط search_bookings بازگردانده شده استفاده کنید.» این کار یک «رد کردن» ساده را به یک «دستور مستقیم» تبدیل میکند.
پیادهسازی لایه معنایی
آنچه باقی میماند باید توسط یک بررسی معنایی اختصاصی که به وضعیت برنامه دسترسی دارد، مدیریت شود. این لایه بهجای پرتاب یک خطای استاندارد، باید یک پاسخ ساختاریافته از نوع Semantic<T> برگرداند. این نوع داده باید مشخص کند که آیا نتیجه ok است، یک message ارائه دهد و تعیین کند که آیا خطا «قابل تلاش مجدد» (retryable) است یا خیر.
بهعنوان مثال، اگر یک شناسه یافت نشد، لایه معنایی نباید فقط بگوید «خطا». بلکه باید سه مورد از آخرین رزروهای کاربر را از دیتابیس استخراج کرده و شناسههای آنها را به مدل برگرداند. این رویکرد، شکست را به یک دستور مستقیم تبدیل میکند تا مدل در گام بعدی شناسه درست را انتخاب کند. این استراتژی در واقع پاسخی به شکاف پیامد در عاملهای هوش مصنوعی است، جایی که استدلال درست مدل لزوماً به نتیجه عملی درست منجر نمیشود.
این روش همچنین از افشای اطلاعات جلوگیری میکند. اگر مدل سعی کند به رزرو کاربر دیگری دسترسی پیدا کند، سیستم باید خطایی غیرقابلتلاش برگرداند. پیام خطا باید بهطور عمدی از تایید وجود یا عدم وجود آن رزرو خودداری کند، زیرا افشای وجود داده برای کاربران دیگر از طریق پیامهای خطا یک ریسک امنیتی واقعی است.
علاوه بر این، لایه معنایی زمینه (Context) گمشده را تامین میکند. اگر مدل تاریخی در گذشته بدهد، خطا باید صریح باشد: «تاریخ ۲۰۲۶-۰۱-۰۱ در گذشته است. امروز ۲۰۲۶-۰۸-۰۶ است.» بدون این واقعیت، مدل احتمالاً دوباره حدس میزند و باز هم به شکل مشابهی شکست میخورد.
شکستن حلقه اصلاح
بدون این حفاظها، مدلها اغلب وارد «حلقه اصلاح» میشوند و یک فراخوانی شکستخورده را بارها تکرار میکنند. راهکار پیشنهادی این است که هر تلاش بر اساس نام ابزار و آرگومانهای خاص استفاده شده (مثلاً با استفاده از هشِ ورودی) کلیدگذاری و ثبت شود.
اگر یک فراخوانی یکسان بیش از دو بار شکست خورد، سیستم باید مدل را مجبور کند حدس زدن را متوقف کند. پیام خطا باید صریح باشد: «این فراخوانی مکرراً شکست خورده است. بهجای تکرار، شناسه رزرو را از کاربر بپرسید.»

این تغییر معماری، نقش پیامهای خطا را از «لاگهای سیستمی» به «مهندسی پرامپت» (Prompt Engineering) — هنر سؤال درست پرسیدن برای گرفتن بهترین جواب — تغییر میدهد. هر چیزی که به عنوان is_error: true علامتگذاری شود، مسیر گام بعدی را هدایت میکند. یک پیام خطای خوب باید از یک ساختار خاص پیروی کند: چه چیزی غلط بود، مقدار درست چه شکلی است و مقدار درست را از کجا میتوان پیدا کرد.
- بد: «ورودی نامعتبر» یا «خطای اعتبارسنجی در $.date»
- خوب: «تاریخ باید ISO 8601 باشد (۲۰۲۶-۰۸-۱۴). شما نوشتید سهشنبه آینده.»
- خوب: «رزرو bk_zzz یافت نشد. موارد موجود: bk_a1b2c3, bk_d4e5f6.»
- خوب: «مقدار limit باید بین ۱ تا ۵۰ باشد. شما ۵۰۰ فرستادید؛ بهجای آن از صفحهبندی استفاده کنید.»
برای توسعهدهندگانی که عاملهای عملیاتی میسازند، این به معنای گذار از «اعتبارسنجی ساده» به «ذهنیت تجزیه» (Parsing) است. بررسی معنایی فقط داده را تایید نمیکند، بلکه آن را به شیء واقعی مورد نیاز برای هندلر تبدیل میکند. با ارسال شیء نهایی (مثلاً رکورد واقعی رزرو) به تابع run ، هندلر از جستوجوی مجدد در دیتابیس جلوگیری میکند که احتمالاً میتوانست با نتیجه اول در تضاد باشد. در واقع، ادغام اعتبارسنجی و اصلاح کد میتواند مسیر بازرسی فنی را تغییر داده و کارایی سیستم را افزایش دهد.
Zod به شما میگوید آرگومانها فرم درستی دارند، اما فقط دادههای شما میگویند که آیا آنها «درست» هستند یا خیر. لایه دوم را بسازید و نتیجه را بهصورت پیامی که مدل بتواند روی آن عمل کند برگردانید تا خطاهای آرگومان بهجای تبدیل شدن به درخواست شکستخورده، در یک گام اضافی حل شوند.
اگر این مطلب مفید بود، مجموعه AI That Acts مرزهای ابزار را بهطور عمیق پوشش میدهد — از جمله طرحوارههایی که کل کلاسهای خطا را حذف میکنند، لایه معنایی، نتایج خطا به عنوان کانال اصلاح، و حفاظهایی که اجازه نمیدهند یک حلقه تلاش مجدد به یک صورتحساب هزینهبر تبدیل شود. مجموعه کامل در xgabriel.com/ai-in-typescript در دسترس است.
گام بعدی شما
- تمام پیامهای خطای API خود را بازبینی کنید و آنها را از حالت «گزارش فنی» به «دستورالعمل برای مدل» تغییر دهید.
- برای هر ابزاری که با دیتابیس در ارتباط است، یک لایه بررسی معنایی (Semantic Check) اضافه کنید که مقادیر پیشنهادی را در صورت خطا برگرداند.
- مکانیزم هشینگ برای ورودیها را پیاده کنید تا از تکرار بیدلیل فراخوانیهای شکستخورده جلوگیری کنید.
اما داستان سختافزاری این تحول حتی شگفتانگیزتر است — به تحلیل ما دربارهی تراشههای Blackwell مراجعه کنید.




گفتگو