Jev Recipe / 输出契约对比

Jev vs JSON Mode:类型化决策与受限生成的对比

json_mode 只保证「语法合法的 JSON」,不保证「正确的答案」。逐项对比重试成本、延迟、输出计费与置信度校准,看受限生成与 Jev 零生成类型化调用的契约差异。

放弃 JSON mode 之前的 6 项检查

01先说清 json_mode 真正承诺了什么:语法合法性。response_format: {type: "json_object"} 保证模型不会吐出坏掉的 JSON 字面量——但它对你的 key、枚举值、以及答案本身对不对,只字未提。
02把流水线真正需要的三层保证拆开:语法合法(json_mode)、符合 schema(structured outputs / json_schema)、值正确(没有任何机制保证)。受限解码补上了前两层,第三层——真正把路由搞坏的那层——依然敞开着。
03上线之前先算重试税:一个形状合格但枚举值幻觉的回复,照样按完整生成计费;每次校验失败都会重新计一遍。在分类量级下,重试不是边缘案例——它就是你的成本模型。
04诚实地对待置信度:逐 token logprob 度量的是「模型有多确定要写下下一个字符」,不是「这个决策有多可能正确」。只有 RLCD 校准过的概率,才能让 0.85 阈值变成精度契约。
05对照你的业务量看延迟曲线:生成时间随输出长度增长——典型 JSON 载荷 500ms 到 2s+,重试还要再乘。Jev 的 evaluate 调用一次前向返回所有类型化答案,~70–100ms,与你塞进多少个问题无关。
06知道受限生成什么时候仍然是对的工具:自由内容——摘要、变长列表、嵌套的生成字段——超出 Jev 的能力,它的决策头只返回有界值。让有界决策走 Jev、生成式载荷走受限生成,同一条流水线里各干各的。
schema / 类型化决策契约
{
  "intent": {
    "type": "choice",
    "instructions": "判断这条进站消息属于哪类",
    "criteria": {
      "billing": "付款、发票或退款问题",
      "technical": "产品故障或 bug",
      "sales": "购买、升级或报价咨询",
      "abuse": "安全或滥用举报"
    }
  },
  "is_actionable": {
    "type": "noul",
    "instructions": "这条消息需要团队采取行动,还是纯知会?"
  },
  "priority": {
    "type": "score",
    "instructions": "为处理优先级打分,1(有空再说)到 5(放下手头一切)"
  }
}
这套 schema 就是「JSON schema 加校验层」一直在逼近的东西——在 Playground 里跑一次,看答案和校准置信度一次性返回。

输出契约:Jev 类型化决策头 vs json_mode / structured outputs

METRIC
Jev
json_mode / structured outputs
真正被保证的是什么
决策头给出的类型化答案——值级契约:你的选项之一、一个分数、或一个 yes/no
json_mode:只保证 JSON 语法合法;structured outputs:保证形状符合 schema——字段值仍是生成的
规模化后的失败模式
没有解析环节——结构上 0% 格式错误
JSON 合法但值错误或缺失:幻觉枚举、看似合理却错误的路由——每次失败都触发一次计费重试
延迟曲线
~70–100ms 恒定——无生成,与问题数量无关
随输出长度增长——典型载荷 500ms 到 2s+,每次重试再乘一遍
输出 token 成本
$0——不存在输出 token
每次尝试按完整输出计费;重试会把整个生成重新计一遍
置信度语义
RLCD 校准的决策置信度——0.85 ≈ 85% 精度,阈值即契约
充其量是逐 token logprob——采样统计量,不是决策校准
载荷中的自由内容
不支持——决策头只返回有界值,绝不产散文
天然强项——摘要、变长列表、嵌套生成字段

代码对比:受限生成 vs Jev 类型化调用

python / openai json_mode + 值校验重试循环
import json
import time
from openai import OpenAI

client = OpenAI()
VALID_QUEUES = {"billing", "technical", "sales", "abuse"}
MAX_RETRIES = 3

def route_ticket(ticket_text: str) -> dict:
    for attempt in range(MAX_RETRIES):
        resp = client.chat.completions.create(
            model="gpt-4o-mini",
            response_format={"type": "json_object"},
            messages=[
                {"role": "system", "content": 'Reply as JSON: {"queue": "...", "urgent": true|false}'},
                {"role": "user", "content": ticket_text},
            ],
        )
        payload = json.loads(resp.choices[0].message.content)  # json_mode:一定能解析
        if payload.get("queue") in VALID_QUEUES:  # 值校验:json_mode 对此只字未提
            return payload
        time.sleep(2 ** attempt)  # 幻觉枚举 -> 整个生成重新计费
    raise ValueError("queue never converged")

# 典型路径:每次尝试 500-1500ms,每轮重试都按 20-60 个输出 token 计费
python / jev 类型化多问题调用
import requests

JEV_ENDPOINT = "https://api.typesafe.ai/v1/jev/evaluate"
AUTO_ROUTE_CONFIDENCE = 0.85

QUESTIONS = {
    "intent": {
        "type": "choice",
        "instructions": "判断这条进站消息属于哪类",
        "criteria": {
            "billing": "付款、发票或退款问题",
            "technical": "产品故障或 bug",
            "sales": "购买、升级或报价咨询",
            "abuse": "安全或滥用举报",
        },
    },
    "is_actionable": {
        "type": "noul",
        "instructions": "这条消息需要团队采取行动吗?",
    },
    "priority": {
        "type": "score",
        "instructions": "为处理优先级打分,1(有空再说)到 5(放下手头一切)",
    },
}

