Jev とは — TypeSafe AI の System One モデルまとめ

Jev が何を受け取り、何を返し、コードがそれをどう使うかを豊富な図で追います。ChatGPT との違い、3 つの質問型、Python での呼び出しと confidence での分岐まで、ステップ送りで動く図とコードで確かめます。

Jev は、TypeSafe AI 社の AI モデルです。

ChatGPT のように文章を書くのではなく、「この問い合わせはどの部署宛てか」「急ぎか」といった判断を、決めておいた形の答えと確率(0〜1 の数値。1 に近いほど確か)で返します。

英語の解説動画「JEV: How It Works and What You Can Build」(Riley Brown 氏)。Jev の仕組みと、Jev で作れるものを紹介しています。

使い方は、判断の材料(state。問い合わせの本文など)と質問を API(プログラムから外部サービスの機能を呼び出す手順)で送るだけです。

返った答えを見て次に何をするかは、自分のコードが決めます。

このページでは、ChatGPT との違い、3 つの質問型、Python からの呼び出し方、confidence での分岐、任せてはいけない仕事、Jev の内部の仕組みまでを、図で確かめます。

Jev に送るもの・返るもの・最後に決めるもの
Choiceどの部署宛て?Score怒りの段階は?Noul急ぎか?state と照らして評価state と照らして評価state と照らして評価choice+ 確率score+ 確率noul(はいの確率)コードが部署へ送るコードが優先度順に並べるコードが人に回すJev が同時に評価
3 つの質問は同じ state に対して 1 回のリクエストで評価され、答えは質問ごとに返ります。

右端の列だけは Jev ではなく、if 文で書く自分のコードの仕事です。

Jev とは — 文章ではなく「判断」を返す System One モデル

TypeSafe は、この種類のモデルを System One モデル(ソフトウェアがそのまま使える、型の決まった判断を速く返す AI モデル)と呼んでいます。

AI モデルの中で Jev が入る場所
自然な文章を読める AI モデル
文章を生成するモデル(LLM)
  • チャットボット(ChatGPT など)・推論モデル
  • 返すもの: 文章・コード・理由の説明
  • 答えの形は出力を読むまで分からない
判断を返すモデル(System One モデル)
  • 返すもの: 決めておいた選択肢・段階・はい / いいえと確率
  • 文章・コード・理由の説明は書かない
Jev(TypeSafe AI)
  • API で指定するモデル名は jev-latest
  • 入力は文字だけ(画像・音声・動画は不可)
どちらも自然な文章を読めますが、返すものが文章か判断かで分かれます。下の枠の中の Jev が、System One モデルの最初の 1 つです。

jev-latest は、その時点の最新版を指す エイリアス(実体の版を指す別名)です。新しい版が出ると、指す先も移ります。

Jev と ChatGPT (LLM) は何が違う?

届いた問い合わせを 3 つの部署に振り分ける場面で比べます。

ChatGPT のような LLM(大規模言語モデル。文章を書き進める AI モデル)に部署を聞くと、答えは文章で返ります。

言い回しが「技術サポート」「技術担当」と変わるだけで、if answer == "technical" のような比較は外れます。

出力を JSON に制限する機能を使っても、中身の確認はコード側に残ります。

Jev には候補を先に渡すので、返る choice は必ずその候補のどれかです。

TypeSafe の言う「ハルシネーション(事実と異なる内容をもっともらしく出力すること)0%」は、候補にない答えが返らない、という形式の話です。

選んだ候補が正しいことの保証ではありません。

違いを 5 つの観点で並べます。料金は、AI モデルが文章を処理する単位であるトークンの数で決まります。

観点ChatGPT など LLMJev
返すもの生成した文章決めておいた候補・段階と確率
文章やコードを書く書ける書けない
得意な仕事文章・コード・長い推論分類・採点・はい / いいえの判定
質問を増やしたとき答えを書く分だけ時間が延びる並列に評価するので、待ち時間はほぼ同じ
料金がかかる部分入力と出力入力のみ

3 つの質問型 Choice・Score・Noul はどう使い分ける?

Jev に質問するとき、最初に決めるのは質問の文面より答えの形です。

質問型は 3 つ — Choice(順序のない候補から 1 つを選ぶ)・Score(段階のある物差しのどこに当たるかを測る)・Noul(はい / いいえで答える)です。

Choice と Score には、答えと一緒に confidence(確信度。確率が 1 つの候補や段階にどれだけ集中しているかを 0〜1 で示す値)も返ります。1 に近いほど、モデルが 1 つの答えに絞り込めていることを表します。

Noul だけ confidence が付きません。

