很多 AI 工作流最后只需要一个路由、一个等级和一个真假判断,却还是让通用大模型生成整段 JSON。最近我试了 TypeSafe AI 的 Jev:它不生成自由文本,只接收 state 和类型化 questions,再把概率化答案交给代码。
本文不复述宣传数字,直接用一条重复扣费工单拆接口,再给出六次真实 API 调用的环境、结果和限制。
一个请求里问三个独立问题
实验使用 @typesafe-ai/sdk@0.6.0。下面是请求结构的简化版:
js
import { TypeSafeClient, choice, score, noul } from '@typesafe-ai/sdk';
const client = new TypeSafeClient();
const response = await client.systemOne({
model: 'jev-latest',
state: {
message: '我被扣了两次钱,请今天退回多扣的一笔。'
},
questions: {
route: choice('Which queue should handle this request?', {
refund: 'The user asks to return money already paid.',
support: 'The user needs help but does not ask for money back.',
other: 'None of the above.'
}),
urgency: score('How urgently does this need human support?', [
'No active issue or deadline.',
'An issue exists without an imminent deadline.',
'Same-day handling or a blocked core function.',
'Ongoing severe impact that cannot wait.'
]),
explicit_refund: noul(
'Does the user explicitly ask for money to be returned?'
)
}
});
Choice 返回选项、各选项概率和 confidence;Score 返回有序等级的概率加权分、分布和 confidence;Noul 返回命题为 yes 的概率,没有额外 confidence。
问题 ID 只是代码取值的键,模型不会靠 route 这个名字理解问题。完整含义要写进 instructions 和 criteria。候选项没有 other,模型也不会凭空替你补上。
为什么要一起问
这三个问题都能直接根据原始消息回答,彼此不依赖,因此可以共享一份 state,在同一个请求里求值。代码拿到结果后再决定哪些答案要用。
如果下一步必须先抽取订单号、查询支付库,再判断是否真的重复扣费,就不能假装所有步骤都能并行。Jev 解决的是同一份上下文上的独立判断,不会消灭业务数据依赖。
这也是我认为它比"只会输出合法 JSON"更准确的定位:类型化结果只是底线,真正的设计点是预定义问题、概率分布、并行问题和代码组合。
六条调用结果
环境:Node.js v22.21.1、SDK 0.6.0、超时 15 秒、重试 0。2026 年 9 月 20 日,一个本机进程顺序发送六次请求;每次同时提交上述三类问题。请求模型为 jev-latest,响应实际模型均为 jev-1.13.0。
| 输入 | 路由 | confidence | 退款 Noul | urgency | 墙钟耗时 |
|---|---|---|---|---|---|
| 中文重复扣费,要求今天退款 | refund | 1.00 | 0.99 | 1.99 | 1962.02 ms |
| 英文重复扣费,要求今天退款 | refund | 1.00 | 0.99 | 2.00 | 782.15 ms |
| 中文明确不要退款,只问发票 | support | 1.00 | 0.03 | 0.08 | 822.18 ms |
| 英文不要退款,协助重置密码 | support | 1.00 | 0.03 | 0.43 | 744.75 ms |
| 中文模糊请求 | other | 0.54 | 0.02 | 0.06 | 823.44 ms |
| 英文无关故事请求 | other | 1.00 | 0.01 | 0.00 | 756.66 ms |
模糊请求的 other 概率为 0.70、support 为 0.30,但 confidence 是 0.54。选中项概率和 confidence 不是同一个字段。示例把 route confidence 小于 0.8 的结果送到 human_review,因此它不会自动路由。
这条 0.8 只是演示阈值,没有业务校准。六条合成样本也不是准确率测试集,更不是概率校准证明。
计时数字别看过头
计时范围包住一次 SDK 调用,包含网络往返和响应解析。没有预热、并发、重复统计或通用模型对照,所以不能把第一条 1962 毫秒解释为冷启动,也不能用它证明中文比英文慢。
TypeSafe 官方给过约 70--500 毫秒的端到端数字,以及工作流评测中的 193.6 倍速度、444.6 倍成本差异。官方同时说明评测通常从美国西海岸访问服务,工作流倍率可能位于真实收益高端。国内网络下应该重新测 p50/p95,而不是把宣传页数字写进 SLA。
confidence 应该怎样进入代码
我更倾向于把原始判断和执行策略分开:
js
function decideAction({ route, refund }) {
if (route.confidence < 0.8) {
return { action: 'human_review', reason: 'uncertain_route' };
}
const conflicts =
(route.choice === 'refund' && refund.noul < 0.8) ||
(route.choice !== 'refund' && refund.noul >= 0.8);
if (conflicts) {
return { action: 'human_review', reason: 'signals_conflict' };
}
return { action: 'route', destination: route.choice };
}
这个函数只给路由建议,不执行退款。真实交易仍要核对订单、身份、金额和规则。高 confidence 代表分布更集中,不是执行高风险动作的授权。
接入时我会保留的几条边界
- 先用带人工标签的数据验证,再定阈值。
- 记录响应里的版本化模型 ID;
jev-latest会移动。 - 英语是官方说明的主要训练语言,中文必须单独评估。
- 低置信、候选缺失或独立判断冲突时,明确回退路径。
- 安装 Agent skill 只是给 Coding Agent 补接入知识,不会下载模型,也不能把 Jev 设成代码助手的底层聊天模型。
完整可运行实验在原博客下载包中,默认 --dry-run 不读密钥、不联网;真实运行需要自己的 TYPESAFE_API_KEY。如果你准备在项目里试,我建议先找一个低风险、可回退、每天会重复很多次的判断,而不是一上来接管最终动作。
你们现在有哪些"让 LLM 返回 JSON"的调用,其实可以继续拆成更窄的判断?
相关资料:JavaScript SDK、Primitives、Confidence、Models。完整代码、依赖锁与实验快照见原博客文章。