Jev Recipe / アーキテクチャ比較
Jev vs Instructor:構造化出力の 2 つの設計
最終更新日: 2026-11-12
判断という有限の意思決定には Jev、豊かな構造の生成・抽出入力には Instructor。エンドポイント、公式 SDK のコード、トレードオフを 2026-11-12 に確認した内容で並べます。
広告
Instructor から Jev への移行 3 ステップ
01Instructor の Pydantic / Zod モデルを、等価な Jev の契約に翻訳します。キューは Choice、度合いは Score、はい/いいえは Noul です。
02「生成 → パース → 検証 → 再試行」のループを 1 回の client.systemOne() に置き換えます。単一のフォワードパスで、設問ごとの型付き答案と確率が返ります。
03confidence のしきい値は業務コード側に置いて分岐させます。指数バックオフの再試行でフォーマットエラーを覆い隠すのではなく、です。
schema / 共通意思決定コントラクト
{
"routing": {
"type": "choice",
"instructions": "チケットを正しいキューへ振り分ける",
"criteria": {
"billing": "決済、返金、インボイス",
"technical": "製品不具合や設定トラブル",
"sales": "購入相談や見積もり"
}
}
} このスキーマは Instructor Pydantic モデルと等価であり、Playground でゼロリトライ判定を検証できます。
アーキテクチャ:契約優先 vs 生成してから検証
METRIC
Jev
Instructor / Guardrails
何を生成するか
テキストを生成しません。宣言した選択肢を採点し、設問ごとに型付き答案を 1 つ返します。
JSON テキストを生成し、Pydantic / Zod モデルで検証します。
出力トークン費用
なし。TypeSafe は入力トークンのみ課金(2026-11-12 時点 $0.042/M)。
フル生成課金:捨てられた再試行分も含め、出力トークンすべてに支払います。
レイテンシ
単一フォワードパスで自己回帰デコードなし。TypeSafe は SLA を公開していないため自分の経路で実測してください。
モデルと応答長に完全に依存します。自分の schema とプロバイダーで実測してください。
失敗の形
答案は必ず宣言した選択肢のいずれか。設計すべき失敗は「信頼度が低い」ことです。
検証が失敗すると再試行ループに入ります。出力長と入れ子の深さが失敗率を左右します。
信頼度
設問ごとの確率分布と confidence。ただし自分のラベルでの較正は別途必要です。
モデルの自己申告(ある場合)。そのままゲートに使える確率ではありません。
Schema 表現力
Choice(最大 255 選択肢)、Score、Noul、画像領域の Box。答案はフラットな値で、入れ子文書ではありません。
任意の入れ子 schema、長い文字列、オブジェクト配列——それが存在理由です。
コード対照:リトライループ vs ゼロリトライ型呼び出し
python / instructor リトライループ
import instructor
from openai import OpenAI
from pydantic import BaseModel
class RouteDecision(BaseModel):
queue: str
client = instructor.from_openai(OpenAI())
def route_ticket(ticket: str) -> RouteDecision:
return client.chat.completions.create(
model="gpt-4o-mini",
response_model=RouteDecision,
max_retries=3,
messages=[{"role": "user", "content": ticket}],
)python / typesafe-sdk による型付き判定
from typesafe_sdk import Choice, TypeSafeClient
client = TypeSafeClient(model="jev-latest")
def route_ticket(ticket: str) -> dict:
response = client.system_one(
state=ticket,
questions={
"routing": Choice(
instructions="チケットを正しいキューへ振り分ける",
criteria={
"billing": "決済、返金、インボイス",
"technical": "製品不具合や設定トラブル",
"sales": "購入相談や見積もり",
},
),
},
)
routing = response.choices["routing"]
return {
"queue": routing.choice, # 必ず宣言した選択肢のいずれか
"confidence": routing.confidence, # ゲートに使う前に較正する
"probabilities": routing.probabilities,
}typescript / @typesafe-ai/sdk による型付き判定
import { choice, TypeSafeClient } from "@typesafe-ai/sdk";
const client = new TypeSafeClient({ defaultModel: "jev-latest" });
export async function routeTicket(ticket: string) {
const { answers } = await client.systemOne({
state: ticket,
questions: {
routing: choice("チケットを正しいキューへ振り分ける", {
billing: "決済、返金、インボイス",
technical: "製品不具合や設定トラブル",
sales: "購入相談や見積もり",
}),
},
});
return {
queue: answers.routing.choice, // 必ず宣言した選択肢のいずれか
confidence: answers.routing.confidence, // ゲートに使う前に較正する
};
}