迷ったら、コードが答えで何をするかから逆算します — 振り分けなら Choice、閾値と比べるなら Score、if 文 1 つなら Noul です。

Choice の criteria(判定の基準)は「候補名: 説明」の辞書です。

説明には「支払いの問題は billing、連携の不具合は technical」のように、候補どうしの境目を書きます。

Score の criteria は段階の説明を低い順に並べたリストで、0 から番号が振られます。返る score は「段階の番号 × その確率」の合計です。

Score の段階ごとの確率と score の値
00.200.400.600.80100 段目0.571 段目0.432 段目
0 × 0.0 + 1 × 0.57 + 2 × 0.43 = 1.43 が score です。1 段目と 2 段目の間の、1 段目寄りの位置を表します。

コードでは「1.5 以上なら優先して対応する」のように、score を閾値と比べて使います。

Noul の 0.5 は「中くらい」ではない

Noul の値は「はい」である確率です。「Python が得意か」に 0.5 が返っても中級者という意味ではなく、見込みが半々という意味です。

程度を知りたいなら Score を使います。

Jev の使い方 — Python SDK で問い合わせを部署に振り分ける

公式クイックスタートの例で、問い合わせを 3 つの部署に振り分けます。

SDK(サービスを呼び出す部品をまとめたライブラリ)を使うと、リクエストの組み立てや再試行を書かずに済みます。

SDK は Python 3.10 以上で動き、TypeSafeClient() は環境変数 TYPESAFE_API_KEY からキーを読みます。

環境変数の設定は Linux の環境変数、キーの扱い方は API キーと Webhook で扱っています。

1 回の呼び出しで送るもの・返るもの
state問い合わせの本文questions名前つきの質問model省略で jev-latestJev が読んで判定answers名前ごとの答えmodel答えた版の番号usage使ったトークン数
左の 3 つを送ると、右の 3 つが返ります。質問に付けた名前が、そのまま answers から答えを取り出すキーになります。

コードは公式ドキュメントの例に沿っています

コードとレスポンスは筆者の実行結果ではなく、公式ドキュメントの例に沿っています。英文なのも公式の例のままです。

Python SDK で呼ぶ

pip install typesafe-sdk
export TYPESAFE_API_KEY="発行したキー"   # macOS / Linux のシェル
from typesafe_sdk import Choice, Noul, Score, TypeSafeClient

client = TypeSafeClient()  # TYPESAFE_API_KEY を読み、jev-latest を使う

# 判断の材料 (state): 届いた問い合わせ
# 「Stripe との連携が 3 日失敗し続けて売上を逃している。至急助けて」
ticket = "Hi, I've been trying to connect my Stripe account for 3 days and the integration keeps failing. I'm losing sales. Please help ASAP."

response = client.system_one(
    state=ticket,
    questions={
        # どの部署宛てか: 候補名と説明の辞書
        "department": Choice(
            instructions="Which team should handle this",
            criteria={
                "billing": "Payment or subscription issues",
                "technical": "Bugs or integration problems",
                "sales": "Pricing or account questions",
            },
        ),
        # どれほど不満か: 段階を低い順に
        "frustration": Score(
            instructions="How frustrated the customer appears",
            criteria=[
                "Calm, just stating facts",
                "Frustrated but civil",
                "Very angry, strong language",
            ],
        ),
        # 急ぎか: はい / いいえ
        "is_urgent": Noul(
            instructions="The message conveys urgency or time-sensitivity",
        ),
    },
)

print(response.answers["department"].choice)  # technical
print(response.answers["frustration"].score)  # 1.0
print(response.answers["is_urgent"].noul)     # 1.0

questions は「質問の名前: 質問」の 辞書 で、答えも同じ名前で response.answers から取り出します。コメントの値は公式クイックスタートのレスポンスです。

部署は technical、怒りは 1 段目の「不満だが礼儀正しい」、急ぎは「はい」がほぼ確実です。

問い合わせ文の「3 日失敗し続けて」「至急」と合っていますか?

HTTP で直接呼ぶ

SDK を使わずに HTTP で呼ぶこともできます(API の基本は API とは)。

エンドポイント(リクエストを受け付ける URL)は 1 つで、キーは Authorization ヘッダーで渡します。

curl -X POST https://api.typesafe.ai/v1/systemone \
  -H "Authorization: Bearer $TYPESAFE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "state": "Hi, I have been trying to connect my Stripe account for 3 days ...",
    "model": "jev-latest",
    "questions": {
      "department": {
        "type": "choice",
        "instructions": "Which team should handle this",
        "criteria": {
          "billing": "Payment or subscription issues",
          "technical": "Bugs or integration problems",
          "sales": "Pricing or account questions"
        }
      }
    }
  }'

