تصور کنید برنامهنویسی هستید که با کابوس نوشتن یک عبارت منظم (Regex) برای تشخیص این موضوع دستوپنجه نرم میکند که آیا مشتری واقعاً میخواهد با یک اپراتور انسانی صحبت کند یا خیر. شما با چند کلمه کلیدی ساده شروع میکنید، اما هر مورد استثنای جدید (edge case)، نیازمند یک استثنای جدید در کد است و به سرعت، کد شما به تودهای غیرقابلمدیریت از خطوط، علامتهای پایپ (|) و بکاسلشها تبدیل میشود.
به عنوان مثال، یک Regex مانند /(human|person|agent|representative)/i.test(text) && !/(human resources|secret agent|humans are)/i.test(text) && !/(don't need|no thanks|not necessary)/i.test(text) ممکن است درخواست کمک را به درستی شناسایی کند، اما جملهای مثل «انسانها شگفتانگیزند» یا «مامور مخفی» (secret agent) را هم به اشتباه به عنوان درخواست اپراتور شناسایی میکند؛ در حالی که جملهای مثل «سه بار پرسیدم و کسی کمک نکرد، یکی را بیاورید که بتواند مشکل را حل کند» را کاملاً نادیده میگیرد. askif این مشکل را با تبدیل هوش مصنوعی به یک گیت منطقی برای شرایط مبهم (fuzzy conditions) حل میکند.
بسیاری از توسعهدهندگان از فراخوانی یک مدل زبانی بزرگ (LLM) — مثل کتابخانهداری که میلیاردها صفحه را خوانده و حالا با همان لحن کتابها جواب میدهد — برای یک تصمیم ساده «بله یا خیر» (boolean branch) دوری میکنند؛ چون هزینه و تأخیر (latency) آن بسیار زیاد و بازدارنده است. تولید متن سنتی کند و گران است و اغلب ثانیهها طول میکشد تا یک پاسخ ساده «بله» یا «خیر» را که در میان جملات طولانی و تعارفی پیچیده شده است، برگرداند. این موضوع باعث شده برنامهنویسان مجبور شوند برای کارهایی که نیاز به ذرهای درک معنایی دارند، از قوانین دستنویس، شکننده و سختگیرانه استفاده کنند.
askif این شکاف را با استفاده از Jev پر میکند؛ مدلی از شرکت TypeSafe AI که به مدلهای «سیستم یک» (System One) تعلق دارد. این رویکرد در واقع پیادهسازی عملی از روش تبدیل متن به عدد برای طبقهبندی دقیق دادههاست که اجازه میدهد مدلها به جای تولید متن، مستقیماً احتمالات را برگردانند. طبق مستندات این شرکت، Jev برخلاف مدلهای زبانی استاندارد، متن تولید نمیکند، بلکه مستقیماً احتمالات را برمیگرداند. این تغییر معماری باعث شده است که این کتابخانه منطق شرطی را با میانگین زمان استنتاج (Inference) — لحظهای که مدل واقعاً جواب تولید میکند، شبیه به خودِ آشپزی و نه دورهی آموزش آشپز — ۷۲ میلیثانیه و هزینه تقریبی ۰.۰۱۳ دلار به ازای هر ۱۰۰۰ فراخوانی اجرا کند. این بهینهسازی چشمگیر است، چرا که مدل Jev توانسته است هزینههای استنتاج را تا ۴۴۴ برابر کاهش دهد و موانع مالی استفاده از LLMها در مقیاس بالا را از بین ببرد. این هزینه بر اساس حدود ۳۰۰ توکن ورودی به ازای هر فراخوانی با نرخ ۰.۰۴۲ دلار به ازای هر میلیون توکن ورودی محاسبه شده است، در حالی که توکنهای خروجی رایگان هستند.
زمینه و تأخیر (Context and Latency)
اندازهگیریهای تأخیر از ژاپن در محیط Playground رسمی TypeSafe، یک زمان کل رفتوبرگشت (round trip) حدود ۲۵۰ میلیثانیه را نشان میدهد. این زمان به این صورت تفکیک میشود: ۷۲ میلیثانیه برای استنتاج مدل و ۱۷۵ میلیثانیه برای تردد در شبکه. دلیل اصلی این تأخیر شبکه این است که Jev در حال حاضر هیچ منطقه (region) اختصاصی در ژاپن یا آسیا ندارد.
از آنجا که Jev مرحله تولید متن را حذف میکند، شما به جای متنی که نیاز به تجزیه (Parsing) داشته باشد، اعدادی مثل ۰.۹۳ دریافت میکنید. این ویژگی، askif را به جایگزینی سریع و مستقیم برای منطقهای شرطی پیچیده در برنامههای سمت سرور تبدیل میکند.
الزامات فنی
برای شروع، توسعهدهندگان باید کتابخانه اصلی و آداپتور Jev را از طریق دستور npm install askif @askif/jev نصب کنند. این سیستم به Node 22 یا نسخههای جدیدتر نیاز دارد.
در حال حاضر، SDK شرکت TypeSafe فقط در سمت سرور (server-side) اجرا میشود. این ابزار از اجرا در محیط مرورگر خودداری میکند زیرا این کار باعث میشود کلید TYPESAFE_API_KEY در معرض دید کلاینت قرار بگیرد. برای فعالسازی استفاده در مرورگر، یک بکاِند پروکسی-سرور در نسخههای آینده برنامهریزی شده است.
سه فعل اصلی (The Three Core Verbs)
این کتابخانه سه متد اصلی برای مدیریت انواع مختلف منطق مبهم ارائه میدهد:
- ask.if: برای تصمیمات دوگانه (binary) یا سهگانه (ternary) است. این متد اجازه میدهد یک شاخه
.then()برای تطبیقهای مثبت، یک.else()برای موارد منفی و یک شاخه منحصربهفرد.unsure()برای احتمالات قرار گرفته در یک بازه خاص (به طور پیشفرض ۰.۲ تا ۰.۸) تعریف کنید. در صورت عدم استفاده از.unsure()، هندلر then زمانی اجرا میشود که احتمال بالاتر از آستانه پیشفرض ۰.۵ باشد. برای دسترسی به دادههای خام،ask.isیک مقدار boolean وask.probabilityیک عدد بین ۰ تا ۱ برمیگرداند. - ask.switch: برای مدیریت گزینههای «یکی از چند مورد» (one-of-many) است. توسعهدهندگان میتوانند بلوکهای
.case()متعددی را با کلید و توضیحات تعریف کنند (مثلاً کلید «returns» برای توضیحات «تبدیل، کالاهای اشتباه یا آسیبدیده»). هم کلید گزینه و هم توضیحات آن به مدل ارسال میشوند. اگر کلید به اندازه کافی گویا باشد، میتوان از نوشتن توضیحات صرفنظر کرد. کتابخانه محتملترین انتخاب را به عنوان یک نتیجه تایپشده (team.choice) برمیگرداند و یک رتبهبندی کامل (team.ranking) از تمام گزینهها (به ترتیب احتمال) ارائه میدهد. - ask.score: یک وضعیت را روی یک مقیاس (scale) قرار میدهد. این متد برای تعیین سطوح شدت ایدهآل است؛ مثلاً: «ظاهری؛ بدون تأثیر بر عملکرد»، «ویژگی خراب یا کاهش یافته، اما راه حل جایگزین وجود دارد» یا «مشکل مسدودکننده؛ هیچ راه حل جایگزینی وجود ندارد». در اینجا نتیجه شامل یک موقعیت وزندار بر اساس احتمال (
score) و یک مقدار نرمالشده (normalized) بین ۰ و ۱ برای رتبهبندی است. هندلری که اجرا میشود مربوط به محتملترین سطح است، نه یک امتیاز گرد شده.
عملکرد و دستهبندی (Performance and Batching)
یکی از حیاتیترین ویژگیها برای محیط عملیاتی، دستهبندی (Batching) درخواستها است. وقتی چندین سؤال درباره یک وضعیت (state) در یک تیک (tick) فراخوانی شوند، askif آنها را در یک درخواست واحد بستهبندی میکند.
در تستهای اندازهگیری شده، ارسال سه سؤال مجزا (مانند بررسی اینکه آیا سفارش مشکوک به کلاهبرداری است، ارسال بینالمللی دارد و فوریت تحویل آن چقدر است) در قالب یک درخواست، میانگین ۱۶۶ میلیثانیه زمان برد. ارسال متوالی آنها زمان را به ۵۱۹ میلیثانیه افزایش داد. در حالی که ارسال آنها به صورت سه درخواست موازی، ۱۷۷ میلیثانیه زمان برد. این اعداد از خارج از ژاپن اندازهگیری شدهاند. این کارایی باعث میشود اجرای چندین بررسی مبهم به صورت همزمان، بدون جریمههای تأخیر خطی، امکانپذیر شود، زیرا افزودن سؤالات اضافی تقریباً زمانی به درخواست اضافه نمیکند.
انعطافپذیری بکاِند و میزبانی محلی
اگرچه این ابزار برای Jev بهینه شده، اما مستقل از ارائهدهنده (provider-neutral) است. این کتابخانه منطق زنجیرهای را از طریق یک قرارداد (contract) از بکاِند جدا میکند و به توسعهدهندگان اجازه میدهد بدون تغییر در منطق تجاری خود، ارائهدهنده را عوض کنند.
کاربران میتوانند با استفاده از @askif/openai از مدلهای زبانی عمومی از طریق Chat Completions استفاده کنند. این آداپتور از موارد زیر پشتیبانی میکند:
- OpenRouter: از طریق یک
baseURLسفارشی و مدل (مثلاًopenai/gpt-6-luna). - Ollama: برای استفاده محلی از طریق
http://localhost:11434/v1(همچنین سازگار با vLLM, LM Studio و llama.cpp). - Azure OpenAI: با استفاده از کلاس کلاینت
AzureOpenAIباdeploymentوapiVersionخاص (مثلاً2025-04-01-preview). - Amazon Bedrock: از طریق کلاس
BedrockOpenAI. - Google Gemini/Vertex AI: از طریق
baseURLسازگار با OpenAI.
با این حال، نویسنده پروژه به یک نقطه ضعف اشاره میکند: مدلهای زبانی عمومی، مدلهای «سیستم یک» نیستند. آنها به جای احتمالات خام (logprobs)، به تخمینهای JSON از طریق خروجیهای ساختاریافته (Structured Outputs) متکی هستند و مقدار confidence توسط askif بر اساس پراکندگی احتمالات محاسبه میشود، زیرا مدلها در گزارش میزان اطمینان خود ضعیف هستند. علاوه بر این، آنها نمیتوانند سؤالات مربوط به یک وضعیت را در یک درخواست دستهبندی کنند و سرورهای محلی باید از response_format: json_schema پشتیبانی کنند تا از خطاهای BAD_RESPONSE جلوگیری شود. جدول سرورها در README منعکسکننده مستندات پروژه است و لزوماً همه آنها به صورت زنده تست نشدهاند.
برای کسانی که الزامات سختگیرانه در مورد مکان ذخیره دادهها یا محدودیتهای امنیتی دارند، OpenJev یک سرور متنباز و سازگار با Jev را فراهم میکند. این امر اجازه میدهد کل پشته (stack) روی GPUهای محلی، تراشههای اپل یا نسخه میزبانی شده در Codiv اجرا شود. هنگام استفاده از OpenJev با @askif/jev، کاربران باید از IDهای مدل OpenJev (مانند openjev-latest) استفاده کنند، زیرا IDهای پینشده Jev (مانند jev-1.13.0) خطای ۴۰۰ برمیگردانند.
بهترین روشهای پیادهسازی (Implementation Best Practices)
برای بهرهوری حداکثری از شاخهبندیهای مبهم، کتابخانه استراتژیهای خاصی را بر اساس مستندات TypeSafe پیشنهاد میکند:
- قضاوتهای تکموضوعی: در هر سؤال فقط یک قضاوت انجام دهید. از سؤالات ترکیبی مانند «آیا کاربر عصبانی است و 환불 میخواهد؟» دوری کنید. در عوض، دو فراخوانی مجزا انجام داده و آنها را در کد خود ترکیب کنید.
- عبارات مثبت: سؤالات را طوری طرح کنید که پاسخ «بله» پاسخ جالب و مورد نظر باشد (مثلاً «شامل دادههای شخصی است» به جای «فاقد دادههای شخصی است»).
- توصیف وضعیت به جای درجه: یک وضعیت را توصیف کنید (مثلاً «خراب است اما راه حل جایگزین وجود دارد») به جای استفاده از صفتهای مبهم مانند «به شدت شدید» یا «متوسط».
این رویکرد، نقش برنامهنویس را از نوشتن Regexهای پیچیده به تنظیم آستانههای احتمالی (Thresholds) در کد تغییر میدهد. این آستانهها را میتوان به صورت کلی از طریق ask.configure({ threshold: 0.6 }) یا به صورت موردی برای هر فراخوانی تنظیم کرد. توصیه میشود این مقادیر را با دادههای خودتان تست کنید، زیرا آستانههای تنظیم شده برای یک بکاِند ممکن است به بکاِند دیگر منتقل نشوند.
تست و توسعه
تستها میتوانند به صورت آفلاین با استفاده از بکاِند mock اجرا شوند. این قابلیت به توسعهدهندگان اجازه میدهد پاسخها را به صورت محلی شبیهسازی کنند و هر فراخوانی انجام شده به بکاِند را برای تأیید ثبت کنند. به عنوان مثال، یک mock را میتوان طوری تنظیم کرد که یک نوع yesno با احتمالی خاص برگرداند و سپس backend.calls را بررسی کرد تا دقیقاً دیده شود چه سؤالی پرسیده شده است.
برای یک توسعهدهنده حرفهای، این یک چرخش در نحوه اعتبارسنجی ورودیها و تریاژ (triaging) است. ما از دنیای باینری true/false به دنیایی از بازههای اطمینان میرویم که در آن «نامطمئن بودن» (unsure) یک شهروند درجه یک در جریان کنترل برنامه است.
توسعهدهندگان میتوانند با نصب askif و @askif/jev از طریق npm شروع کنند. منتظر انتشار قریبالوقوع بکاِند پروکسی-سرور برای پشتیبانی از مرورگر، فرمی برای تعریف چندین سؤال در ابتدا، AbortSignal برای هر فراخوانی همراه با گزارش مصرف، و آداپتورهای اضافی برای Anthropic و پیکربندیهای مبتنی بر MLX باشید. مثالهای آفلاین در دایرکتوری packages/askif/examples/ در مخزن پروژه موجود است.
گام بعدی شما
- اگر در پروژههایتان با Regexهای طولانی و غیرقابلفهم دستوپنجه نرم میکنید، کتابخانه askif را در یک ماژول کوچک تست کنید.
- برای کاهش هزینهها و تأخیر، از مدلهای سیستم یک مانند Jev به جای مدلهای زبانی عمومی استفاده کنید.
- استراتژی «قضاوتهای تکموضوعی» را در پرامپتهای خود پیاده کنید تا دقت دستهبندی افزایش یابد.
اما داستان سختافزاری این تحول حتی شگفتانگیزتر است — به تحلیل ما دربارهی تراشههای Blackwell مراجعه کنید.




گفتگو