はじめに
2026/9/15にTypeSafe社から公開されたJevをJavaScript SDKを試してみました。
公式ページのサンプルコードは、Python SDKではnoul/choice/scoreとすべてを試すコードが書かれていましたが、JavaScript SDKは、choiceだけになっていたので、簡単なコード例ですが、3つの種類すべてを呼び出すサンプルを書きました。
参考になれば幸いです。
Jev とは
Introductionより
Jev is TypeSafe’s flagship model and the first System One model. Send state and typed questions; get structured answers your code can use directly.
(要約:TypeSafeのフラグシップモデルで、stateと型付けされた質問に対して構造化された答えを返すモデルです)
Large language models (LLMs) are designed to produce text for humans to read. When you need a model to make a judgment that your code will consume, that creates a mismatch: you are coercing a text-generation system into outputting structured decisions, then parsing the results back into something your code can depend on.
(要約:LLMsは人が読むためのテキスト生成向けに設計されており、判断を行わせたいモデルを使いたいときには合っていない。そのため、テキスト生成のシステムに対して構造化された出力を強制し、その結果をコードによって解析している(のが現状多くみられる))
Jev is TypeSafe’s flagship model and the first System One model. System One models are built to make fast, structured decisions that software can use directly. Jev evaluates typed questions against a state and returns structured results directly. No text generation, no parsing. You get typed values and probability distributions that your code can branch on, sort by, and route with. Choice and Score also return confidence, which your code can use to decide whether and how to act on an answer.
(要約:System Oneモデルは、ソフトウェアが直接利用可能な、迅速かつ構造化された意思決定を行うために設計されています。以下略)
サンプル
TypeScriptで試したほうが楽そうなのでTypeScriptを使いました。ランタイムはNodeではなく、Bunというランタイムを使いました。BunはTypeScriptをデフォルトで動作させることができるので設定回りが楽です。
Windowsだと以下のように進めます。
mkdir jev-test
cd jev-test
bun init
set TYPESAFE_API_KEY=<APIKEYの値>
で、プロジェクトを作成、初期化します。
bun add @typesafe-ai/sdk
で、TypeSafe SDKを追加します。(npm install に当たります)
試した内容は、メールタイトルから、
- noul : スパムかどうか?
- choice : 誰からのメールか
- score : 重要性の評価
を判別しました。Jevの特徴として、1度のAPIでQuestionsとして複数の判断を行うことができます。
また、実行時間も簡単にでるようにしました。
import { choice, noul, score, TypeSafeClient } from "@typesafe-ai/sdk";
async function main() {
const mailTitles = [
"永久不滅ポイント 有効期限間近のお知らせ",
"夫が大アリクイに殺されてから3年が過ぎました",
"久しぶりです。今度の週末空いていますか?",
]
const client = new TypeSafeClient();
for(const mailTitle of mailTitles) {
const startTime = new Date();
console.log("--------------------")
console.log(mailTitle)
console.log("--------------------")
const response = await client.systemOne({
state: {document: mailTitle},
questions: {
// noulには質問を渡す
isSpam: noul("このメールタイトルはスパムメールですか?"),
// choiceには分類したい依頼と状態・説明を渡す
category: choice("このメールをカテゴリ分けしてください", {
spam: "スパムメール",
friend: "友人からのメール",
enemy: "敵対的なメール",
other: "その他",
}),
// scoreはスコアリングの説明と凡例の配列を渡す
importance: score("このメールの重要性を評価してください",[
"スパム",
"低い",
"普通",
"高い",
])
} // questions
});
const endTime = new Date()
console.log(endTime.getSeconds()*1000 + endTime.getMilliseconds() - endTime.getSeconds()*1000 - startTime.getMilliseconds() + "ミリ秒")
console.log("--------------------")
console.log(response.answers)
console.log("--------------------")
}
}
main();
TypeScriptでnoul/choice/scoreと試しましたが、補完が効くため、ドキュメントがなくてもある程度類推できます。
- noul : Yes / No を返します。引数にはYes/Noで答えてほしい質問を指定するだけです
- choice : 選択肢と確率を返します。第一引数に質問、第二引数に、状態と説明を記述します
- score : 配列で渡された状態のスコアと確率を返します。2番目の引数に配列を渡すのが他と違いました
実行結果
bun index.ts
で実行します。(BunだとNodeにts-nodeやtsxなども不要で楽ですね。)
さて、結果はどうなったかというと、以下の通りです。
実行結果サマリ
| メールタイトル | noul(スパムか) | choice(相手) | score(重要度) | 実行時間 |
|---|---|---|---|---|
| 永久不滅ポイント 有効期限間近のお知らせ | 46% | spam:57% other:43% |
高い50% | 215ms |
| 夫が大アリクイにry | 13% | other:94% | 低い~高い30%程度 | 168ms |
| 久しぶりです。今度の週末空いていますか? | 6% | friend:97% | 低い55%, 普通45% | 186ms |
という結果です。スピードは通常のLLMと違いテキストを生成しないためとても速く感じました。
スパムフィルタとしては残念な結果だと思いました。
実行結果すべて
--------------------
永久不滅ポイント 有効期限間近のお知らせ
--------------------
215ミリ秒
--------------------
{
isSpam: {
type: "noul",
noul: 0.46,
},
category: {
type: "choice",
choice: "spam",
confidence: 0.42,
probabilities: {
enemy: 0,
friend: 0,
spam: 0.57,
other: 0.43,
},
},
importance: {
type: "score",
score: 2.14,
confidence: 0.14,
legend: {
"0": "スパム",
"1": "低い",
"2": "普通",
"3": "高い",
},
probabilities: {
"0": 0.1,
"1": 0.17,
"2": 0.23,
"3": 0.5,
},
},
}
--------------------
--------------------
夫が大アリクイに殺されてから3年が過ぎました
--------------------
168ミリ秒
--------------------
{
isSpam: {
type: "noul",
noul: 0.13,
},
category: {
type: "choice",
choice: "other",
confidence: 0.92,
probabilities: {
friend: 0.05,
spam: 0,
other: 0.94,
enemy: 0.01,
},
},
importance: {
type: "score",
score: 1.96,
confidence: 0,
legend: {
"0": "スパム",
"1": "低い",
"2": "普通",
"3": "高い",
},
probabilities: {
"0": 0.03,
"1": 0.36,
"2": 0.24,
"3": 0.37,
},
},
}
--------------------
--------------------
久しぶりです。今度の週末空いていますか?
--------------------
186ミリ秒
--------------------
{
isSpam: {
type: "noul",
noul: 0.06,
},
category: {
type: "choice",
choice: "friend",
confidence: 0.96,
probabilities: {
friend: 0.97,
enemy: 0,
spam: 0,
other: 0.03,
},
},
importance: {
type: "score",
score: 1.45,
confidence: 0.55,
legend: {
"0": "スパム",
"1": "低い",
"2": "普通",
"3": "高い",
},
probabilities: {
"0": 0,
"1": 0.55,
"2": 0.45,
"3": 0,
},
},
}
--------------------
レスポンスのスピードは速く、いつものように、Doomというシューティングゲームがおもちゃにされているのが公式ページにも載っていました。