# Hướng dẫn sử dụng Jev: Kiểm duyệt nội dung với mô hình ra quyết định của TypeSafe trên OpenRouter

- Nguồn: OpenRouter: Announcements
- Thời gian phát hành: 2026-09-23 07:00 (giờ Việt Nam)
- Điểm AI: 57/100
- Link AIHOT.vn: https://aihot.vn/items/cbc6accbffaaf840
- Nguồn dữ liệu AI HOT: https://aihot.news/items/cmuek20s205hkroynl449lqr2
- Link gốc: https://openrouter.ai/blog/tutorials/how-to-use-jev

## Tóm tắt AI

Khám phá cách dùng Jev (typesafe/jev-1.13) qua OpenRouter Decisions API để nhận kết quả có định dạng kiểu dữ liệu và xác suất thay vì văn bản thuần, giúp tối ưu hóa quy trình kiểm duyệt sản phẩm bằng TypeScript.

## Thân bài

![How to Use Jev: Moderation with the Jev API in TypeScript](https://openrouter.ai/blog/images/how-to-use-jev.png)

[Jev](https://openrouter.ai/docs/guides/community/jev) là một mô hình ra quyết định từ TypeSafe. Nó tiếp nhận dữ liệu đầu vào phi cấu trúc và trả về các đánh giá có kiểu dữ liệu (typed judgments) kèm theo xác suất, sau đó mã nguồn của bạn sẽ quyết định bước tiếp theo. Hướng dẫn này chỉ ra cách sử dụng Jev cho vấn đề của riêng bạn, thông qua một ví dụ thực tế về việc kiểm duyệt các bài đăng trên một sàn thương mại điện tử bằng TypeScript.

### Cách thức hoạt động của Jev

Được rồi, bạn đã hiểu Jev dùng để làm gì và cảm thấy mình đang đi đúng hướng. Bây giờ, câu hỏi là: một yêu cầu Jev trông như thế nào ở bên trong?

Hãy bắt đầu từ đầu. Mỗi yêu cầu Jev bao gồm một trạng thái (state) và một tập hợp các câu hỏi. Trạng thái là dữ liệu đầu vào mà Jev cần đánh giá. Nó có thể là một chuỗi, đối tượng JSON hoặc mảng các chuỗi. Nếu bạn đang cố gắng đánh giá một chuỗi các mục, chẳng hạn như các tin nhắn trong một cuộc hội thoại, thì mảng là lựa chọn phù hợp. Các câu hỏi là danh sách những đánh giá mà Jev cần thực hiện trên trạng thái đó. Một câu hỏi bao gồm hai phần: hướng dẫn (instructions) và tiêu chí (criteria). Hướng dẫn mô tả đánh giá cần thực hiện. Tiêu chí mô tả các câu trả lời khả thi. Khi đánh giá trạng thái, Jev sẽ xác định mức độ phù hợp của từng tiêu chí với trạng thái đó và trả về kết quả. Khi trạng thái là một đối tượng JSON, các hướng dẫn có thể tham chiếu đến một trường có tên trong trạng thái bằng cách đặt nó trong dấu backtick. Chúng tôi gọi đây là đường dẫn trường (field path). Ví dụ, một đường dẫn trường hợp lệ có thể là listing.description. Khi hướng dẫn này được cung cấp, Jev sẽ đọc giá trị trong trường đó và thực hiện đánh giá trên nó.

Các loại câu hỏi bao gồm choice (lựa chọn), noul (đúng/sai) và score (điểm số). Câu hỏi choice chọn một tùy chọn từ tập hợp do bạn định nghĩa. Câu hỏi noul quyết định xem một khẳng định có đúng hay không. Câu hỏi score đặt đối tượng vào một thang đo có thứ tự với các mức độ do bạn định nghĩa.

Jev đánh giá từng câu hỏi của bạn một cách riêng biệt và song song trên cùng một trạng thái. Nó sẽ chỉ đưa ra một câu trả lời cho mỗi câu hỏi. Mỗi câu trả lời có một kiểu dữ liệu: choice, noul hoặc score. Một câu trả lời choice bao gồm: 1. Tùy chọn thắng cuộc, 2. Xác suất của từng tùy chọn, 3. Độ tin cậy (confidence) từ 0 đến 1 mà TypeSafe tính toán từ hình dạng của phân phối xác suất. Nếu xác suất tập trung cao vào tùy chọn thắng cuộc, độ tin cậy sẽ cao. Nếu nó bị phân tán, độ tin cậy sẽ thấp hơn, ngay cả khi tùy chọn thắng cuộc có xác suất riêng lẻ cao nhất. Độ tin cậy không phải là xác suất của tùy chọn thắng cuộc, mà là bản tóm tắt của toàn bộ phân phối. Một câu trả lời noul bao gồm: 1. Một xác suất duy nhất cho thấy khẳng định là đúng, 2. Không có độ tin cậy, vì xác suất noul đã thể hiện mức độ tự tin của mô hình. Một câu trả lời score bao gồm: 1. Trung bình có trọng số xác suất của các số mức độ, 2. Xác suất của từng số mức độ, 3. Độ tin cậy, và 4. Chú giải ánh xạ các số mức độ sang mô tả tương ứng.

Mỗi câu trả lời là một tùy chọn hoặc một con số mà mã nguồn của bạn có thể so sánh, đặt ngưỡng và kết hợp. Không có văn bản nào được tạo ra để bạn phải phân tích cú pháp. Đây là lý do nên ưu tiên Jev thay vì một mô hình chat được yêu cầu trả lời YES hoặc NO. Bạn nhận được một phân phối trên các câu trả lời đã định nghĩa, vì vậy sự không chắc chắn là một con số mà bạn có thể dựa vào để điều hướng.

Jev chạy trên OpenRouter Decisions API sử dụng ID mô hình typesafe/jev-1.13. Mọi hoạt động sử dụng API sẽ được tính phí vào tài khoản OpenRouter của bạn. Một yêu cầu gửi đến Jev chỉ bao gồm văn bản, với ngân sách token được tiêu thụ bởi cả trạng thái và các câu hỏi được đặt ra. [Trang mô hình Jev](https://openrouter.ai/typesafe/jev-1.13) hiện hiển thị ngân sách và giá cả. Người dùng mới có thể làm theo [hướng dẫn Jev](https://openrouter.ai/docs/guides/community/jev-tutorial) để nhận câu trả lời đầu tiên trong vài phút.

### Ví dụ thực tế: Sàn thương mại điện tử

Giả sử bạn đang xây dựng một sàn thương mại điện tử nơi người dùng có thể đăng bán các món đồ cũ. Người bán viết tiêu đề và mô tả, chọn danh mục, ghi chú tình trạng món hàng và tải lên hình ảnh. Trước khi bài đăng được xuất bản, bạn muốn đảm bảo không ai đăng bán các mặt hàng bị cấm hoặc yêu cầu thanh toán ngoài nền tảng. Bạn cũng muốn phát hiện các mặt hàng sai danh mục và các mô tả mâu thuẫn với tiêu đề hoặc tình trạng đã khai báo.

Một số kiểm tra này chỉ là mã nguồn thông thường, nhưng những kiểm tra khác đòi hỏi phải thực sự đọc bài đăng và diễn giải ý nghĩa của nó. Đây là mục đích của Jev. Mỗi phần dưới đây mô tả một khía cạnh của việc sử dụng Jev nói chung, sau đó là cách nó hoạt động cho sàn thương mại điện tử. Mô hình tương tự áp dụng cho việc định tuyến yêu cầu hỗ trợ, kiểm soát công cụ đại lý, hoặc bất cứ thứ gì bạn đang xây dựng.

### Cách Jev tích hợp vào chương trình

Jev là một mô hình [System One](https://docs.typesafe.ai/concepts/system-one). Thuật ngữ đó là cách gọi của TypeSafe cho một mô hình tạo ra các quyết định có kiểu dữ liệu và xác suất đã được hiệu chuẩn. [Hướng dẫn xây dựng](https://docs.typesafe.ai/concepts/how-to-build-with-system-one) của TypeSafe mô tả cách xây dựng với một mô hình như vậy. Hãy chèn Jev vào nơi cần đánh giá trong một chuỗi quy trình phần mềm thông thường. Mã nguồn xử lý luồng điều khiển, các quy tắc xác định và các tác dụng phụ. Jev cung cấp các câu trả lời có kiểu dữ liệu, dựa trên trạng thái cho một tập hợp nhỏ các câu hỏi do mã nguồn chuẩn bị. Mã nguồn chuyển đổi các câu trả lời đó thành hành động. Jev không tự quyết định hành động tiếp theo của nó.

Trong sàn thương mại điện tử, nguyên tắc này tạo ra một quy trình giữa lúc người bán nhấn xuất bản và lúc bài đăng hiển thị trực tuyến. Nó tiếp nhận bài đăng và trả về kết quả: xuất bản, giữ lại để con người kiểm duyệt, hoặc từ chối kèm lý do.

1. Các quy tắc cứng được chạy trước bằng mã nguồn, chẳng hạn như số lượng ảnh, giới hạn giá và độ dài văn bản tối thiểu. Các bài đăng không đạt yêu cầu sẽ bị từ chối trước khi bất cứ thứ gì được gửi đến Jev.
2. Việc xây dựng trạng thái kết hợp văn bản của người bán với các dữ kiện do mã nguồn tính toán, và quyết định những gì Jev sẽ thấy.
3. Đánh giá là một yêu cầu hỏi Jev năm câu hỏi có kiểu dữ liệu về trạng thái đó. Jev trả về xác suất và không bao giờ trả về hành động.
4. Xác thực đảm bảo phản hồi khớp với hình dạng mà chính sách mong đợi, và dừng xử lý nếu không khớp.
5. Chính sách so sánh các xác suất đó với các ngưỡng đã được hiệu chuẩn dựa trên các bài đăng mà người kiểm duyệt đã quyết định trước đó.

Giai đoạn 3 là Jev và bốn giai đoạn còn lại là của bạn. Điều này giống nhau cho tất cả các tích hợp Jev. Jev là một hàm chuyển trạng thái thành bằng chứng, và mọi thứ khác là phần mềm thông thường.

### Quyết định những gì Jev quyết định và những gì mã nguồn của bạn quyết định

Câu hỏi thiết kế đầu tiên khi tích hợp Jev là những gì nên được gửi đến nó để đánh giá. Bài kiểm tra là liệu mã nguồn có thể tính toán câu trả lời mà không cần đọc bất kỳ văn bản nào hay không. Nếu có thể (đếm, so sánh ngày tháng, tra cứu), hãy giữ nó trong mã nguồn, nơi kết quả là chính xác và miễn phí. Jev dành cho việc đánh giá đòi hỏi diễn giải ngôn ngữ tự nhiên.

[Trang jaggedness cho Jev 1.13](https://docs.typesafe.ai/model-jaggedness/jev-1.13) của TypeSafe liệt kê các phép tính số học, đếm chính xác và so sánh ngày tháng là những mục nên giữ trong mã nguồn thay vì đưa vào câu hỏi.

Áp dụng vào sàn thương mại điện tử, bài kiểm tra phân loại các kiểm tra như sau.

| Kiểm tra | Vị trí thực hiện | Lý do |
| --- | --- | --- |
| Giá trong giới hạn, ít nhất một ảnh, độ dài tối thiểu | Mã nguồn | Có tính xác định. Một mô hình chỉ có thể kém tin cậy hơn một câu lệnh if. |
| Giá thấp hơn nhiều so với mức giá bán thông thường của danh mục này | Mã nguồn | Tính toán trên dữ liệu bán hàng của riêng bạn. Truyền kết quả cho Jev như một dữ kiện. |
| Mặt hàng thuộc loại bị cấm (vũ khí, hàng giả, ghế trẻ em bị thu hồi) | Jev | Người bán hiếm khi sử dụng từ ngữ bị cấm. "Chất lượng gương, cùng nhà máy" không bao giờ nói là hàng giả. |
| Bài đăng yêu cầu người mua thanh toán hoặc trò chuyện ngoài nền tảng | Jev | Số điện thoại rất dễ dùng regex để nhận diện. Nhưng câu “Tôi cũng có thể giao dịch qua điện thoại” thì không. |
| Mặt hàng phù hợp với danh mục mà người bán đã chọn. | Jev | Đánh giá ngữ nghĩa dựa trên một định nghĩa. |
| Mô tả mâu thuẫn với tiêu đề hoặc tình trạng đã khai báo. | Jev | Đòi hỏi phải so sánh ý nghĩa. |

Các bước kiểm tra cũng xác định loại danh sách mà mỗi giai đoạn chia sẻ. Mọi trường dữ liệu đều thuộc một trong ba loại: đầu vào theo quy tắc cứng (hard-rule), dữ liệu thực tế được tính toán cho Jev, hoặc văn bản mà Jev đọc. Các điều kiện được sắp xếp từ tệ nhất đến tốt nhất, vì vậy chỉ số của điều kiện đã khai báo sẽ tương ứng với các cấp độ của điểm số điều kiện sau này.

```
// listing.ts
export const CATEGORIES = {
  electronics: 'Phones, laptops, cameras, audio gear, game consoles, and their accessories.',
  furniture: 'Tables, chairs, sofas, beds, shelving, and other household furniture.',
  clothing: 'Apparel, shoes, bags, and fashion accessories.',
  sporting_goods: 'Bikes, fitness equipment, camping gear, and equipment for playing sports.',
  toys_and_baby: 'Toys, games, strollers, car seats, cribs, and other children’s items.',
} as const;

export type Category = keyof typeof CATEGORIES;

export const CONDITIONS = ['for_parts', 'fair', 'good', 'like_new', 'new'] as const;
export type Condition = (typeof CONDITIONS)[number];

export type Listing = {
  id: string;
  title: string;
  description: string;
  category: Category;
  condition: Condition;
  priceUsd: number;
  photoCount: number;
};
```

Các định nghĩa danh mục được viết dưới dạng văn xuôi vì Jev đọc chúng từ trạng thái (state) khi đánh giá xem một danh sách có thuộc danh mục đó hay không. Đây là một nguyên tắc chung. Nếu một đánh giá phụ thuộc vào quy tắc của bạn, hãy diễn đạt quy tắc đó trong trạng thái bằng văn xuôi và tham chiếu nó trong câu hỏi của bạn, để mô hình sử dụng định nghĩa của bạn thay vì tự suy diễn.

Các quy tắc cứng (hard rules) là mã nguồn tiêu chuẩn và được chạy trước bất kỳ lệnh gọi nào tới Jev.

```
// rules.ts
import type { Category, Listing } from './listing';

// Typical sale price per category, in USD. In production this comes from your own sales data.
const TYPICAL_PRICE_USD: Record<Category, number> = {
  electronics: 180,
  furniture: 120,
  clothing: 35,
  sporting_goods: 90,
  toys_and_baby: 40,
};

export type PriceSignal = 'far_below_typical' | 'typical' | 'far_above_typical';

export function priceSignal(listing: Listing): PriceSignal {
  const ratio = listing.priceUsd / TYPICAL_PRICE_USD[listing.category];
  if (ratio < 0.2) return 'far_below_typical';
  if (ratio > 10) return 'far_above_typical';
  return 'typical';
}

// Hard rules. Anything here is a fact your code already knows, so no model is involved.
export function hardRuleFailures(listing: Listing): string[] {
  const failures: string[] = [];
  if (listing.photoCount < 1) failures.push('at least one photo is required');
  if (listing.priceUsd < 0.01 || listing.priceUsd > 50_000) failures.push('price must be between $0.01 and $50,000');
  if (listing.title.trim().length < 8) failures.push('title must be at least 8 characters');
  if (listing.description.trim().length < 30) failures.push('description must be at least 30 characters');
  return failures;
}
```

Các giới hạn giá cho thấy sự phân tách trong một bước kiểm tra đơn lẻ. Các giới hạn này được triển khai bằng mã nguồn, nhưng một chiếc túi xách được niêm yết với giá 120 đô la trong một danh mục thường có giá 1.800 đô la sẽ gợi lên lo ngại về hàng giả, và việc diễn giải tín hiệu đó là một sự đánh giá. Mã nguồn thực hiện việc so sánh và gửi nhãn đã hoàn thiện cho Jev.

### Cấu trúc hóa trạng thái mà Jev nhìn thấy.

Trạng thái là một nửa đầu vào của giao diện giữa mã nguồn của bạn và Jev. [Tài liệu về trạng thái](https://docs.typesafe.ai/concepts/state) của TypeSafe mô tả nó như những gì một hội đồng chuyên gia sẽ nhận được trước khi được yêu cầu đưa ra đánh giá. Jev không biết gì về chủ đề này ngoại trừ thông qua trạng thái, và mọi câu hỏi trong yêu cầu đều nhìn thấy cùng một trạng thái đó.

Ba quy tắc xây dựng trạng thái áp dụng cho mọi lĩnh vực. Hãy sử dụng tên gọi mang tính mô tả cho các trường dữ liệu của bạn, vì các câu hỏi tham chiếu đến các trường theo đường dẫn và tên gọi sẽ truyền tải ý nghĩa cho mô hình. Chỉ bao gồm những thông tin mà câu hỏi cần, vì bối cảnh không liên quan sẽ làm mô hình bị xao nhãng.

Truyền các dữ kiện đã tính toán dưới dạng nhãn hoàn thiện. Jev có thể sử dụng trực tiếp `price_signal: 'far_below_typical'`, trong khi các giá trị thô như `price_usd: 120` và `typical_price: 1800` buộc nó phải thực hiện phép tính chia.

Dưới đây là trạng thái cho một danh sách trên sàn thương mại điện tử.

```
{
  "listing": {
    "title": "Louis Vuitton Neverfull MM tote",
    "description": "Mirror quality 1:1, same factory as the boutique version. Nobody can tell the difference. Text me on WhatsApp for more photos and a better price.",
    "category": "clothing",
    "declared_condition": "new",
    "price_usd": 120
  },
  "category_definition": "Apparel, shoes, bags, and fashion accessories.",
  "price_signal": "typical"
}
```

ID người bán, dấu thời gian và URL ảnh bị lược bỏ vì không có câu hỏi nào trong năm câu hỏi sử dụng chúng. `category_definition` được đưa vào vì câu hỏi về độ phù hợp danh mục so sánh danh sách với nó, và `price_signal` được đưa vào vì tiêu chí hàng giả đọc dữ liệu này.

### Chọn loại câu hỏi cho mỗi đánh giá.

Mỗi câu hỏi của Jev đều có một loại, và loại câu hỏi đó phải tuân theo ý nghĩa của câu trả lời. Nó cố định hình thức của câu trả lời, và hình thức đó quyết định những gì bạn có thể làm với nó sau này.

Sử dụng `choice` khi một tùy chọn từ tập hợp bạn xác định cần được chọn và mã nguồn của bạn cần biết đó là tùy chọn nào. Bạn sẽ nhận được kết quả thắng cuộc và xác suất cho mọi tùy chọn, nhờ đó bạn có thể thấy mức độ xác suất rơi vào các tùy chọn còn lại. Sử dụng `noul` khi câu trả lời là một mệnh đề đúng hoặc sai, và bạn sẽ nhận được một xác suất duy nhất để đặt ngưỡng.

Bạn có thể sử dụng `score` để biểu thị một mức độ. Nó nằm trên một thang đo có thứ tự. Kết quả là một con số mà bạn có thể trừ, so sánh với các con số khác và nó cung cấp cho bạn thước đo về sự khác biệt giữa chúng.

Định dạng tiêu chí thay đổi tùy theo loại câu hỏi. Các câu hỏi `choice` nhận một đối tượng ánh xạ mỗi tên tùy chọn với mô tả của nó, với tối đa 255 tùy chọn. Các câu hỏi `noul` nhận một đối tượng tùy chọn với các mô tả đúng và sai. Một câu hỏi lý tưởng cần ngắn gọn và trực tiếp, vì vậy nhiều câu hỏi thậm chí không cần đối tượng mô tả. Các câu hỏi `score` nhận một mảng có thứ tự các mô tả cấp độ (từ 2 đến 10 cấp độ), và câu trả lời được đo lường dựa trên chỉ số bắt đầu từ 0 của mảng đó.

_Bài gốc còn tiếp._ Xem tiếp tại: <https://openrouter.ai/blog/tutorials/how-to-use-jev>
