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 実測です。
| 方式 | 素直にパースできた | 宣言どおりの値だった | p50 | p95 |
|---|---|---|---|---|
POST /v1/jev | 30 / 30 | 30 / 30 | 439 ms | 525 ms |
gpt-5.4-nano に JSON を依頼 | 30 / 30 | 30 / 30 | 949 ms | 1,451 ms |
deepseek-v3 に JSON を依頼 | 20 / 30 | 20 / 30 | 1,697 ms | 2,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 |
state | 20,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 | 起きるとき |
|---|---|---|
| 400 | invalid_parameter | state が無い/質問の形が不正/未知の model/上限超過 |
| 400 | invalid_json | ボディが JSON でない |
| 402 | insufficient_credits | AP が足りない |
| 403 | — | キーに llm スコープが無い |
| 502 | generation_failed | プロバイダが失敗、または answers を返さなかった(返金) |
| 503 | internal_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 も受け付けないため)。