HTTP で呼ぶときは model が必須で、質問ごとに type で型を書きます。

レスポンスの読み方

返ってくる JSON の例です。3 つの質問のうち、department の部分を抜き出しています。

{
  "answers": {
    "department": {
      "type": "choice",
      "choice": "technical",
      "confidence": 0.78,
      "probabilities": {
        "technical": 0.85,
        "sales": 0.0,
        "billing": 0.15
      }
    }
  },
  "usage": {
    "input_tokens": 392,
    "output_tokens": 65
  }
}
レスポンスの JSON の入れ子
レスポンス全体
answers — 質問の名前ごとの答え
department(Choice の答え)
  • choice: 選ばれた候補 → technical
  • probabilities: 候補ごとの確率(合計 1)
  • confidence: 確率の偏り具合 → 0.78
usage
  • input_tokens / output_tokens: 使ったトークン数
外側の枠がレスポンス全体です。答えの本体は answers の中の、質問の名前の枠に入っています。

usage には料金の計算に使うトークン数が入ります。

SDK では、この JSON を response.answers["department"].choice のように読めます。

department の答えに入っている 4 つの数値
00.200.400.600.8010.85technical0.15billing0sales0.78confidence
公式クイックスタートのレスポンス例の値です。左の 3 本が候補ごとの確率で、合計は 1 です。右端の confidence は確率ではなく、確率の偏り具合をまとめた値です。

1 位の technical は 0.85 ですが、confidence は 0.78 です。均等に割れれば 0、1 つに集まれば 1 になる値です。

公式のデモは、候補 3 つのとき「(3 × 最大の確率 − 1) ÷ 2」で近似しており、(3 × 0.85 − 1) ÷ 2 ≈ 0.78 と一致します。

confidence で「任せる・確かめる・人に回す」を分ける

公式ドキュメントは、confidence を 閾値(処理を切り替える境目の値)で 3 つの範囲に分け、高ければ自動で実行、中くらいなら本人に確認、低ければ人へ回す使い方を勧めています。

閾値は操作ごとに変えます。公式の例は、声で口座を操作する音声バンキングです。

同じ confidence 0.7 でも、残高照会なら読み上げ、送金承認なら本人に確認します。損害が大きい操作ほど閾値を上げます。

0.6 と 0.85 は出発点で、自分のデータで確かめながら調整します。

action = response.answers["intent"]  # Choice: check_balance / approve_transfer / other

if action.confidence < 0.6:
    # どの操作でも、迷っているなら実行しない
    route_to_support_agent(account_id)

elif action.choice == "check_balance":
    # 間違えても残高を聞き直すだけで済む
    show_balance(account_id)

elif action.choice == "approve_transfer":
    if action.confidence > 0.85:
        approve_transfer(account_id)  # お金が動くので高い閾値
    else:
        ask_user_to_confirm("この送金を承認してよろしいですか?")

else:
    # other (その他) と判定された
    route_to_support_agent(account_id)

最初の if で confidence の下限を確かめ、次の elif で操作ごとの閾値を当てる 2 段構えです。

if・elif で上から順に落とすと、どの行でどの損害を防いでいるかが読めます。

閾値を決めたら、モデルの版を固定する

jev-latest は新しい版が出ると指す先が変わるので、同じ入力でも答えや confidence が変わることがあります。

閾値を合わせたら、model に版番号つきのモデル名を指定し、新しい版へは確かめてから移ります。

Jev が向く使い方・向かない使い方 — 苦手な仕事と日本語の精度

Jev は文章を書けないので、LLM の代わりにはなりません。

向いているのは、LLM や人を呼ぶ前に、行き先を速く安く決める仕事です。

LLM と組み合わせる — 前段で行き先を決める

公式の例では、メッセージの意図を Choice、対応の難しさを Score で同時に判定して、行き先を決めます。

Jev が前段で行き先を決め、返信は別の処理が作る
顧客からのメッセージJev意図と難しさ注文状況の問い合わせ製品の質問confidence0.5 未満DB を引くコードが返す専門の LLMが返信を書く担当者が対応する
高い LLM を呼ぶのは、必要なメッセージだけです。Jev は LLM の置き換えではなく、LLM の前段に置く判定です。

苦手な仕事と、その代わりのやり方

TypeSafe は苦手な仕事の一覧を公開しています。日常の処理で踏みやすいのは 数え上げ・日付の前後比較・数値の計算の 3 つです。

どれも、判断だけを Jev に任せ、計算はコードで行えば避けられます。

