پرش به محتوای اصلی
پرش به محتوای مقاله

استفاده از Zod برای تبدیل خروجی‌های نامنظم هوش مصنوعی به داده‌های قابل‌اعتماد

·۲۱ مرداد ۱۴۰۵۸ دقیقه مطالعه۱ بازدید
راهنما
طراحی قرارداد خروجی با Zod Schema برای اعتبارسنجی داده‌ها
طراحی قرارداد خروجی با Zod Schema برای اعتبارسنجی داده‌ها
اشتراک‌گذاری
واقعاً چه چیز جدید است؟

جایگزینی اعتبارسنجی دستی با قراردادهای Zod که هم‌زمان تایپ‌های TypeScript و محدودیت‌های رمزگشایی مدل (Constrained Decoding) را یکپارچه می‌کند.

اگر امروز برنامه‌ای می‌نویسید که خروجی یک مدل زبانی را مستقیماً به رابط کاربری می‌فرستد، احتمالاً با خطاهای ۵۰۰ و کرش‌های ناگهانی دست‌وپنجه نرم می‌کنید. مشکل اینجاست که فاصلهٔ عمیقی میان رشته‌های متنی تولید شده توسط مدل و اشیایی (Objects) که کد شما برای اجرا نیاز دارد، وجود دارد. در حالی که مدل‌های هوش مصنوعی می‌توانند پاسخ‌های بسیار پیچیده‌ای تولید کنند، اما شکافی بحرانی بین خروجی رشته‌ای (String) مدل و شیء مورد نیاز یک کامپوننت وجود دارد. یک طرح‌واره (Schema) واحد در Zod این نقطه شکست رایج را حل می‌کند؛ زیرا با طرح‌واره به عنوان یک قرارداد رسمی برخورد کرده و به توسعه‌دهندگان اجازه می‌دهد محدودیت‌های ارسالی به مدل، اعتبارسنجی پاسخ و تایپ‌های TypeScript مصرفی در اپلیکیشن را به‌طور خودکار مدیریت کنند.

بسیاری از ادغام‌های هوش مصنوعی در محیط عملیاتی شکست می‌خورند چون با خروجی مدل زبانی بزرگ (LLM) — مثل کتابخانه‌داری که میلیاردها صفحه را خوانده و حالا با همان لحن کتاب‌ها جواب می‌دهد — به عنوان رشته‌هایی که «احتمالاً درست هستند» برخورد می‌کنند. در واقعیت، مدل‌ها مدام JSON را در میان متون توضیحی یا بلوک‌های Markdown می‌پیچانند یا برخی کلیدهای ضروری را کاملاً حذف می‌کنند. این وضعیت مرزی شکننده ایجاد می‌کند که در آن حتی یک براکت گم‌شده می‌تواند منجر به خطای ۵۰۰ و کرش کامل سیستم شود.

طبق یک راهنمای فنی که در ۱۲ اوت ۲۰۲۶ منتشر شد، راهکار خروج از این وضعیت، جایگزینی «امید به دریافت JSON» با «اجبار به رعایت قرارداد» است. این چرخش، خروجی هوش مصنوعی را از یک جریان غیرقابل‌پیش‌بینی به یک شیء داده‌ای اعتبارسنج‌شده تبدیل می‌کند که بقیه لایه‌های نرم‌افزاری می‌توانند به آن اعتماد کنند. این رویکرد در واقع تکامل یافته‌ی متدهای قدیمی است، همان‌طور که جایگزینی مهندسی پرامپت با سخت‌افزارهای JSON در استقرار مدل‌های زبانی، دقت سیستم‌ها را به شدت افزایش داد.

همان‌طور که در بحث‌های گذشته‌ی ما درباره‌ی امنیت مدل‌های بازمتن اشاره کردیم، اعتماد کورکورانه به خروجی مدل‌ها بزرگ‌ترین ریسک معماری در سیستم‌های مدرن است. این ریسک تنها به ساختار داده‌ها محدود نمی‌شود، بلکه در لایه‌های منطقی نیز تکرار می‌شود؛ برای مثال، شکاف معنایی در ابزارهای SQL نشان می‌دهد که درستی نحوی لزوماً به معنای صحت تجاری خروجی نیست.

استفاده از یک طرح‌واره (Schema) در کتابخانه Zod چهار مزیت هم‌زمان ایجاد می‌کند. برای مثال، یک طرح‌واره برای «تیکت پشتیبانی» (Ticket) را تصور کنید که فیلدهای زیر را تعریف می‌کند: عنوان (رشته، ۳ تا ۱۲۰ کاراکتر)، شدت خطا (Enum: کم، متوسط، زیاد، بحرانی)، بخش مربوطه (Enum: احراز هویت، صورت‌حساب، جستجو، API، رابط کاربری، سایر)، مراحل بازتولید (آرایه‌ای از رشته‌ها، ۱ تا ۸ مورد)، وضعیت تأثیر بر کاربران (بولیان) و تخمین ساعت (عدد ۰ تا ۲۰۰، که می‌تواند null باشد).