resp = requests.post(
    JEV_ENDPOINT,
    json={"state": {"message": "..."}, "questions": QUESTIONS},
    timeout=5,
)
resp.raise_for_status()
data = resp.json()

if data["intent"]["confidence"] >= AUTO_ROUTE_CONFIDENCE:
    lane = f"auto:{data['intent']['answer']}"  # ~70-100ms,只计输入 token,零重试
else:
    lane = "review"
typescript / openai structured outputs(json_schema)
import OpenAI from "openai";
import { z } from "zod";
import { zodResponseFormat } from "openai/helpers/zod";

const RouteDecision = z.object({
  queue: z.enum(["billing", "technical", "sales", "abuse"]),
  urgent: z.boolean(),
});

const client = new OpenAI();

const resp = await client.chat.completions.create({
  model: "gpt-4o-mini",
  response_format: zodResponseFormat(RouteDecision, "route_decision"),
  messages: [{ role: "user", content: ticketText }],
});

const decision = RouteDecision.parse(
  JSON.parse(resp.choices[0].message.content!),
);
// 形状有保证。"queue" 是不是正确的队列——以及模型有多确定——
// 都无法表达:你拿到的是一个猜测,不是校准过的决策。
typescript / jev 类型化多问题调用
const JEV_ENDPOINT = "https://api.typesafe.ai/v1/jev/evaluate";
const AUTO_ROUTE_CONFIDENCE = 0.85;

const QUESTIONS = {
  intent: {
    type: "choice",
    instructions: "判断这条进站消息属于哪类",
    criteria: {
      billing: "付款、发票或退款问题",
      technical: "产品故障或 bug",
      sales: "购买、升级或报价咨询",
      abuse: "安全或滥用举报",
    },
  },
  is_actionable: {
    type: "noul",
    instructions: "这条消息需要团队采取行动吗?",
  },
  priority: {
    type: "score",
    instructions: "为处理优先级打分,1(有空再说)到 5(放下手头一切)",
  },
} as const;

const resp = await fetch(JEV_ENDPOINT, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    state: { message: ticketText },
    questions: QUESTIONS,
  }),
});
const data = await resp.json();

const lane =
  data.intent.confidence >= AUTO_ROUTE_CONFIDENCE
    ? `auto:${data.intent.answer}`
    : "review"; // 低置信带或安全旗标 -> 同一条复核队列

Jev vs JSON Mode 常见问题

什么是 JSON mode?

OpenAI 聊天补全的一个特性——response_format: {"type": "json_object"}——如今大多数主流厂商都有等价物:约束模型只输出语法合法的 JSON,不带 markdown 围栏、不夹散文。但它只保证「可解析」。你的 key、枚举值、以及里面那个答案对不对,仍是模型的猜测——这也是生产代码依然要在 json_mode 外面再包一层 schema 校验和重试循环的原因。

JSON mode 和 structured outputs 是一回事吗?

不是。JSON mode(json_object)只保证语法合法;structured outputs(json_schema)更进一步,通过受限解码强制输出形状匹配你的 schema。但两者都仍在逐 token 生成载荷:延迟随输出长度增长、输出 token 计费、值是否正确没有任何保证。structured outputs 补上了形状缺口;决策质量缺口依旧敞开。

JSON 都合法了,为什么流水线还是会崩?

因为规模化之后,「可解析」从来不是难的部分——难的是值正确。一个形状合格但枚举值幻觉("queue": "shippping")、看似合理却路由错误、或缺字段的回复,解析干干净净、应用照样出错。而每一次这样的失败都会触发一次校验重试,把完整生成重新计费。拿你实测的失败率乘以单次输出成本和 QPS——这个乘积就是「没有校准地靠猜」的价签。

json_mode 或 structured outputs 能拿到置信度吗?

拿不到可用于决策的置信度。logprob 度量的是采样分布下每个 token 被生成的可能性——是「打字置信度」,不是「决策准确度」。一个以高 token 概率输出的路由标签仍然可能是错的。Jev 的概率是对着结果 RLCD 校准的,0.85 阈值的行为接近精度契约——正是这个性质让「对着数字做自动化」变得安全。

什么时候应该继续用 JSON mode 而不是 Jev?

载荷必须包含自由生成内容的时候:摘要、解释、变长列表、抽取的散文、带文本字段的嵌套对象。Jev 的决策头只返回有界值——它写不出一段话。生产里的标准分工:Jev 用一次 ~95ms 的调用回答有界问题(路由、门禁、评分、yes/no),受限生成调用负责填那些生成式字段。

这和 Instructor、以及 OpenAI 的 Decision API(Luna)是什么关系?

同一个问题的三个不同层。Instructor 是在库层给生成包上 Pydantic 校验和重试循环——见 Jev vs Instructor 对比。json_mode 和 structured outputs 是在 API 层约束生成——就是本页。OpenAI 基于 GPT-6 Luna 的 Decisions API 是另一个非生成产品:从预定义答案集中返回一个答案加置信度——契约级对比见 Jev vs OpenAI Decision API。所有方向的箭头都指向同一处:离开「解析生成文本」,走向「类型化决策」。

继续深入结构化输出家族