بیشتر کاربردهای هوش مصنوعی در بکاند در واقع تولید متن نیستند؛ تصمیمگیریاند. این تیکت به کدام تیم برود؟ این پیام فوری است؟ این کاربر درخواست بازگشت وجه کرده؟ تا امروز معمولاً برای این سؤالها یک LLM صدا زده میشد و از آن خواسته میشد جواب را در قالب JSON برگرداند؛ کند، پرهزینه و گاهی با جوابی خارج از گزینههای مجاز. Jev، مدل تازه شرکت TypeSafe AI، دقیقاً برای همین نوع کار ساخته شده: متن تولید نمیکند، بین گزینههایی که شما تعریف کردهاید تصمیم میگیرد و برای هر گزینه احتمال برمیگرداند.
در این مقاله توضیح میدهم Jev چیست، API آن چطور کار میکند، کجا به درد یک پروژه Laravel میخورد و کجا نه. یک نمونه کد کامل Laravel هم آوردهام که با تست خودکار بررسی شده است.
شفافیت درباره منبعها: همه اطلاعات فنی این مقاله از مستندات رسمی TypeSafe در docs.typesafe.ai است که در ۲۰ مهر ۱۴۰۵ بررسی کردم. کلید API ندارم و کد را روی API زنده اجرا نکردهام. کد Laravel با پاسخهای نمونه همان مستندات تست شده است. عددهای سرعت و هزینه، ادعای خود سازندهاند.
Jev چیست؟
TypeSafe مدلهای خود را «System One» مینامد؛ مدلهایی برای تصمیمهای سریع و ساختاریافته داخل نرمافزار، در برابر مدلهای زبانی که پاسخ را کلمهبهکلمه تولید میکنند. Jev اولین و فعلاً تنها مدل این خانواده است. نسخه فعلی در زمان نوشتن این مقاله jev-1.13.0 است.
تفاوت اصلی با یک LLM در خروجی است. شما یک «state» (وضعیت: متن، شیء JSON یا آرایه) و چند «سؤال تایپشده» میفرستید. Jev برای هر سؤال یک جواب ساختاریافته برمیگرداند که همیشه یکی از گزینههای خود شماست. چون متنی تولید نمیشود، جوابی خارج از گزینهها، JSON خراب یا متن اضافه وجود ندارد.
سه نوع سؤال
| نوع | کاربرد | خروجی |
|---|---|---|
choice | انتخاب یک گزینه از فهرست شما، مثل مسیریابی تیکت یا دستهبندی | گزینه انتخابشده، احتمال هر گزینه و confidence |
score | امتیاز روی یک مقیاس مرتب، مثل شدت مشکل یا سطح ریسک | امتیاز وزندار، احتمال هر سطح، legend و confidence |
noul | سؤال بله/خیر، مثل «آیا درخواست بازگشت وجه است؟» | یک عدد بین ۰ و ۱: احتمال «بله» |
هر درخواست میتواند چند سؤال از هر سه نوع داشته باشد و همه روی همان state و بهصورت موازی ارزیابی میشوند. سؤال choice حداکثر ۲۵۵ گزینه میپذیرد.
ساختار API
همه مدلها از یک endpoint سرویس میگیرند:
POST https://api.typesafe.ai/v1/systemone
Authorization: Bearer <API_KEY>
Content-Type: application/json
{
"model": "jev-latest",
"state": "Help! My payouts have been failing for 3 days.",
"questions": {
"is_urgent": { "type": "noul", "instructions": "Does this convey urgency?" }
}
}
پاسخ شامل نام نسخهای از مدل است که جواب داده (مثلاً jev-1.13.0)، یک شیء answers با همان کلیدهای سؤالهای شما، و تعداد توکنهای مصرفشده. alias jev-latest با انتشار نسخه جدید جابهجا میشود. اگر آستانههایتان را روی یک نسخه تنظیم کردهاید، مستندات توصیه میکند نسخه مشخص را pin کنید و نسخه پاسخدهنده را لاگ کنید.
confidence؛ مهمترین بخش برای بکاند
جوابهای choice و score یک فیلد confidence بین ۰ و ۱ دارند که از شکل توزیع احتمال محاسبه میشود. اگر همه احتمال روی یک گزینه باشد، ۱ است. اگر بین گزینهها پخش شده باشد، به صفر نزدیک میشود. برای noul فیلد جداگانهای وجود ندارد؛ عدد نزدیک ۰٫۵ یعنی مدل مطمئن نیست.
این همان چیزی است که تصمیم مدل را برای کد بکاند قابل استفاده میکند. مستندات TypeSafe الگویی سهسطحی پیشنهاد میکند: confidence بالا یعنی اقدام خودکار، متوسط یعنی تأیید یا بررسی، پایین یعنی واگذاری به انسان یا سیستم دیگر. آستانهها هم باید با ریسک تصمیم تغییر کنند: نمایش صفحه اشتباه قابل جبران است، تأیید یک برداشت مالی نه.
نمونه Laravel: مسیریابی تیکت پشتیبانی
کلاس زیر سه سؤال را در یک درخواست میپرسد: کدام تیم، چقدر جدی، و آیا درخواست بازگشت وجه است. نکته کلیدی این است که مدل فقط تصمیم میگیرد و همه آستانهها و اثرهای جانبی در کد شما میمانند:
<?php
namespace App\Support\Jev;
use Illuminate\Http\Client\Factory as Http;
/**
* Asks Jev three typed questions about a support ticket and turns the answers into
* an action. The model decides; this class owns every threshold and side effect.
*/
final class TicketTriage
{
public function __construct(private Http $http, private string $apiKey, private string $model = 'jev-latest') {}
public function triage(array $ticket): array
{
$response = $this->http
->withToken($this->apiKey)
->acceptJson()
->timeout(5)
->retry(2, 200, fn ($e) => $e instanceof \Illuminate\Http\Client\ConnectionException)
->post('https://api.typesafe.ai/v1/systemone', [
'model' => $this->model,
'state' => [
'subject' => $ticket['subject'],
'message' => $ticket['message'],
'customer_plan' => $ticket['plan'],
],
'questions' => [
'department' => [
'type' => 'choice',
'instructions' => 'Which team should handle this ticket?',
'criteria' => [
'billing' => 'Payments, invoices, refunds, duplicate charges',
'technical' => 'Bugs, errors, outages, failing integrations',
'sales' => 'Pricing, upgrades, new accounts',
],
],
'severity' => [
'type' => 'score',
'instructions' => 'How severe is the impact on the customer?',
'criteria' => [
'Question or minor inconvenience',
'A feature is broken but there is a workaround',
'The customer cannot operate or is losing money',
],
],
'refund_requested' => [
'type' => 'noul',
'instructions' => 'The customer explicitly asks for money back.',
],
],
])
->throw()
->json();
$department = $response['answers']['department'];
$severity = $response['answers']['severity'];
$refund = $response['answers']['refund_requested']['noul'];
// Thresholds live in code and scale with the cost of a wrong decision.
$queue = $department['confidence'] < 0.5 ? 'human-review' : $department['choice'];
$page = $severity['score'] >= 1.5 && $severity['confidence'] >= 0.6;
return [
'queue' => $queue,
'page_on_call' => $page,
'flag_refund' => $refund >= 0.8,
'model' => $response['model'], // log the versioned model that answered
];
}
}
چند نکته طراحی:
- timeout کوتاه و retry محدود. این تصمیم در مسیر ثبت تیکت است. اگر سرویس بیرونی کند یا در دسترس نبود، تیکت باید به صف پیشفرض برود، نه اینکه کاربر منتظر بماند. در production این فراخوانی را در یک job صف اجرا کنید. الگوهای کلی را در مقاله Resilient Third-Party API Integrations in Laravel نوشتهام.
- severity بالا اما نامطمئن، کسی را بیدار نمیکند. آستانه برای اقدام پرهزینه (page کردن تیم آنکال) هم به امتیاز و هم به confidence وابسته است.
- نسخه مدل لاگ میشود. وقتی alias جابهجا شود، بدون این لاگ نمیفهمید چرا رفتار سیستم تغییر کرد.
و یکی از چهار تستی که با پاسخ نمونه مستندات اجرا کردم؛ وقتی confidence پایین است، سیستم حدس نمیزند:
public function test_low_confidence_goes_to_a_human_instead_of_guessing(): void
{
$http = new Factory();
$http->fake(['*' => $http->response($this->answers(0.31, 'technical', 2.0, 0.4, 0.55))]);
$result = $this->triage($http);
$this->assertSame('human-review', $result['queue']);
$this->assertFalse($result['page_on_call']); // severe-looking but uncertain: no page
$this->assertFalse($result['flag_refund']); // 0.55 is not a clear yes
}
هر چهار تست (ساختار درخواست، مسیریابی خودکار با confidence بالا، ارجاع به انسان با confidence پایین، و خطای 429) روی Laravel 8.83 و PHP 8.2 با Http::fake پاس شدند.
قیمت، محدودیتها و زبان فارسی
طبق صفحه Models مستندات، در زمان نوشتن:
- قیمت
jev-1.13.0: ۰٫۰۴۲ دلار برای هر یک میلیون توکن ورودی. توکن خروجی رایگان است. - محدودیت نرخ: ۱۰۰ هزار توکن و ۸۰ درخواست در ثانیه. خود TypeSafe نوشته این عددها به دلیل تقاضای زیاد ممکن است بدون اطلاع قبلی تغییر کنند.
- context: حداکثر ۶۴ هزار توکن برای کل درخواست و ۳۲ هزار توکن برای state بههمراه طولانیترین سؤال.
- ورودی فقط متنی است؛ تصویر، صدا و ویدیو پشتیبانی نمیشود.
- داده درخواستها برای آموزش مدل استفاده نمیشود.
نکته مهم برای پروژههای ایرانی: مستندات صریحاً میگوید زبان اصلی آموزش انگلیسی است و زبانهای دیگر پشتیبانی میشوند، اما با دقت کمتر. اگر state شما متن فارسی کاربران است، قبل از هر تصمیم خودکار، با داده واقعی خودتان تست کنید و به confidence حساستر باشید. یک راه عملی این است که instructions و گزینهها را انگلیسی و دقیق بنویسید و فقط محتوای کاربر فارسی بماند.
کجا Jev انتخاب خوبی نیست
TypeSafe صفحهای به نام «jaggedness» منتشر کرده که ضعفهای شناختهشده jev-1.13 را فهرست میکند (آخرین بازبینی: ۲ اکتبر ۲۰۲۶). خلاصهاش برای توسعهدهنده بکاند:
- محاسبه و شمارش: Jev ماشینحساب نیست و شمارش را قابل اعتماد انجام نمیدهد. حساب را در کد انجام دهید.
- مقایسه تاریخ: تاریخ را متن میخواند. اجزای تاریخ را با مدل استخراج و مقایسه را در کد انجام دهید.
- برداشت تحتاللفظی: به همان چیزی که نوشتهاید جواب میدهد، نه منظور شما. شرط را دقیق و موارد مرزی را در criteria بنویسید.
- ترتیب گزینهها: ترتیب گزینههای choice میتواند روی جواب اثر بگذارد. با جابهجا کردن گزینهها پایداری جواب را بسنجید.
- state بزرگ پر از جزئیات بیربط: قبل از ارسال فیلتر کنید.
- تولید متن: برای خلاصهنویسی، پاسخ به مشتری یا هر خروجی آزاد، از یک مدل زبانی استفاده کنید.
Jev در کنار LLM، نه بهجای آن
الگویی که به نظرم برای بیشتر محصولها منطقی است: Jev بهعنوان لایه سریع و ارزان تصمیم، و LLM فقط جایی که تولید یا استدلال چندمرحلهای لازم است. مثلاً Jev تشخیص میدهد تیکت درباره بازگشت وجه است و confidence بالایی دارد. کد قوانین بازگشت وجه را اجرا میکند. فقط برای نوشتن پاسخ به مشتری یک LLM صدا زده میشود. خود مستندات TypeSafe هم الگوهایی مثل «intent routing» را دقیقاً با همین تقسیم کار توضیح داده است.
برای سنجش هر مدلی پیش از اعتماد به آن، همان اصولی که در آزمایش index ترکیبی MySQL روی یک میلیون ردیف به کار بردم اینجا هم صدق میکند: داده واقعی با توزیع واقعی، اجرای تکراری، و مقایسه با یک baseline. برای Jev یعنی چند صد تیکت واقعی که جواب درستشان را میدانید، و اندازهگیری اینکه در هر بازه confidence چند درصد جوابها درست بوده است.
جمعبندی
Jev نوع تازهای از مدل است که بهجای تولید متن، بین گزینههای شما تصمیم میگیرد و میزان اطمینانش را هم اعلام میکند. برای مسیریابی، دستهبندی، امتیازدهی ریسک و فیلترهای بله/خیر داخل بکاند، شکل خروجیاش با کد سازگارتر از یک LLM است. محدودیتهایش در حساب، تاریخ و زبانهای غیرانگلیسی را جدی بگیرید و آستانهها را با داده خودتان تنظیم کنید.
اگر میخواهید تصمیمگیری خودکار با هوش مصنوعی را به شکل امن و قابل اندازهگیری در بکاند Laravel خود اضافه کنید، در خدمت طراحی API و معماری بکاند با هم طراحیاش میکنیم.
پرسشهای متداول
Jev با ChatGPT یا Claude چه فرقی دارد؟
آنها متن تولید میکنند؛ Jev فقط یکی از گزینههایی را که خودتان تعریف کردهاید انتخاب میکند و برای هر گزینه احتمال و میزان اطمینان برمیگرداند.
آیا Jev متن فارسی را میفهمد؟
طبق مستندات، زبان اصلی آموزش انگلیسی است و زبانهای دیگر با دقت کمتر پشتیبانی میشوند. برای متن فارسی حتماً با داده خودتان تست کنید.