2026/09/26

curl、Python、JavaScript から Jev API を呼び出す方法

ターミナルに、そしてアプリにそのまま貼り付けられる最初の Jev AI /v1/systemone リクエスト — 実際のレスポンス、実測のレイテンシ、エラー表をすべて掲載。

最初の呼び出しの前に

Jev は型付きの判断を返します。状態と名前付きの質問を送ると、宣言した回答のうちの 1 つを確率付きで返します。Optio はリクエストを Jev に転送する、独立して運営されているゲートウェイです。アカウントを作成し、ダッシュボードを開いて API キーを作成します。キーの全体は一度しか表示されず、jev_live_ で始まります。サーバー側のシークレットマネージャか環境変数に保存し、フロントエンドのコードや Git リポジトリには絶対に置かないでください。

エンドポイントはどのクライアントでも同じです:

POST https://jevai.website/api/v1/systemone
Authorization: Bearer $JEV_API_KEY
Content-Type: application/json
エンドポイントと認証ヘッダー

最小限のリクエスト

リクエストボディは 2 つの部分からなります:state(判断の対象)と questions(知りたいこと)です。state はプレーンな文字列、文字列の配列、JSON オブジェクトのいずれかで、最大 100,000 文字です。questions は 1〜8 個の名前付き質問のマップです。名前は有効な識別子である必要があります(英数字とアンダースコア — そのまま回答のキーになります)。

curl https://jevai.website/api/v1/systemone \
  -H "Authorization: Bearer $JEV_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "state": "The payments webhook failed twice overnight. Should I wake up the on-call engineer?",
    "questions": {
      "page": {
        "type": "noul",
        "instructions": "Should someone be paged right now?",
        "criteria": {
          "true": "Revenue-impacting or data loss",
          "false": "Can wait until morning"
        }
      }
    }
  }'
curl — はい/いいえの質問 1 件

criteria の値は自分の言葉で書きます — ポリシーの条文のように書いてください。モデルはこの文言を判断基準にするため、「Should someone be paged?」のような質問でも、true/false の定義を明示しておけば、丸投げした場合よりはるかに再現性が高くなります。

レスポンスの姿

このエンドポイントの実際の 200 レスポンスは次のようになります(ライブゲートウェイで取得。トークン数は実際のリクエストのもの):

{
  "request_id": "req_fe17d05411092c4f7f97947a",
  "model": "jev-1.14.0",
  "answers": {
    "page": { "type": "noul", "noul": 0.91 }
  },
  "usage": {
    "input_tokens": 128,
    "output_tokens": 21,
    "credits": 1,
    "credits_remaining": 4
  },
  "latency_ms": 432
}
200 レスポンス(要約)

回答は質問名をキーに返されるので、コードでの分岐は簡単です:if (answers.page.noul < 0.8) escalate()。すべてのレスポンスには request_id も含まれます — サポートに問い合わせるときはこの値を伝え、照合のために自分側でもログに残しておいてください。

3 つの質問タイプ

  • noul — はい/いいえ。回答が「はい」である確率(0〜1)を noul として返します。true/false の説明を含む criteria は任意ですが、指定を推奨します。
  • choice — ラベル付きの 2〜20 個の選択肢から 1 つを選びます。choice(選ばれたラベル)、選択肢ごとの probabilities、confidence を返します。
  • score — 状態を 2〜10 段階の順序付きスケール上に置きます(例:[穏やか, 不満, 激怒])。連続値の score(0 = 最初のレベル)、レベル上の probabilities、スコア範囲をラベルに対応させる legend、confidence を返します。

1 つのリクエストには最大 8 つの質問を乗せられます — 課金は質問単位ではなく入力トークン単位で、最低 1 クレジットであるため、これはコストの観点で重要です。合計が 1,000 トークン未満に収まる限り、同じ状態に対する 3 つの質問は 1 つの質問と同じコストです。

Python と JavaScript で回答をパースする

import os, requests

resp = requests.post(
    "https://jevai.website/api/v1/systemone",
    headers={"Authorization": f"Bearer {os.environ['JEV_API_KEY']}"},
    json={
        "state": {
            "ticket": {"subject": "Refund duplicate charge", "order": "A-104"},
            "refund_policy": "Duplicate charges are eligible for a full refund.",
        },
        "questions": {
            "policy_supports": {"type": "noul", "instructions": "Does the policy support this refund?"},
            "frustration": {"type": "score", "instructions": "How frustrated is the customer?",
                            "criteria": ["Calm", "Frustrated", "Very angry"]},
        },
    },
    timeout=30,
)
resp.raise_for_status()
answers = resp.json()["answers"]
if answers["policy_supports"]["noul"] > 0.9:
    print("auto-approve; frustration =", answers["frustration"]["legend"])