این ساختار چهار کاربرد حیاتی دارد:

  • اعتبارسنجی زمان اجرا (Runtime Validation): مانند یک نگهبان نهایی عمل می‌کند و تضمین می‌کند داده‌ها پیش از رسیدن به رابط کاربری، دقیقاً همان شکلی باشند که انتظار داریم.
  • ایمنی زمان کامپایل (Compile-time Safety): با استفاده از z.infer در TypeScript، تایپ‌ها به‌طور خودکار از طرح‌واره استخراج می‌شوند. این تضمین می‌کند که تایپ و بررسی اعتبارسنجی هرگز از هم فاصله نگیرند؛ و این اصلی‌ترین دلیل برتری Zod نسبت به تعریف دستی Interfaceها در کنار Guardهای دستی است.
  • محدود کردن مدل: طرح‌واره را می‌توان به JSON Schema تبدیل کرد. در Zod 4 متد z.toJSONSchema(schema) داخلی شده است، اما در Zod 3 این قابلیت وجود ندارد و باید از بسته مجزای zod-to-json-schema استفاده کرد. این JSON Schema به ارائه‌دهندگانی مثل OpenAI (مثلاً در مدل gpt-4o-mini با تنظیم response_format: { type: "json_schema", ... }) ارسال می‌شود تا رمزگشایی (Decoding) — لحظه‌ای که مدل واقعاً جواب تولید می‌کند — را محدود کند و تولید JSON غلط را به جای «نامحتمل»، «غیرممکن» سازد.
  • دستورالعمل‌های اصلاح: وقتی اعتبارسنجی شکست می‌خورد، Zod پیام‌های خطای ساختاریافته‌ای تولید می‌کند. توسعه‌دهندگان می‌توانند با تبدیل error.issues به خطوطی با فرمت path: message (مسیر: پیام)، قالبی خوانا ایجاد کنند که به عنوان دستورالعمل‌های دقیق برای تلاش دوم به مدل بازگردانده شود.

برای مدیریت این مرز، باید بین دو نوع شکست تفاوت گذاشت: رشته‌ای که اصلاً JSON معتبر نیست، یا JSONی که با طرح‌واره مطابقت ندارد. ترکیب این دو منجر به پرامپت‌های اصلاحی غلط می‌شود که مدل را گیج می‌کند.

به نقل از مستندات مذکور، برای استخراج صحیح داده‌ها باید یک فرآیند استخراج مستحکم طراحی شود تا با این واقعیت که مدل‌ها بیش از آنچه اعتراف می‌کنند JSON را در متن یا فنس‌ها می‌پیچانند، مقابله کند:

  • پاک‌سازی و حذف فنس‌ها: ابتدا خروجی خام Trim شده و با استفاده از Regular Expressions، بلوک‌های کد Markdown (مثل ```json ... ```) حذف می‌شوند.
  • جداسازی براکت‌ها: اگر فنسی یافت نشد، منطق برنامه به دنبال اولین وقوع { یا [ می‌گردد و رشته را تا آخرین } یا ] متناظر برش می‌زند. این کار باعث می‌شود شیء JSON از هرگونه پرکننده یا متون گفتاری اطراف آن جدا شود.

در استراتژی اعتبارسنجی، استفاده از safeParse به جای parse توصیه می‌شود. پرتاب یک ZodError در یک Route Handler معمولاً منجر به خطای ۵۰۰ و نمایش Stack Trace می‌شود. اما استفاده از safeParse این کرش احتمالی را به یک وضعیت قابل‌بازیابی با یک گام بعدی مشخص تبدیل می‌کند.

برای اصلاح خطاها، به جای حلقه‌های تکرار بی‌نهایت، از یک «نردبان ارتقاء» (Escalation Ladder) استفاده کنید که مقرون‌به‌صرفه‌ترین استراتژی است. مدلی که JSON تقریباً درستی تولید کرده، معمولاً وقتی دقیقاً به او گفته شود چه چیزی اشتباه بوده، در تلاش بعدی موفق می‌شود:

