Jev Recipe / 架构对比
Jev vs Instructor:结构化输出的两种工程路线
最近更新: 2026-11-12
有限决策交给 Jev、丰富结构交给 Instructor。端点、官方 SDK 代码与取舍,按 2026-11-12 核验的官方资料并列。
广告
从 Instructor 迁移到 Jev 的 3 个步骤
01先把 Instructor 的 Pydantic / Zod 模型翻译成等价的 Jev 契约:队列用 Choice,程度用 Score,是/否用 Noul。
02用一次 client.systemOne() 替换「生成 → 解析 → 校验 → 重试」循环,一次前向推理就返回每个问题的类型化答案与概率。
03把 confidence 阈值写进业务代码做分流,而不是用指数退避的重试风暴去掩盖格式错误。
schema / 共享决策契约
{
"routing": {
"type": "choice",
"instructions": "把工单分到正确队列",
"criteria": {
"billing": "付款、退款或发票",
"technical": "产品故障或使用问题",
"sales": "购买、升级或报价",
"abuse": "安全或滥用举报"
}
}
} 此 schema 与 Instructor Pydantic 模型等价,可直接在 Playground 验证零重试结果。
架构对比:契约优先 vs 先生成再校验
METRIC
Jev
Instructor / Guardrails
生成什么
不生成文本。模型给你的候选选项打分,每个问题返回一个类型化答案。
生成 JSON 文本,再用你的 Pydantic / Zod 模型校验。
输出 token 成本
没有。TypeSafe 只按输入 token 计费(2026-11-12 为 $0.042/M)。
完整生成计费:每个输出 token 都要付钱,包括被丢弃的重试。
延迟
单次前向推理,没有自回归解码。TypeSafe 没有公布延迟 SLA,请自己实测链路。
完全取决于模型和响应长度。请用自己的 schema 与供应商实测。
失败模式
答案永远来自你声明的选项。需要设计的失败是「置信度低」。
校验可能失败并触发重试循环;输出长度与嵌套深度直接决定失败率。
置信度
每个问题都有概率分布和 confidence,但仍需用你自己的标注数据校准。
模型自报(如果有的话),不是可以直接拿来当门限的概率。
代码对比:重试循环 vs 零重试 typed 调用
python / instructor 重试循环
import time
import instructor
from openai import OpenAI
from pydantic import BaseModel, ValidationError
class RouteDecision(BaseModel):
queue: str
client = instructor.from_openai(OpenAI())
MAX_RETRIES = 3
def route_ticket(ticket_text: str) -> RouteDecision:
for attempt in range(MAX_RETRIES):
try:
return client.chat.completions.create(
model="gpt-4o-mini",
response_model=RouteDecision,
messages=[{"role": "user", "content": ticket_text}],
)
except ValidationError:
if attempt == MAX_RETRIES - 1:
raise
time.sleep(2 ** attempt) # 指数退避
# 典型路径:1800ms+ 延迟,每次尝试计费 20~50 output tokenspython / typesafe-sdk 类型化判定
from typesafe_sdk import Choice, TypeSafeClient
client = TypeSafeClient(model="jev-latest")
def route_ticket(ticket_text: str) -> dict:
response = client.system_one(
state=ticket_text,
questions={
"routing": Choice(
instructions="把工单分到正确队列",
criteria={
"billing": "付款、退款或发票",
"technical": "产品故障或使用问题",
"sales": "购买、升级或报价",
},
),
},
)
routing = response.choices["routing"]
return {
"queue": routing.choice, # 永远是你声明的选项之一
"confidence": routing.confidence, # 拿来当门限前先校准
"probabilities": routing.probabilities,
}typescript / instructor 重试循环
import OpenAI from "openai";
import Instructor from "@instructor-ai/instructor";
import { z } from "zod";
const RouteDecision = z.object({ queue: z.string() });
const client = Instructor({ client: new OpenAI(), mode: "TOOLS" });
async function routeTicket(ticket: string, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await client.chat.completions.create({
model: "gpt-4o-mini",
response_model: RouteDecision,
messages: [{ role: "user", content: ticket }],
});
} catch {
if (attempt === maxRetries - 1) throw new Error("schema validation failed");
await new Promise((r) => setTimeout(r, 2 ** attempt * 1000));
}
}
}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, // 拿来当门限前先校准
};
}