メインコンテンツまでスキップ

Jev

:::warning 返るのは確率であって、判断ではありません

Jev が返すのは確からしさと類似度です。0.92 は「強くそちらに寄っている」であって「決まった」ではありません。choice が返す名前は「いちばん確率が高かった選択肢」であって、決定ではありません。ここでは何も決まりません。**しきい値を決めて決定にするのは、呼び出すあなたの仕事です。**その両側で何をするかも呼ぶ側が決めます。

このエンドポイントが /v1/decisions ではなく /v1/jev という名前なのはこのためです。判断(decision)は人が下す、重く離散的で確定的なものです。名前が実物より重いと、返ってきた 0.92 を「決まった」と読む人が出ます。(2026-09-23・CEO 判断)

**POST /v1/decisions は 2026-09-23 に削除され、現在 404 を返します。**別名は残していません。

:::

**このエンドポイントは TypeSafe の Jev です。**同じモデル・同じ答えで、応答には毎回 "model": "jev-1.13.0" が入ります。TypeSafe のアカウントも Cloudflare のアカウントも waitlist も不要。いま持っている aicu_live_ の鍵だけで動きます。Cloudflare の公式サンプルは、URL と鍵を変えるだけでここで動きます。

質問を投げると、そのまま分岐に使える型付きの値が返ります。選択肢のどれか、0〜N の段階、0〜1 の確からしさ。それぞれ裏付けの確率つきです。文章から JSON を取り出す処理も、コードフェンスに包まれたときのリトライも要りません。

これが置き換えるもの​

言語モデルから判断を取り出す一般的なやり方は、「JSON で返して」と頼んで祈ることです。それが実際どのくらい持つのかを測りました。10 ケース × 各 3 回(n=30)、すべてこの API 経由、2026-09-22 実測です。

方式素直にパースできた宣言どおりの値だったp50p95
POST /v1/jev30 / 3030 / 30439 ms525 ms
gpt-5.4-nano に JSON を依頼30 / 3030 / 30949 ms1,451 ms
deepseek-v3 に JSON を依頼20 / 3020 / 301,697 ms2,402 ms

性能の良いモデルは、ちゃんと JSON を返します。 このページの以前の版は gpt-5.4-nano を 5/6 と書き、そこを根拠にしていました。n=30 では 30/30 です。少ない試行のゆらぎを読んでいたということになります。使っているモデルが良く、プロンプトが丁寧なら、「JSON が返ってこないから」はこのエンドポイントを使う理由になりません。

試行を増やしても残った違いは 3 つで、こちらが正直な売りです。

①速さ、とくに裾。p95 で 525 ms 対 1,451 ms の 2.8 倍。中央値でも 2.2 倍です。裾が短いことが、リクエストの経路に判断を置けるかどうかを決めます。

②同じ入力に同じ答えが返る。10 ケースすべてで /v1/jev は 3 回中 3 回一致しました。gpt-5.4-nano は 1 ケースで 2/3 に割れています。

③確率と confidence が付く。答えだけでなく、どれくらい強くそう言えるかが返ります。迷っているケースを人に回す設計ができるのは、これがあるからです。

deepseek-v3 は別の話で、30 回中 10 回が失敗しました(コードフェンスの救済はしていません)。"route":"tech|billing" を繰り返し返す、つまりプロンプトに書いた選択肢の一覧を、そのまま値としてコピーする失敗です。性能の低いモデルは確かにこう壊れますし、判断専用のエンドポイントはこの種類の失敗ごと無くします。選択肢はこちらが宣言し、答えはその中のどれかになります。

3 つの質問タイプ​

タイプ渡すもの返るもの
choice名前つきの選択肢宣言したキーのどれか+各キーの確率
score低い順に並べたラベルその尺度上の連続値+段ごとの確率
noul質問文だけ0〜1 の数値(どれくらい「はい」か)

noul は真偽値ではありません。「はい」の強さなので、しきい値をモデルではなくこちら側が決められます。確認ダイアログを出すだけなら 0.5、何かを削除するなら 0.9、といった使い分けができます。

最初の 1 回​

curl -X POST https://api.aicu.ai/v1/jev \
-H "Authorization: Bearer aicu_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"state": "問い合わせ本文: 「昨日から /v1/chat/completions が 401 を返します。キーは先週発行したものです。請求書も届いていません。」",
"questions": {
"route": {
"type": "choice",
"instructions": "この問い合わせの一次担当を決める",
"criteria": {
"tech": "技術サポート",
"billing": "請求・経理",
"sales": "営業",
"abuse": "不正利用調査"
}
},
"urgency": {
"type": "score",
"instructions": "緊急度",
"criteria": ["翌営業日でよい", "当日中", "数時間以内", "即時"]
},
"needs_human": {
"type": "noul",
"instructions": "人間のオペレーターに引き継ぐべきか"
}
}
}'

返ってきた応答(そのまま):