۱. تلاش با مدل ارزان: شروع با مدل‌های کم‌هزینه (مثل gpt-4o-mini) با استفاده از رمزگشایی محدود شده (در صورتی که ارائه‌دهنده پشتیبانی کند).
۲. اصلاح هدفمند: در صورت شکست، یک «نوبت اصلاح» (Repair Turn) فعال کنید. این شامل ارسال یک پرامپت سیستمی («تو JSONهای خراب را اصلاح می‌کنی. فقط شیء JSON اصلاح شده را برگردان. بدون متن، بدون فنس کد، بدون توضیح.»)، خروجی خراب و جزئیات دقیق خطای Zod است. این مرحله ارزان است چون به جای ارسال مجدد کل سند (که ممکن است هزاران توکن باشد)، فقط چند صد توکن ارسال می‌شود.
۳. جایگزینی با مدل قدرتمند: اگر اصلاح شکست خورد، یک تلاش نهایی با مدلی با قابلیت بالا (مثل gpt-4o) انجام دهید. این آخرین هزینه است.
۴. توقف سخت: بعد از سه تلاش، عملیات باید متوقف شود. اگر مدل دو بار در برابر یک پیام خطای صریح شکست خورد، احتمالاً هرگز در بار سوم موفق نمی‌شود؛ زیرا یا مدل با طرح‌واره مخالف است یا اطلاعات مورد نیاز در منبع وجود ندارد.

این سقف مانع از «حلقه‌های تکرار نامحدود» و صورت‌حساب‌های نجومی API می‌شود. با محدود کردن بدترین حالت به تقریباً سه برابر بهترین حالت، توسعه‌دهندگان می‌توانند بودجه‌ای پیش‌بینی‌پذیر داشته باشند. در نهایت، سیستم به جای پرتاب Exception، مقدار null برمی‌گرداند تا فراخواننده تصمیم بگیرد که آیا مورد را برای بررسی انسانی در صف قرار دهد، نتیجه‌ای ناقص نشان دهد یا از کاربر بخواهد درخواستش را بازنویسی کند.

طراحی طرح‌واره‌هایی که مدل‌ها بتوانند واقعاً پر کنند نیز هنر است. بسیاری از شکست‌های طرح‌واره در واقع شکست‌های طراحی هستند. چند قانون طلایی در این زمینه وجود دارد:

  • تخت بودن به جای تو در تو: عمق زیاد، دقت را بدون هیچ افزایشی در بیانگری، کاهش می‌دهد. سه سطح تو در تو، خطاهای ساختاری بیشتری نسبت به سه شیء سطح‌بالا تولید می‌کند که به‌طور جداگانه استخراج شده‌اند.
  • استفاده از Enum به جای String: استفاده از z.enum([...]) یک مجموعه بسته فراهم می‌کند. استفاده از z.string() آزاد برای یک دسته‌بندی، اغلب منجر به تولید چهارده املای مختلف از یک کلمه در میان هزار سند می‌شود.
  • Nullable به جای Optional: نبود یک کلید مبهم است؛ ممکن است به معنای «غیرقابل اعمال» یا «نیافت شده» باشد. اما یک null صریح (مثلاً z.number().nullable()) تصمیمی است که مدل گرفته و اپلیکیشن می‌تواند بر اساس آن عمل کند.
  • توضیحات (Descriptions): افزودن .describe("ISO 8601 date, or null") به فیلدها، دستورالعمل‌ها را مستقیماً وارد JSON Schema تولید شده می‌کند. این ارزان‌ترین راه برای بهبود دقت است.
  • عدم استفاده از مقادیر محاسباتی: مدل‌ها در محاسبات ریاضی غیرقابل اعتماد هستند. هرگز مجموع، درصد یا تعداد نخواهید؛ داده‌های خام را استخراج کرده و کل را در TypeScript محاسبه کنید.
  • آرایه‌های محدود: استفاده از .max(20) روی یک آرایه، ابزاری برای کنترل هزینه است. یک آرایه نامحدود باعث می‌شود یک پاسخ ۲۰۰ توکنی در ورودی‌های غیرعادی به ۴۰۰۰ توکن تبدیل شود.

در نهایت، چالش استریم کردن (Streaming) خروجی‌های ساختاریافته وجود دارد؛ چون یک رشته JSON ناقص تا رسیدن آخرین براکت، نامعتبر است. توسعه‌دهندگان دو گزینه صادقانه دارند:

اول، استریم کردن وضعیت (Status Streaming)؛ یعنی شیء را استریم نکنید، بلکه وضعیت را استریم کنید. پیام‌هایی مثل «در حال خواندن سند» و «در حال استخراج فیلدها» را نشان دهید و نتیجه نهایی را تنها پس از اعتبارسنجی کامل رندر کنید. برای ویژگی‌های پر کردن فرم، این تجربه کاربری بهتری نسبت به تماشای ظاهر شدن براکت‌ها دارد و کد کمتری می‌طلبد.

