手搓代码:实现火爆全网的 Jev 背后原理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
最近在 AI 与大模型工程圈里,一个名为 Jev 的新概念引发了极大的关注。
在当下满大街都在卷聊天助手、长篇思维链和反思型“AI Agent”的时候,TypeSafe 团队推出的 Jev 却反其道而行之:它不负责陪聊,也不跑冗长缓慢的多轮推理,而是宣称以 百倍以上的速度和成本优势,专门对各类复杂的非结构化材料做单步、确定性的结构化裁决与打分。
Jev 为什么能做到又快又稳?它背后的底层支柱,正是认知科学中著名的 System One(系统 1 直觉与模式识别) 架构。
诺贝尔经济学奖得主丹尼尔·卡尼曼在《思考,快与慢》中指出,人类心智包含两套系统: - 系统 1(System One):快速、直觉、擅长感知与模式识别; - 系统 2(System Two):慢速、严谨、负责逻辑推理与规则运算。
当前很多大模型应用之所以在严肃业务中频频“翻车”,根本原因在于让大模型同时兼任了系统 1 和系统 2——既让它做直觉判断,又让它在自然语言里自己做规划、自己决定业务流程的下一步去哪。结果导致整个系统的控制流彻底黑盒化,模型即使答错了,往往也能写出一段看似天衣无缝的自信狡辩。
而 Jev 背后的 System One 架构做了一次彻底的解耦重构:
真正棘手的问题从来不是“AI 能不能给出一个答案”,而是:
官方的 Jev 目前还在内测排队中,且是一套商业闭源 API。这就引申出了本文的核心探索:如果我们不依赖官方 API,能不能借用 Jev 背后这套高明的 System One 架构思想,用本地现有的开源模型(如 Qwen、本地 Ollama 或安全代理)和几行干净的代码,在自己的材料上亲手搭出一道能精准拦错的安全门?
本文正是这次硬核折腾的全程记录。我们不回避理论,也不会一上来堆公式,而是按照“直觉 → 理论 → 代码 → 实验”的脉络,带你一步步手搓实现一个完全自主可控的 System One 决策引擎。读完后,你应该能够回答:
先看一个常见写法:
这段代码把模型的一次回答直接变成了流程动作。问题在于,它没有给“不确定”留下位置。
更稳妥的写法是:
两段代码的区别不在于 AI 更聪明了,而在于系统增加了一道安全门。
《思考,快与慢》常用“系统 1”和“系统 2”解释人的两类思维:
这里借用的不是完整心理学模型,而是它的分工思想:不要要求同一个模型既做直觉判断,又自行决定是否值得信任。
普通程序不擅长理解复杂文字,但非常擅长执行明确规则。AI 恰好相反。System One 的工程价值,就是把两者放到各自擅长的位置。
整个流程可以压缩为四步:
后面所有概念和代码,都是在完善这四步。
这里必须先分清两层:
专用决策模型可以在训练阶段专门优化“概率是否诚实”。相关方法常被概括为 RLCD(Reinforcement Learning for Calibrated Decisions,即面向校准决策的强化学习)。它追求的不只是选对答案,还包括:模型报出 80% 时,长期正确率也应接近 80%。
本文没有复现这种训练过程。Self-Consistency 只是利用普通模型在多次采样中的分歧,构造一个可以实验的替代指标。因此,本文会保留概率校准理论,但不会把“一致程度”冒充成原生模型的校准概率。
特别注意:Jev 的“一次调用回答多道问题”和本文的“同一道题调用 5 次”不是同一种并行。
因此,本文后面统一使用 agreement 和 vote_margin 描述本地采样。只有讨论 Jev 原生响应时,才使用 confidence。
普通 if 擅长判断代码能直接计算的条件:
但“这条消息是在询问账单,还是报告故障”并不是简单数值条件。Jev 的位置,就是先把这种语义判断转换成类型化结果,再让普通代码继续执行 if/else。
它不是聊天机器人,也不负责写回复、调用工具或持续运行一个任务循环。它只是软件内部的一个决策部件。这个定位比“更快的小语言模型”更准确。
下面是 Jev 原生接口的最小请求形状。数字和输出仅用于说明结构;能否调用以及实际模型版本以服务端为准。
返回结构类似:
这里有三个关键观察:
Jev 接入现有流程时,应直接读取原生字段;本文的 Self-Consistency 则是没有 Jev 能力时用于学习和实验的替代路线。接口形状和问题设计原则可参考 Flavio Copes 的 Jev 深度介绍。
下面的代码是按教学顺序逐步搭建的最小版本。为了不覆盖仓库中的完整实现,建议先创建一个练习目录:
后面出现“创建某文件”时,都在这个目录中操作。这样可以一边运行教学代码,一边对照仓库中的正式实现。
直接问“这份材料应该怎么办”,往往得不到稳定、可比较的结果。这个问题混合了多个维度:材料属于什么类型、风险多高、是否缺少信息、接下来采取什么动作。
System One 的第一条重要思想是:先把大问题拆成单一、边界清楚的小问题。
Choice 适合互斥的分类问题:
从概率角度看,Choice 对应一个分类分布:
如果结果是:
答案是 billing,但我们还知道其他选项并非完全没有可能。
Score 适合“低、中、高”这类有先后顺序的问题:
它与 Choice 的区别是:Choice 的类别通常没有大小关系,而 Score 的相邻等级比跨级更接近。把“低”误判成“中”,通常比误判成“高”偏差小。
Jev 原生 Score 还可能返回位于两个等级之间的连续位置,例如 1.9,并同时给出各等级的概率。这个数适合排序或与阈值比较,但不能解释成“现实属性精确处在 90% 的位置”。Score 是有序判断,不是测量仪器。
Noul 是二值问题:
理论上只需要一个数:
如果 p_yes = 0.52,虽然“是”略占上风,但它离完全拿不准的 0.50 很近。这与 p_yes = 0.95 显然不是一回事。
写 Noul 时应尽量让高值始终表示“是”。例如,“消息是否明确表达紧急性”比“消息是否不紧急”更容易阅读和维护。p_yes = 0.50 表示模型难以区分是与否,不表示某种属性处于“中等程度”;要表达程度,应改用 Score。
边界较模糊时,可以为 true 和 false 增加具体标准:
现在创建 primitives.py:
这段代码没有任何 AI 魔法,只是在明确数据结构:
创建 business_rules.py:
把题目定义集中放在一个文件里有两个好处:
这里体现了第一个理论落地点:问题的类型和含义由人预先定义,模型只在这个边界内回答。
还有一个容易忽略的细节:问题 ID 主要供程序取值,不能代替完整问题。即使键名叫 is_urgent,也应在 instructions 中把判断条件写完整,因为模型真正需要理解的是问题正文和标准。
假设一个天气应用连续很多天都说“今天有 80% 的概率下雨”。如果长期统计后,这些天中大约有 80% 真的下雨,我们会说这个概率比较诚实。
这就是概率校准的直觉:
用数学写法表示:
不熟悉公式也没关系,它只是说:在所有自称“把握为 p”的答案中,正确比例应该接近 p。
设想两个模型都答对了 80 道题:
它们的准确率相同,但模型 B 的不确定性信息更有用,因为我们可以优先复核它认为困难的题。
所以要区分两个能力:
System One 的分流价值依赖第二种能力。如果错题和对题一样自信,阈值闸门就无法挑出风险样本。
预期校准误差(Expected Calibration Error,ECE)是一种常见指标。它把预测按置信度分组,再比较每组的平均置信度和实际正确率:
逐项翻译:
本文的小样本实验不适合精细估计 ECE,但理解它有助于避免一个误区:置信度不是装饰字段,而是一项需要用历史结果验证的预测。
最简单的做法,是让普通语言模型返回:
这叫 Verbalized Probability,可以理解为“让模型用文字报出一个概率”。
问题在于,语言模型生成 0.85 的方式,与生成“我很确定”本质相似:它是在预测什么文本接在后面最合适,而不一定是在读取一个经过校准的内部概率。
在 13 条已有人工作答的数据上,单次回答自报的置信度如下:
差距只有 0.030。错题几乎和对题一样自信。
这意味着:即使我们设置一个看起来很严格的阈值,也未必能有效拦住错题。
先用一组极小的数据理解这个指标:
这里的 gap 不是严格的概率校准指标,而是一个直观的资格测试:
这一步的理论意义是:在扫描阈值之前,先验证置信度是否具备最基本的排序能力。
既然不能轻易相信模型自报的数字,我们换一个可以直接观察的量:同一个问题多问几次,答案是否一致。
这种方法叫 Self-Consistency,即自洽性采样。
创建 votes_demo.py:
运行:
你会看到:
到这里,我们已经写出了整个系统最核心的统计逻辑。
本文把最高票占比记作:
5 票中有 3 票选择 billing,所以:
agreement 的中文是“一致程度”。它不应被解释成“答案有 60% 的概率正确”,更不能与 Jev 原生返回的 confidence 混用。
只看第一名占比有时不够。vote_margin 衡量第一名领先第二名多少:
在 3 比 2 的例子中:
如果有五个选项,第一名 0.40、第二名 0.20,虽然 agreement 不高,但第一名的相对优势仍比 0.40 对 0.35 明显。两个指标放在一起,能更完整地描述分歧形状。
如果模型每次都采用完全确定的生成方式,它可能机械地返回相同答案,我们就观察不到它在邻近答案之间的摇摆。
因此实验把 temperature 设为 0.7,让每次采样保留适度随机性:
0.7 只是本次实验设置,不是普遍最优值。
Self-Consistency 测量的是:在给定采样设置下,模型的答案有多稳定。
它不能保证:
模型可能稳定地犯同一个错误。因此,自洽性是一个工程近似,不是真正经过训练和验证的校准概率。
现在把手工准备的 votes 换成真实模型返回的结果。
项目中的 engine.py 使用兼容 Chat Completions 的 HTTP 接口。下面按功能拆开来看。
这三个值分别表示服务地址、访问密钥和模型名。请根据自己的环境修改,不要照抄密钥。
这段解析代码体现了“有类型问题”的价值:有效答案只能来自 valid_keys。模型写了很多解释也没关系,程序最终只接收预先定义的选项。
有些服务不支持 n=5,这时可以循环请求 5 次。无论使用哪种方式,都要确认返回的确是独立采样,而不是把同一结果复制 5 份。
这里故意采用保守策略:只要有效答案不足 5 个,就不伪造默认票数,而是返回错误,让后面的安全门转人工。
这是一个很重要的工程原则:解析失败也是不确定性,不能被隐藏。
模型完成计票后,它的工作就结束了。接下来由 router.py 执行固定规则。
输出:
这里要特别注意:
Noul 只有一个 p_yes。当它接近 0.5 时最不确定,接近 0 或 1 时更确定。因此可以定义:
代入几个值:
对应代码:
这个公式说明了为什么不能简单写成 p_yes >= 0.8 才可信:p_yes = 0.05 虽然很小,但对“否”的判断其实很确定。
现在创建 run_demo.py,把题目、模型和安全门连起来。
准备 cases_sample.json:
运行:
你应该重点观察三件事:
不要急着追求高准确率。先确认数据流完整、失败会被看见、安全门确实生效。
能运行不等于有效。下一步要准备人工确认的参考答案,例如 truth.json:
创建 analyse_gap.py:
把阈值设为 1.00,通常能让自动处理集合更准确,但可能只放过极少样本。反过来,把阈值降得很低,覆盖率提高了,错题也可能一起混进来。
因此至少要同时看:
不存在脱离业务代价的“最佳阈值”。阈值越严格,通常越安全,但人工工作量也越大。
如果参考答案本身是用简单关键词或另一个未经验证的模型生成的,那么整个评估会建立在错误地基上。
参考答案至少应包含:
理论上再漂亮的指标,也无法修复错误的参考答案。
本项目在 13 条人工确认的历史样本上做过一次小规模实验。
分类任务答对 11 条:
这叫裸准确率:不考虑是否转人工,只看模型最终选项是否正确。
差距太小,说明错题没有明显表现得更不确定。
对错差距从 +0.030 增加到 +0.182,约为原来的 6 倍。这表明在这批样本上,多次采样的一致程度比模型自报数字更有排序价值。
设置阈值后,12 条样本进入自动通道,其中 11 条正确:
但模型裸准确率仍然是:
这两个数字并不矛盾。安全门没有让模型突然多答对一道题,而是把一个不稳定样本留给了人。
这叫“选择性预测”或“带拒答的分类”:系统允许自己在部分样本上不自动作答,从而提高剩余样本的可靠性。
13 条样本太少,因此不能据此宣称:
它只说明:在这次小样本实验中,这条方向值得继续用更多数据验证。
类型化输出只能保证答案形状正确,不能保证业务含义正确。实际效果很大程度取决于问题是否写得清楚。
好问题:
坏问题:
后者把紧急程度、原因和处置动作混在了一起。正确做法是拆成独立问题,再由代码组合结果。
模型回答的是实际写下的问题,不是作者心里想的问题。看到错误结果时,如果必须补一句“我的真正意思是……”,这句话通常就应该进入 instructions 或 criteria。
应特别避免:
只要选项不能保证覆盖所有输入,就加入:
提取信息时,如果原文可能没有提供答案,应加入 not_stated。否则模型被迫从错误选项中挑一个,结构虽然合法,含义却可能错误。
不够清楚:
更清楚:
如果相邻等级仍容易混淆,可以为每一级增加相同结构的说明和贴近真实输入的例子。例子应帮助模型理解边界,而不是堆砌无关背景。
Jev 和普通语言模型都不应代替计算器。以下任务优先用代码:
如果需要统计“哪些条目符合某个语义条件”,可以让模型对每个条目分别回答 Noul,然后由代码计数。
大量无关文本会降低语义判断质量。能用确定性方法过滤时,先由代码过滤;无法直接过滤时,可以先按文本块询问“这一块是否与目标问题相关”,再把相关部分送入真正的判断题。
决策模型适合“从牌堆中选一张牌”,不适合“凭空说出一张牌”。
如果任务看起来是“提取某个值”,可先通过规则或生成模型找出候选值,再让 Choice 选择正确候选。需要写回复、总结文章或生成代码时,仍应使用生成模型。
一次可复现的决策至少要记录:
只要模型、instructions、criteria 或阈值中任何一项发生变化,都应重新回放代表性样本。对版本别名完成标定后,也不应在没有回归测试的情况下自动切换到新版本。
输入文本是数据,但其中可能包含试图改变模型行为的句子。类型约束只能防止返回范围外的值,不能保证模型不会被诱导而选择错误的合法选项。
因此,对外部输入至少要:
以上问题设计与失效边界,参考了 Flavio Copes 的 Jev 深度介绍,并结合了本项目的本地实验结果。
模型可能 5 次都犯同一个错误,尤其是在题目带有系统性偏差或缺少关键信息时。
应对方法:始终保留人工真值集,单独统计“高一致但答错”的样本。
5 次采样只能得到 0.2 的票数步长。3 比 2 和 4 比 1 之间相差一票,指标却会从 0.6 跳到 0.8。
应对方法:在成本允许时比较 n=5、n=10、n=20 的稳定性,而不是盲目增加次数。
温度太低可能制造虚假的稳定,太高可能制造无意义的随机分歧。
应对方法:把温度视为实验参数,与模型名、提示词版本一起记录。
如果一道 Choice 同时询问类别、风险和动作,不同采样可能各自抓住不同重点。这时分歧反映的是题目设计失败。
应对方法:把大问题拆成多个正交小问题,每个问题只判断一个维度。
如果 5 次都无法解析,却把默认选项补成 5 票,就会得到虚假的 agreement = 1.0。
应对方法:解析失败必须显式记录,并默认进入 HUMAN_REVIEW。
如果要继续完善,建议按这个顺序推进:
例如,某类占全部样本的 80%,模型准确率也是 80%,可能只是永远猜多数类。
如果错题并不比对题更不确定,就不要继续扫描阈值。
至少绘制或列出:
阈值选择取决于错误代价和人工处理能力,而不是哪个数字看起来更漂亮。
系统上线后仍要保存:
有了这些记录,才能发现数据变化、模型退化和阈值失效。
现在回头看,我们不是从一个复杂框架开始,而是逐步增加能力:
如果只记住三句话,请记住:
这才是 System One 思路真正值得学习的地方:它不是让 AI 包办更多,而是把 AI 放进一个可观察、可验证、可拒答的决策流程中。
前文为了讲清理论,把代码拆成了许多小段。本附录把它们整理成一个完整、相互一致的练习项目。
先创建并进入目录:
这个文件只用于明确说明依赖状态,不会下载第三方包。也可以跳过下面这一步:
这份实现默认发送 5 次独立请求,而不是依赖服务端支持 n=5。这样兼容性更好,也更容易确认每一票确实来自独立采样。
连接信息通过环境变量读取,不把真实密钥写进代码:
示例只使用虚构的通用客户消息:
第四条故意同时包含购买和技术问题,用来观察模型是否出现投票分歧。
case-004 的参考答案是假定“页面打不开应先排除故障”。在真实项目中,这类边界答案必须由负责该流程的人确认,不能直接照搬。
先设置自己的模型连接信息。以下地址和模型名只是示例:
运行完整流程:
程序会生成 predictions.json,其中保留:
即使暂时没有可用的模型服务,也可以验证计票和安全门:
这组投票是 3 比 2,因此一致程度为 0.60、领先幅度为 0.20,最终应进入 HUMAN_REVIEW。先确认这个结果,再连接真实模型,排错会容易得多。
下面是本机 Python 3.14 虚拟环境中的一次真实运行。模型对每条消息独立回答 5 次,4 条样本的 5 次结果全部一致。
本次耗时约 1 分 17 秒,输出如下:
这次运行可以确认三件事:
按照修正后的统计脚本,输出为:
这里的 100% 只能说明:这 4 条教学样本在本次运行中全部答对。
它不能证明模型在真实任务中也有 100% 的准确率,更不能证明当前阈值已经完成标定。因为本次没有出现错题,所以无法比较“答对样本”和“答错样本”的一致程度,Gap 也就没有统计意义。
这组结果的价值是验证代码链路,而不是证明模型能力。要检验安全门能否真正识别疑难项,下一步需要:
也就是说,4 条样本完成的是“冒烟测试”;真正的置信度标定,才是下一阶段的工作。