{
"object": "jev",
"model": "jev-1.13.0",
"answers": {
"route": {
"type": "choice",
"choice": "tech",
"probabilities": { "tech": 0.89, "billing": 0.1, "abuse": 0.01, "sales": 0 },
"confidence": 0.85
},
"urgency": {
"type": "score",
"score": 1.57,
"legend": { "0": "翌営業日でよい", "1": "当日中", "2": "数時間以内", "3": "即時" },
"probabilities": { "0": 0.04, "1": 0.4, "2": 0.5, "3": 0.06 },
"confidence": 0.45
},
"needs_human": { "type": "noul", "noul": 0.8 }
},
"usage": { "input_tokens": 492, "output_tokens": 79 },
"ap_cost": 2
}

answers.route.choice は、こちらが宣言したキーのどれかです。それ以外にはなりません。つまり下のような分岐に、「想定外の値が来たのでアラートを上げる」default: を書かなくて済みます。

route = res["answers"]["route"]["choice"] # "tech" | "billing" | "sales" | "abuse"
urgency = res["answers"]["urgency"]["score"] # 0.0 〜 3.0
if res["answers"]["needs_human"]["noul"] > 0.7:
assign_to_human(route, urgency)

答えだけでなく confidence を読む​

質問ごとに confidence が返り、同じ応答の中でも値が違います。上の例では route が 0.85、urgency は 0.45。誰が担当すべきかははっきりしていて、どれくらい急ぐかは本当に迷っている、ということです。理由は確率に出ています。urgency は「当日中」0.40 と「数時間以内」0.50 で割れています。

ここが使いどころです。低い confidence を、それ自体ひとつの分岐先として扱えます。

r = res["answers"]["route"]
if r["confidence"] < 0.6:
queue_for_review(ticket) # 推測させず、人が見る列へ
else:
assign(r["choice"])

文章で返る答えにはこれがありません。「これは請求の問題です」という一文は、確信があってもなくても同じ調子で返ってきます。

複数の質問をまとめて聞く​

上の例の 3 問は 1 回の呼び出しで、1 回分の料金で答えが返っています。ひとつの状況について知りたいことは、まとめて 1 リクエストにしてください。安く、往復が 1 回で済み、すべての答えが同じ文脈に対して出されます。

score はラベルに尺度を書く​

score の criteria は低い順の配列です。ラベルが実際に働きます。モデルはそこから尺度の意味を読むので、新しく入った同僚に説明するつもりで書いてください。

{
"risk": {
"type": "score",
"instructions": "レギュレーション違反の度合い",
"criteria": ["問題なし", "軽微", "重大", "明確な違反"]
}
}

「実在の人物の写真を許可なく学習させた」と作者自身が書いたコンテスト応募作について、これは 2.94(confidence 0.94、確率 {"2": 0.05, "3": 0.95})を返しました。中間で濁さず、尺度の上端に寄せています。

上限​

項目値
1 リクエストの質問数20
state20,000 文字
instructions(質問ごと)2,000 文字
criteria の項目数(質問ごと)20
criteria の 1 項目500 文字
questions 全体(JSON のバイト数)64,000 バイト
上流の待ち時間20 秒

state は必須です。model は任意で、jev-latest(既定)と jev-1.13.0 を受け付けます。それ以外は受理可能な一覧(allowed_models)を添えて拒否します。

料金​

基本 2 AP + 入力 1,000 文字ごとに 1 AP(切り捨て)。典型的な 1 件は 2 AP です。 質問を何問入れても基本額は変わりません。変わるのは送った量のほうです。

ここでいう入力は state と questions の合計です(どちらも上流へ送るため)。上限いっぱいの入力で約 27 AP になります。

料金は上流を呼ぶ前に確保し、呼び出しが失敗したら全額返金します。失敗した判断にお金はかかりません。 応答には毎回 X-AICU-AP-Cost と X-AICU-AP-Balance、X-Credits-Remaining が付きます。

認証​

llm スコープを持つ Bearer キー。すでに /v1/chat/completions を呼べているキーなら、そのまま使えます。新しいスコープも、キーの再発行も不要です。

エラー​

ステータスcode起きるとき
400invalid_parameterstate が無い/質問の形が不正/未知の model/上限超過
400invalid_jsonボディが JSON でない
402insufficient_creditsAP が足りない
403—キーに llm スコープが無い
502generation_failedプロバイダが失敗、または answers を返さなかった(返金)
503internal_error判断プロバイダが利用できない(返金)

向いていないこと​

これが返すのは判断であって、文章ではありません。人が読む一文が必要なら LLM API を呼んでください。両方要ることもよくあります。まずこれで判断し、文章が要ると分かったものにだけモデルを使う、という順番です。

中で使っているもの​

TypeSafe の Jev を Cloudflare Workers AI 経由で呼んでいます。TypeSafe のアカウントも、Cloudflare のアカウントも、それぞれの鍵も要りません。いま持っている aicu_live_ キーだけで動きます。

Jev は System One モデルと呼ばれる種類のもので、文字列を生成してから解析するのではなく、一つの状態を型付きの質問に照らして評価し、答えを並列に返します。較正済みの確率つきです。質問を 3 つ入れたリクエストが、1 つのリクエストとほぼ同じ時間・同じ AP で済むのはこのためです。

state には文字列・オブジェクト・配列を渡せます。Cloudflare の公式サンプルは、ネストしたオブジェクトを渡すものも含めて、そのまま動きます。数値・真偽値・null は 400 invalid_parameter で弾かれます(上流の Jev も受け付けないため)。