Python
const resp = await fetch("https://jevai.website/api/v1/systemone", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.JEV_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    state: "Charged twice for order A-104, please refund the duplicate.",
    questions: {
      route: {
        type: "choice",
        instructions: "Which team handles this?",
        criteria: {
          billing: "Payments, payouts, invoicing, refunds",
          technical: "Bugs, outages, integrations",
          sales: "Pricing, upgrades, new accounts",
        },
      },
    },
  }),
});
const { answers, usage, latency_ms } = await resp.json();
console.log(answers.route.choice, answers.route.probabilities, latency_ms);
JavaScript / TypeScript

エラーコードとリトライ

エラーは常に同じ形式です:{error: {code, message, request_id}}。メッセージ本文ではなく code で分岐してください。表は次のとおりです:

  • 401 missing_api_key / invalid_api_key — Bearer ヘッダーがない、またはキーが失効しています。リトライしないでください。
  • 402 insufficient_credits — ワークスペースの残高では確保分を賄えません。リトライせず、チャージしてください。
  • 422 invalid_request — ボディの形式が不正、質問名が無効、質問が 0 件、state が 100,000 文字を超過。リトライせず、リクエストを修正してください。
  • 429 rate_limited — プランの同時実行数または 1 分あたりリクエスト数の上限に達しました。指数バックオフでリトライしてください。レスポンスには Retry-After と X-RateLimit-Remaining ヘッダーが含まれます。
  • 502 upstream_error(upstream_timeout、upstream_unreachable も同様)— モデルプロバイダーが失敗したか、15 秒の上游タイムアウト時間が経過しました。バックオフ付きでリトライしてください。課金はされていません。
  • 529 upstream_overloaded — プロバイダーのキャパシティです。502 と同じ対応をします。
import time

def decide(body, max_retries=3):
    for attempt in range(max_retries + 1):
        resp = requests.post(URL, headers=HEADERS, json=body, timeout=30)
        if resp.status_code in (429, 502, 529):
            time.sleep(min(2 ** attempt, 8))
            continue
        resp.raise_for_status()
        return resp.json()
    raise RuntimeError("upstream kept failing; give up or degrade")
そのまま使える Python のリトライループ

クレジットはモデルの実行前に確保され、実行後に実際のトークン数で精算されます。プロバイダーが失敗した場合、確保分は自動的に返還されます。失敗したリクエストが台帳に課金として残ることはありません。

コストと応答速度

1 クレジットは入力 1,000 トークンで、課金額は ceil(入力トークン / 1,000)、最低 1 です。出力トークンは無料です。上記のテストでは、2 つの質問を含む 401 トークンのリクエストがちょうど 1 クレジットでした。Starter パック($10 = 100,000 クレジット)では 1 判断あたり $0.0001 です。

レイテンシ:1 営業日に 16 回連続でライブ呼び出しを行ったところ、報告された latency_ms は、質問 1 件のリクエストでも 2 件のリクエストでも 400〜560 ms 付近に集中し、中央値は約 445 ms でした。アイドル期間の後の最初の呼び出しでは、ときおり約 3 秒のコールドスタートが発生しました。このサンプルサイズでは長い裾は観測されていません。この 1 回の測定を信用するのではなく、自分のリージョンの p99 からタイムアウトを設定してください。

1 つのリクエストで 8 を超える質問はできますか?

できません — 1 リクエストあたり 8 質問が上限です。残りは同じ状態に対する 2 回目のリクエストに分けるか、優先度の低い質問をより安価なバッチ処理に回してください。

最初の無料クレジットはどこで手に入りますか?

新しいワークスペースには 5 クレジットが無料で付与され、Playground はブラウザで無料で使えます(匿名で 1 日 30 回、サインイン時は 50 回)。支払いを始める前に、実データでの判断の検証には 5 クレジットで十分です。

これは TypeSafe の公式エンドポイントですか?

いいえ。Optio は Jev を呼び出すための独立したゲートウェイであり、TypeSafe とは提携関係にありません。リクエスト形式は同じ /v1/systemone コントラクトに従うため、既存のクライアントをそのまま向けることができます。

Jev AI Playground を試す。このガイドを読み終えたら、最初の無料の判断を送ってみましょう。