دوم، اعتبارسنجی با طرح‌واره تسهیل‌شده (Relaxed Schema)؛ با استفاده از Ticket.partial() نسخه‌ای از طرح‌واره را بسازید که در آن تمام فیلدها اختیاری هستند. این به رابط کاربری اجازه می‌دهد فیلدها را هم‌زمان با رسیدن، با استفاده از یک پارسر JSON افزایشی و منعطف رندر کند. با این حال، این کار یک وابستگی واقعی و منبعی برای باگ‌های ظریف ایجاد می‌کند.

صرف‌نظر از انتخاب، طرح‌واره سخت‌گیرانه باید آخرین دروازه برای هر داده‌ای باشد که ذخیره می‌شود یا هزینه ایجاد می‌کند. یک طرح‌واره تسهیل‌شده صرفاً برای راحتی در رندر است و هرگز نباید به عنوان مرز اعتبارسنجی استفاده شود.

این چرخش معماری، هوش مصنوعی را از یک «جعبه سیاه» که ممکن است اپلیکیشن را خراب کند، به یک ارائه‌دهنده داده پیش‌بینی‌پذیر تبدیل می‌کند. با محدود کردن هزینه و ساختار، توسعه‌دهندگان می‌توانند برای بدترین سناریو بودجه‌بندی کنند و در عین حال نرخ موفقیت بالایی داشته باشند.

گام بعدی شما

  • اگر از JSON.parse ساده استفاده می‌کنید، همین امروز کتابخانه Zod را جایگزین کنید تا از کرش‌های Runtime خلاص شوید.
  • برای کاهش هزینه‌ها، ابتدا از مدل‌های کوچک با json_schema استفاده کنید و فقط در صورت شکست به مدل‌های بزرگتر سوییچ کنید.
  • تمام فیلدهای حساس طرح‌واره‌های خود را با متد .describe() تجهیز کنید تا نرخ توهم مدل کاهش یابد.

اما مدیریت حافظه در این مدل‌ها برای حفظ ساختار در گفتگوهای طولانی چالش دیگری است — به تحلیل ما درباره‌ی پنجره متنی (Context Window) مراجعه کنید.

چرا این موضوع مهم است؟

این متدولوژی با تکیه بر تخصص مهندسی نرم‌افزار، عدم قطعیت مدل‌های زبانی را به پیش‌بینی‌پذیری تبدیل می‌کند. نتیجه آن کاهش چشمگیر نرخ خطای سیستم‌های عملیاتی و بهینه‌سازی هزینه‌های API است.

تأثیر برای ایران

برنامه‌نویسان ایرانی که از مدل‌های OpenAI یا DeepSeek از طریق API استفاده می‌کنند، می‌توانند با این روش هزینه‌های توکن را از طریق مدل‌های ارزان‌تر (مثل gpt-4o-mini) مدیریت کنند و پایداری اپلیکیشن‌های خود را افزایش دهند.

·نگاه ما
تحریریه دات‌هوش

انتقال اعتبارسنجی از لایه منطق برنامه به لایه قرارداد داده (Data Contract)، پارادایم توسعه با هوش مصنوعی را تغییر می‌دهد. در واقع، ما از مدل به عنوان یک «تولیدکننده متن» فاصله می‌گیریم و آن را به عنوان یک «سرویس‌دهنده داده» می‌بینیم. این رویکرد باعث می‌شود هزینه خطای مدل نه در تجربه کاربر، بلکه در لایه میانی سیستم مدیریت شود.

منابع

این گزارش با خط‌لولهٔ خودکار دات‌هوش از منابع معتبر جهانی تدوین و زیر نظر تحریریه منتشر شده است. روش کار ما

گفتگو

پنج‌شنبه‌های هوش‌محور

بسته‌ی هفتگی دات‌هوش

۵ خبر، ۲ ابزار، ۱ پرامپت در هر شماره. به‌زودی راه‌اندازی می‌شود — هر پنج‌شنبه صبح.

خبر کلیدی
ابزار کاربردی
پرامپت حرفه‌ای
تحلیل پژوهش
به‌زودی
زاویه‌ی ایرانی
به‌زودی
تمرین این هفته
به‌زودی

راهنماهای دات‌هوش

راهنماهای کاربردیِ دات‌هوش برای کار با هوش مصنوعی — از همین‌جا شروع کنید:

دات‌هوش

راهنمای فارسی هوش مصنوعی — با نگاه به ایران

اخبار روزانه، معرفی ابزارها و مدل‌ها، و آموزشِ کار با هوش مصنوعی؛ همیشه با این پرسش که از ایران چه چیزی کار می‌کند و چه چیزی نه.