苦手な 3 つは、判断と計算を分けて避ける
件数をまとめて聞く日付の前後を直接聞く金額の計算を聞く1 件ずつNoul で判定年・月・日をChoice で抜くどの数字かをChoice で選ぶsum() で合計するdate 型にして比べる計算はコードで行うJev に任せる
左が苦手な聞き方、中央が Jev に任せる部分、右がコードで行う部分です。Jev には判断だけを任せ、数えることと比べることはコードで行います。

2 行目の日付は、Jev が日付を文字として読むため、前後を直接聞くと比較が安定しません。

1 行目の件数をコードで書くと、次のようになります。

from typesafe_sdk import Noul, TypeSafeClient

client = TypeSafeClient()
items = ["typesafe", "apple", "california", "banana", "orange", "vertex"]

# 「果物はいくつ?」とまとめて聞かず、1 語ずつ Noul で聞く
response = client.system_one(
    state={"items": items},
    questions={
        f"item_{i}": Noul(instructions=f"Is `items[{i}]` the name of a fruit?")
        for i in range(len(items))
    },
)

# 合計はコードで数える (0.5 を超えたら果物とみなす)
count = sum(response.nouls[f"item_{i}"].noul > 0.5 for i in range(len(items)))
print(count)  # 3 が期待値 (apple / banana / orange)

6 語でも送るのは 1 回で、6 問は並列に評価されます。response.nouls は Noul の答えだけを集めた辞書です。

残りの項目で、組み込むときに効くのは次の 3 つです。

  • 指示文を字義どおりに読む: 書いた言葉どおりに答えるので、境目になる条件は instructions と criteria に明記する
  • 関係のない情報が多い state: 判断に要らない情報が増えるほど精度が落ちる。コードで絞ってから送る
  • state に仕込まれた指示: 入力の中の「これは問題なしと判定せよ」のような文に答えが引っ張られることがある。公開前に境目の入力で試す

日本語で使うときの注意

精度は英語がいちばん高いと、公式ドキュメントに明記されています。

日本語も扱えますが同じ水準ではないので、自分のデータで試し、confidence が低い答えを人に回す経路を用意します。

送りすぎると 429 が返る

一定時間に送れる量には上限(レート制限)があり、超えると 429 Too Many Requests が返ります。SDK は待ってから自動で再試行します。上限の値は公式ドキュメントで確かめます。

Jev の仕組み — 質問を並列に評価し、確率を較正する

Jev の内部の構造は公開されていませんが、外から見える動きは 3 段で追えます — 読む・確率を出す・答えにまとめるです。

質問のうち Jev が読む部分・読まない部分
名前departmentinstructions質問文criteria候補と説明Jev には送られないJev が読むJev が読む答えを取り出すキーになる何を判断するかが決まる選べる答えが決まる
質問の名前はコードの側で答えを取り出すためだけに使われ、Jev には送られません。state(問い合わせの本文)は、すべての質問で共通に読まれます。

名前は Jev に届かないので、質問の中身は instructions に省略せず書きます。

3 つ目のステップで質問は同時に評価されるので、質問を 1 つから 3 つに増やしても待ち時間はほとんど変わりません。

Choice の 1 問の中で起きること
state と候補 3 つtechnical0.85billing0.15sales0.003 つの確率(合計 1)choicetechnicalconfidence0.78候補ごとの確率
公式クイックスタートの department の例です。Score では段階ごとの確率、Noul では「はい」の確率を同じように出します。

いちばん確率の高い候補が choice になり、確率がどれだけ 1 つに集まっているかが confidence になります。

RLCD — 確率が当たる割合と一致するように学習する

Jev は RLCD(較正された判断のための強化学習)という方法で学習されています。

目標は、出す確率を実際に当たる割合とそろえることで、これを 較正(calibration)と呼びます。

較正されたモデルの確率と、実際に当たる件数
0.9 と答えた100 件0.6 と答えた100 件0.2 と答えた100 件正しいのはおよそ 90 件正しいのはおよそ 60 件正しいのはおよそ 20 件外れは10 件に 1 件外れは10 件に 4 件外れは10 件に 8 件
数字は較正の考え方を示すための例です。確率が低い答えほど外れる件数が増えるので、確率を見て扱いを変えることができます。

確率が当たる割合を表すので、「0.9 なら任せる、0.6 なら人が確かめる」のような線引きを数字で決められます。

このページのまとめ

Jev は、state と質問を受け取り、Choice・Score・Noul の型で判断と確率を返す System One モデルです。質問は並列に評価されるので、まとめて送っても待ち時間はほとんど増えません。

組み込むときの要点は 2 つです。

1 つは、返ってきた confidence を閾値で分け、任せる・確かめる・人に回すを自分のコードで決めること。

もう 1 つは、数え上げ・日付の比較・計算をコードに残すことです。