摘要
你有没有写过这样的代码:让大模型判断一条工单是否紧急,于是你在 prompt 里写「请只返回 JSON,格式如下……」,然后拿到一堆带 ```json 标记、夹着「好的,我认为……」的文字,再用正则去抠、用try/except兜底、失败就重试一遍。
Jev 想干掉的就是这一步。
它是 TypeSafe 的旗舰模型,也是第一个所谓System One模型:输入是「状态(state)+ 一组类型化的问题(questions)」,输出是「类型化的答案 + 概率分布」。不生成文本,也不需要解析。
本文带你搞清楚:Jev 是什么、和 ChatGPT 这类大模型差在哪、三种原语怎么用、什么场景该交给它、它给出的概率凭什么可信,最后用一个完整的中文实战案例收尾。
关键词:Jev、TypeSafe、System One、RLCD、概率校准、AI Agent、LLM 工程化
TL;DR(太长不看)
- Jev 是 TypeSafe 的 System One 决策模型。
- 三种原语:Choice、Score、Noul。
- 与 LLM 本质区别:不生成文本,只出判断。
- 适用场景:路由、排序、批量分流等程序决策。
- 概率可信前提:RLCD 校准,需自测分布。
- 心法:模型管语义,代码管规则。
一、先说痛点:我们到底在为什么买单
传统 LLM 是为「人类阅读」而生的——它写出来的东西,是给人看的。
可一旦代码需要做判断,流程就变成了这样:
中间这一步「把生成的文字再解析回程序能依赖的形式」,既慢又脆。慢在要多生成一堆废话 token,脆在格式随时可能崩:多一个逗号、多一句寒暄、少一个引号,你的json.loads就炸了。
于是工程上涌现出各种补丁:JSON Mode、function calling、结构化输出约束、重试兜底、双模型校验……本质上都是在给「生成」这一步打补丁。
Jev 的思路更直接:把生成这一步整个砍掉。
它像 LLM 一样能读懂自然语言,但只返回你问的那几个数,而且每个数都带着概率。
二、Jev 是什么:一句话定义
Jev 是 TypeSafe 的旗舰模型,也是第一个 System One 模型——输入是 state 加一组类型化的问题,输出是类型化的答案加概率分布。没有文本生成,也没有解析。
用公式表示就是:
Jev(state, questions) → { answer₁: (value₁, p₁), answer₂: (value₂, p₂), … }这里的state就是你要判断的那段文本(可以是一句话、一段对话、一个 JSON、一个文本数组),questions是你预先定义好的一组带类型的问题。
两个必须知道的边界
- 目前只接受文本输入——字符串、JSON、文本数组都行,图像/音频/视频暂不支持。
- 名字借自《思考,快与慢》的「系统 1」——取「快速直觉判断」这个意象,不是说它在科学上复现了人类思考。别过度解读这个名字。
三、和聊天大模型到底差在哪
这是最容易被问到的问题,官方给了个非常清晰的对比表:
维度 | 聊天大模型(LLM) | Jev(System One) |
训练目标 | 生成讨人喜欢的回复(RLHF) | 校准决策(RLCD):概率对齐真实结果 |
输出 | 一段自由文本 | 类型化取值 + 概率分布(由你的问题定义) |
会做什么 | 写作、代码、解释推理 | 只做判断;不写回复、不解释推理 |
适合谁消费 | 人 | 程序:分支、排序、路由 |
关键差异在第二行——训练目标。
- RLHF(人类反馈强化学习):目标是让回复更讨人喜欢,产出是文本。
- RLVR(可验证奖励强化学习):目标是让推理更准,产出是会思考但更慢更贵的模型。
- RLCD(面向校准决策的强化学习):Jev 走的第三条路——训练模型返回决策和校准概率,而不是文本。
一句话总结:LLM 是给写给人看的内容的,Jev 是给程序做分支用的。
它不会给你写周报,也不会给你解释推理过程。它就是个高速、带概率的判断器。
四、三种原语,就是它的全部词汇
Jev 的全部表达能力,就三个原语(primitive)。记住这三个,你就掌握了它的 90%。
原语 | 问题类型 | 示例输出 |
| 从选项中选一个 |
|
| 按有序标准打分 |
|
| 某陈述是否为真 |
|
4.1 Choice —— 是哪一类?
从一组互斥的选项里挑一个,返回选中的标签 + 每个选项的概率。
criteria是「选项 key → 选项描述」的字典。选项 key 建议用英文,描述用中文,这样代码里判断分支时不会被中文 key 坑到编码问题。
4.2 Score —— 打几分?
按一组有序的标准打分,返回的是概率加权后的期望值(所以会出现 1.4 这种小数,而不是硬选一档)。
注意criteria这里传的是列表(有序),不是字典。下标 0/1/2 对应三档,最终score = Σ(下标 × 概率)。
比如概率分布是{0: 0.05, 1: 0.26, 2: 0.69},那么:
这个设计很妙——它把「模棱两可」诚实地表达成了 1.64,而不是强行归到某一档。
4.3 Noul —— 是不是?
判断某个陈述是否为真,返回一个 0~1 的概率值。
noul这个名字挺怪,官方的解释是它代表一个「是/否 + 不确定度」的量。不确定性直接体现在数值靠近 0.5——0.95 是很确定,0.55 是基本没谱。
4.4 一次调用,三种混用(核心体验)
这是 System One 最值得体验的一点:
三种问题可以在一次调用里混用,每个问题并行、相互独立地对照同一个 state 求值。
带来两个直接好处:
- 加问题几乎不增加延迟——不是串行地问三个问题,是一次往返问完。
- 没有长上下文「越读越糊」的问题——每个问题独立看同一份 state,不存在多轮对话那种注意力稀释。
五、三分钟上手
5.1 环境准备
要求 Python ≥ 3.10:
注意一个坑:安装包名是typesafe-sdk,Python 导入名是typesafe_sdk(横杠 vs 下划线)。
然后配置 API Key(不要写进代码或 Notebook):
5.2 最快的方式:一行 curl
不想装 SDK,直接发 HTTP 也行:
也可以直接去官方 Playground 粘贴文本试,连登录都省了。
5.3 Python SDK:一次调用问三个问题
from typesafe_sdk import Jev 初始化客户端:传入你的 API Key(建议从环境变量读取,不要硬编码) jev = Jev(api_key="YOUR_API_KEY") 定义要判断的文本(state) state = "我的订单已经付款三天了,但一直显示待发货,客服也没人理,我要投诉!" 定义三个类型化的问题(questions) questions = [ { "key": "urgency", # 问题标识,用于在结果中取值 "type": "score", # 类型:score(打分) "criteria": [ # 有序标准列表,下标 0/1/2 对应三档 "0:常规咨询,可稍后处理", "1:需要尽快处理,但不危及安全", "2:紧急,涉及资金或权益受损" ] }, { "key": "category", # 问题标识 "type": "choice", # 类型:choice(分类) "criteria": { # 选项 key → 描述(key 用英文,描述用中文) "refund": "客户要求退款", "complaint": "客户投诉服务质量", "inquiry": "普通咨询,可自动回复" } }, { "key": "needs_human", # 问题标识 "type": "noul", # 类型:noul(是非判断) "criteria": "这条消息是否需要人工客服介入" # 陈述句,返回 0~1 概率 } ] 一次调用问完三个问题,返回带概率的结果 resp = jev.ask( state=state, # 要判断的文本 questions=questions # 类型化问题列表 ) 打印结果:每个答案都带概率 print(f"紧急度 = {resp['urgency'].score:.2f}") print(f"类别 = {resp['category'].choice} (概率: {resp['category'].probabilities})") print(f"转人工 = {resp['needs_human'].noul:.2f}")5.4 读结果
一发请求,三份带概率的答案。这就是 System One 的核心体验。
拿到手之后,你的代码可以直接这么写:
干净、可测、不需要任何正则。
六、提问纪律:原子性(最重要的工程经验)
这是整份教程里我认为最有价值的一条:
每个问题只问一件专家几秒内能下结论的事(原子判断)。
复杂判断拆成多个独立问题,在代码里用你自己的逻辑加权组合。
这样做的好处是:优先级变了,只改代码里的系数,不用改提示词、不用重跑评测。
反例:一个问题问两件事
比如你想问「该不该给这条工单升级到人工?」
这是个不合格的问题。它其实混了两个独立判断:
- 这个问题严重不严重?→
Score或Noul
- 当前的自动流程能不能处理?→
Noul或Choice
如果塞进一个noul里问,任一因素翻转都会污染概率——你拿到 0.6 的时候,根本不知道是「不严重但要升级」还是「严重但能自动处理」。
正例:拆开问,代码里组合
模型管语义,代码管规则。这句话是 Jev 用法的心法。
七、场景地图:什么活儿适合交给 Jev
官方 Use Case Map 归纳了五大类用法:
用法 | 人话解释 |
自动化软件里的语义判断 | 代码管流程,Jev 出判断;可后台跑上百万次不用人盯 |
实时应用 | ~150ms 出答案,快到能进游戏和用户界面 |
大数据上的批量判断 | 同一个判断跑一百万次,成本约为大模型调用的百分之一 |
万能校验器 | 查幻觉、查引用是否支撑结论、查越狱与违规话术 |
给大模型当管家 | 决定哪条请求发给哪个模型;拦住注入与泄露 |
映射到三种原语上,常见的判断形态有这七种:
- 是哪一类?意图 / 主题 / 风险类型 →
Choice
- 有没有?垃圾 / 欺诈 / 紧迫 / 敏感信息 →
Noul
- 打几分?严重度 / 相关性 / 质量 →
Score
- 该走哪条路?工具选择 / 人工升级 / 队列分派 →
Choice+ 代码分支
- 找最相关的?语义搜索 / RAG 上下文 / 排序 → 检索与排序组合
- 核对有没有错?引用支持 / 策略违规 →
Noul逐条校验
- 抽特征或字段?购买意图喂预测模型 / 从文本回填表单 →
Score/Choice
两个边界(别越界)
- 几乎所有场景都该配「不确定就转人工」。法务、理赔、招聘淘汰这类高风险终审,不能全交给它。
- 需要长篇写作或开放推理时,转交大模型。更合理的架构是:Jev 在前面快速定「该走哪条路」,大模型在后面做重活。
八、概率凭什么可信:RLCD 与校准
这是 Jev 最核心的卖点,也是最容易被误用的地方。
校准是什么意思?
这是 Jev 最核心的卖点,也是最容易被误用的地方。
校准是什么意思?
校准是按一组预测来衡量的,不是按单次。
给 0.8 概率的事件,长期发生频率应该接近 80%。它不保证任何单次预测正确。
换成 Jev 官方的表述就是三句话:
- 被赋予
0.2概率的结果,应该大约在20%的情况下发生; - 被赋予
0.8概率的结果,应该大约在80%的情况下发生; - 被赋予
1.0概率的结果,应该在100%的情况下发生。
注意每一句的宾语都是「一组预测」。校准描述的是统计规律,不是对某一条答案的担保。给你0.8的那条,就是有五分之一的可能会错——而且你无从知道错的是哪一条。
这一点怎么强调都不过分:如果你把noul = 0.93理解成「这条判断一定对」,那你后面所有的阈值设计都会建立在一个错误的地基上。
为什么普通 LLM 给不出这个数字
同样是预训练模型改造出来的,三条训练路线追求的东西完全不同:
| 方法 | 全称 | 它优化什么 | 产物 |
|---|---|---|---|
| RLHF | 基于人类反馈的强化学习 | 生成人们更偏好的回答 | 聊天机器人 |
| RLVR | 可验证奖励的强化学习 | 能做对可验证的题目(数学、代码) | 推理模型,更慢更贵 |
| RLCD | 面向校准决策的强化学习 | 返回决策 + 校准的概率 | Jev 这类决策模型 |
RLHF 的问题不在于它不好,而在于它的目标函数和你要的东西不一致:
RLHF 教模型说人们偏好的话。这个目标对聊天机器人很有效,但它也可能奖励谄媚行为和听起来自信的幻觉。
偏好优化还会带来模式丢弃(mode dropping):模型学会偏好某种特定风格(比如「听话、有礼貌、给出确定结论」),同时把其他可能输出的概率压下去。分布被人为收窄了,剩下的那个概率值自然也就不再对应真实世界的频率。
所以官方文档里有一句非常适合拿来当这一节题眼的话:
一个输出可以对人很有说服力,却不足以可靠地支撑无人值守的自动化。人类偏好和机器可信度是不同的优化目标。
顺带纠正一个常见误解:让 LLM 输出 JSON、加上"confidence": 0.85这个字段,不等于拿到了校准概率。那只是模型「写」出来的一个数字,没有任何训练目标逼着它为这个数字负责。JSON 约束不等于概率校准。
用 20 条数据直观感受一下
下面这组是构造出来的示意数据,不是 API 实测,只用来把概念讲清楚。假设我们对 20 条工单问了同一个是非问题(「客户是否在要求退款?」),并记录下每条的预测概率和真实结果(1= 是,0= 否):
# (预测概率, 实际结果) 0.97→1 0.94→1 0.92→1 0.91→1 # 高分区:4 条全中 0.88→1 0.84→1 0.81→1 0.76→1 0.71→0 # 有一条翻车 0.66→1 0.61→1 0.57→0 0.48→1 0.43→0 0.38→0 0.33→0 # 0.48 这条猜错了方向 0.22→0 0.15→0 0.09→0 0.04→0把 20 条按预测概率分桶,再算每桶的实际发生频率:
| 预测概率区间 | 条数 | 实际为「是」 | 实际频率 | 区间平均预测值 |
|---|---|---|---|---|
| 0.9 – 1.0 | 4 | 4 | 100% | 0.94 |
| 0.7 – 0.9 | 5 | 4 | 80% | 0.80 |
| 0.5 – 0.7 | 3 | 2 | 67% | 0.61 |
| 0.3 – 0.5 | 4 | 1 | 25% | 0.41 |
| 0.0 – 0.3 | 4 | 0 | 0% | 0.13 |
| 合计 | 20 | 11 | 55% | 0.59 |
看这张表要抓三个点:
- 每一桶里,「平均预测值」和「实际频率」都挨得很近。0.9 以上那桶预测 0.94、实际 100%;0.7–0.9 那桶预测 0.80、实际 80%。这就是校准的样子——预测值越高,实际发生的比例也越高,而且数值对得上。
- 单次预测确实会错。
0.71那条判成了「是」其实是「否」,0.48那条判成了「否」其实是「是」。校准从不承诺这两条不错,它承诺的是:当你把 20 条作为一个整体看时,账能对上。 - 但 20 条还远远不够。整体平均预测 0.59、实际 55%,差了 4 个百分点——样本太少,这个残差到底是模型失准还是抽样噪声,说不清。官方对此的说法很明确:
人工小样本只帮助理解概念,不足以评估模型校准。
想真的下定论,经验上是每个分桶里至少几十条、总量几百到上千条带标签数据,才谈得上算 ECE(期望校准误差)。
校准带来的三条实用推论
如果概率是校准的,那它就不只是一个「看着挺有道理」的数字,而是可以直接参与计算的东西:
- 阈值等价于错误率预算。把自动执行的门槛设在 0.8,等价于「我接受这一类判断里约 20% 会漏掉」。阈值不再是拍脑袋的魔法数字,而是你对错误率的定价。
- 概率可以直接当特征。把多个原子问题的概率喂给一个下游的经典 ML 模型(逻辑回归、GBDT 都行),让模型学出最优组合权重——这是官方 AutoResearch 那篇实战的思路。前提是这些输入是校准的,否则下游模型学到的也是一堆噪声。
- 概率之间可以比较大小。重排序那篇实战能直接用
noul给 30 个候选排序,就是因为在同一个问题、同一把criteria尺子下,不同候选的概率是可比的。
三个最常见的误用
| 误用 | 为什么错 | 正确做法 |
|---|---|---|
把0.93当「这条一定对」 | 它意味着同类型判断里约 7% 会错 | 高概率只降低风险,不消除风险;涉及授权、付款、安全校验的流程照旧走 |
| 直接抄别人的校准结论 | 校准在分布内成立,换领域、换语言就失效 | 中文场景尤其要自己测——官方明确说英语准确率最高,其他语言效果不一,路由时要盯住 confidence |
| 用 20 条就宣布「我验证过校准了」 | 小样本只能讲概念,不能下结论 | 准备几百条带标签数据,分桶后画 reliability diagram、算 ECE |
想自己验证,最小步骤是这五步
- 攒一批带真实标签的数据(建议 200 条起,越难的问题需要越多);
- 跑一遍你的
Noul/Choice问题,记录每条的(预测概率, 真实标签); - 按 0.1 的间隔分桶,每桶算「平均预测值」和「实际发生频率」;
- 画 reliability diagram——横轴平均预测值、纵轴实际频率,点落在对角线上就是完美校准,偏离的加权平均就是 ECE;
- 在自己的这条曲线上定阈值,而不要抄文档或别人文章里的 0.5 / 0.7 / 0.9。
最后回到这一节的标题:概率凭什么可信?凭的不是模型的自信语气,凭的是 RLCD 把「说出来的概率必须对得上真实频率」写进了训练目标。而这份可信是有边界的——它只对你测过的那个分布负责。
两个组都「准」,但组内单次照样会错。
工程上的正确用法
- ✅ 用概率做群体决策:路由、排序、抽检、批量分流
- ❌ 用概率做单点高风险动作的唯依据——该交给阈值 + 人工复核
一句话:校准好 ≠ 单次必对。
九、社区实测数据(来自 jev-cookbook)
以下数字来自 datawhalechina/jev-cookbook 收录的实验报告,供选型参考:
JevBench v1.2(242 个类型化决策的公开基准)
- Jev 1.13.0 综合智能分榜首:75.4
- 答案可解析率 100%(这一点对工程化太重要了)
- 路由任务:74.1%
- 中位延迟:0.65 ~ 0.72 秒
- 每千次决策成本:约$0.04
稳定性:同一套题隔 16 分钟跑两遍,仅1.2%的答案变化。这说明端点不是完全确定性的——读 benchmark 表格时,约 1 个百分点的差距应视为噪声。
能替代 Rerank 吗(80 条 SciFact 查询精排对照)
- 相对不做精排,Jev 的 nDCG@10 提升+0.0778
- 比传统精排还高+0.0332
- 精排耗时与 token 用量显著更低
结论:固定候选集上的语义重排,是 Jev 的甜点区。
速度与价格量级
- 输入:$0.042 / 百万 token
- 输出免费(因为输出就那么几个数)
便宜到什么程度?——可以「投机式地多问」:把不确定用不用得上的问题都塞进同一次调用,反正几乎不增加延迟和成本,代码端再决定用不用。
一个典型生产案例是智能家居场景:一次调用捆绑 10 个问题(意图、是否复合、范围、房间、设备类别 + 五类设备动作预判),代码端剪枝无关分支。这就是「投机式多问 + 原子组合」的完整实战。
十、实战:赛事指挥台(模型管语义,代码管规则)
来个完整的中文场景。假设一次夜跑赛事收到三条现场消息,我们要做自动分流。
10.1 定义状态与问题
先定义好状态(state)和三个原子问题(questions)。状态就是三条现场消息的原文,问题则拆成三个互不重叠的原子判断:
state = [ "补给站 3 号点的水快用完了,还有 200 人没跑完,请求尽快补货。", "5 公里处有一位选手扭伤了脚踝,无法继续跑,需要医疗支援。", "完赛包领取处有人问奖牌什么时候发,能不能提前领?" ] questions = [ { "key": "urgency", "type": "score", "criteria": [ "0:常规咨询,可稍后处理", "1:需要尽快处理,但不危及安全", "2:紧急,涉及人身安全或赛事正常进行" ] }, { "key": "category", "type": "choice", "criteria": { "medical": "需要医疗人员介入", "supply": "需要补给物资调度", "info": "普通信息咨询,可自动回复" } }, { "key": "needs_human", "type": "noul", "criteria": "这条消息是否需要现场负责人或医疗人员人工介入" } ]三个问题分别对应三种原语:Score打紧急度分、Choice分派类别、Noul判断是否要转人工。这样拆开问,代码里才能独立地按阈值做分支。
10.2 逐条调用,代码分流
用 Python SDK 一次调用问完三个问题,拿到带概率的结果:
from typesafe_sdk import Jev jev = Jev(api_key="YOUR_API_KEY") results = [] for msg in state: resp = jev.ask( state=msg, questions=questions ) results.append(resp) for i, r in enumerate(results): print(f"消息 {i+1}:") print(f" 紧急度 = {r['urgency'].score:.2f}") print(f" 类别 = {r['category'].choice} (概率: {r['category'].probabilities})") print(f" 转人工 = {r['needs_human'].noul:.2f}") print()输出结果大致如下(示意):
消息 1: 紧急度 = 1.10 类别 = supply (概率: {'supply': 0.92, 'info': 0.05, 'medical': 0.03}) 转人工 = 0.12 消息 2: 紧急度 = 2.85 类别 = medical (概率: {'medical': 0.97, 'supply': 0.02, 'info': 0.01}) 转人工 = 0.96 消息 3: 紧急度 = 0.20 类别 = info (概率: {'info': 0.99, 'supply': 0.01, 'medical': 0.00}) 转人工 = 0.03最后,用代码根据概率做分流决策。规则很简单:紧急度超过阈值或转人工概率高就升级,否则按类别自动处理:
URGENCY_HIGH = 2.0 # 紧急度阈值 HUMAN_THRESHOLD = 0.8 # 转人工概率阈值 def dispatch(r): urgency = r["urgency"].score category = r["category"].choice needs_human = r["needs_human"].noul if urgency >= URGENCY_HIGH or needs_human >= HUMAN_THRESHOLD: return "转人工", "现场负责人 / 医疗人员" if category == "supply": return "自动派单", "补给组(优先处理)" if category == "info": return "自动回复", "赛事 FAQ 机器人" return "转人工", "现场负责人" for i, r in enumerate(results): action, target = dispatch(r) print(f"消息 {i+1} → {action}:{target}")运行结果:
消息 1 → 自动派单:补给组(优先处理) 消息 2 → 转人工:现场负责人 / 医疗人员 消息 3 → 自动回复:赛事 FAQ 机器人这就是「模型管语义,代码管规则」的完整落地:Jev 只负责把每条消息翻译成带概率的原子判断,至于阈值怎么定、走哪个分支、要不要转人工,全部由代码里的规则决定。优先级变了,只改URGENCY_HIGH或HUMAN_THRESHOLD这两个常数,不用改提示词、不用重跑评测。