从淘小蜜分流模型的实践,聊聊 Jev 与 System One
原创 吴双 2026-11-10 18:01 浙江

关于最近大火的 Jev,本文或许能够提供一些技术实践参考

这是2026年的第 79 篇文章
( 本文阅读时间:约 30 分钟 )
前言
最近 Jev 很火,技术社区里也出现了不少复现项目。看完相关文档和项目后,我发现团队去年做的淘小蜜客服 Agent 分流模型和 Jev 要解决的问题有一些相似之处,技术方案上也存在可以互相验证的地方。
本文的初稿其实在去年九月份就已经写好了,当时的内容主要是总结淘小蜜分流模型的数据构建、训练和部署经验;最近分流模型又做了一轮优化,在线上部署和评测时踩了四五天坑,再加上 Jev 发布后大家都在猜它的实现方式,所以重新把之前的内容整理了一番。
先说明,Jev 没有公开模型结构和具体训练方法。本文对 Jev 的介绍以 TypeSafe 官方文档为准,对模型结构的讨论主要参考 SemIf、open-bonsai-jev、AlexWortega/openjev 等社区项目;社区项目只能说明某种方案可以实现类似能力,不能说明 Jev 内部一定采用了相同方案。
01
背景
淘小蜜客服 Agent 在回答用户问题前需要先判断应由哪个 Agent 承接,当前的分流模型主要把用户问题分成售前、售后、其他问题、意图不清四类,再根据分类结果路由到不同的 Agent。
这个任务表面上是一个普通四分类,实际做起来却没有那么简单。售前和售后的标准不是按照通用语义划分,而是按照不同 Agent 的能力边界划分。例如订单评价、取消订单、价保、退款后的优惠券和红包等问题属于售前。“退差价”也不能见词就判:因质量不符、重量不足、少件、描述不符等商家责任要求退差价,属于售后;没有这些商家责任原因的退差价,属于售前。猫超、国际、百补、小时达、闪购等自营场景的问题,如果超出当前 Agent 的承接范围,又可能归为其他问题。这些规则带有较强的业务属性,和通用大模型在预训练阶段学到的常识并不完全一致。
在分流模型的迭代过程中,主要经历三个阶段。
第一阶段是使用通用 LLM 做 ICL few-shot 分类。
具体做法是在 prompt 中描述分类规则,再放入一些示例,让模型直接输出分类标签。这种方案开发比较快,前期效果也能满足基本需求,但是存在几个问题:
大模型调用成本较高,响应速度较慢,大促高峰期还有系统稳定性的问题。
业务规则和通用常识冲突时,仅调整 prompt 很难完全纠正模型。
对于退款权益、红包、退差价等边界 case,继续增加 few-shot 的收益逐渐变小。
第二阶段是对 7B 模型做 SFT。
这一阶段用约 2.1 万条数据做 SFT,把业务知识教给 7B 模型,解决了部分通用模型不了解业务规则的问题。问题是标签直接写成“售前/售后”,输入格式、输出词和标签比例也长期固定。对只有几种分类的训练任务,模型很容易把训练集里的词和标签记成捷径,而没有真正学会判断条件。例如看见“红包”就倾向售前,但体验赔付红包可能属于售后;看见“退差价”就倾向售后,又会错过没有商家责任原因的售前 case。继续增加类似训练样本,线上没见过的用户 query 也未必能分对,这正是当时遇到的泛化问题。它不能简单归因于模型参数量大;数据分布、标签噪声和训练目标都在起作用。
另一个问题是训练数据天然不均衡。早期二分类数据的售前、售后比例约为 3:7,扩展成四分类后,售前、售后、其他问题和意图不清也不是等量的。标签直出时,这种分布直接反映到输出词上,模型容易形成“更常回答售后”的先验。后面我们把业务标签随机映射到字母,让同一个标签在不同样本中对应不同字母,正确答案的字母分布就能在统计上接近均衡。这里平衡的是输出 token 的分布,业务样本本身仍然不均衡;随机映射的有限样本也不保证每个字母数量完全相同,需要检查实际分布。
第三阶段是把分类改成选择题。
训练数据不再要求模型生成“售前”“售后”等标签,而是给每个标签分配一个选项字母,让模型学习预测正确字母。线上只做一次前向计算,读取候选字母 token 的 logits,取最大值对应的选项并映射回业务标签;实际生成出的答案文本不参与判定。输出由候选表控制,因此不会返回候选表之外的标签或一段解释。这和 Jev 所说的“不产生幻觉”有相似之处:解决的是输出越界,模型仍然可能选错候选项。

从任务形式来看,这类模型更接近一个带语义理解能力的决策函数:输入是一段对话和分类标准,输出是有限候选中的一个结果,以及每个候选对应的分数。模型不需要生成完整回答,也不需要解释推理过程。
分类模型本身并不是新的方向。BERT 一类编码器通常在预训练模型上增加输出层,再针对分类、自然语言推断等任务做微调。编码器一次读完整段输入,在固定标签任务上通常更省推理资源,后面会聊到的 Laya 就采用了这条路线。[9] 生成式 LLM 则成为 Agent 的常用底座,同一个模型可以通过 prompt 处理问答、生成、推理和工具调用,并直接读入新的业务规则。但是在 Agent 系统中,仍然存在大量只需要返回有限结果的高频判断,例如分流、打分、守卫、模型路由和是否重试。对于这类任务,生成能力并不是必需能力。
TypeSafe 把这类任务定义为 System One 任务:给定足够的信息后,可以在很短时间内完成的聚焦判断。对于复杂任务,官方建议拆成多个独立问题,再通过代码组合结果。[1] 这个定义和分流模型实际解决的问题比较接近。
02
谈谈 Jev
TypeSafe 在 2026 年 9 月 15 日发布了 Jev,并把它定义为首个 System One Model。Jev 接收文本或结构化状态,输出带类型的概率决策。官方公开的信息包括新的模型架构、并行 sampler,以及一套名为 RLCD(Reinforcement Learning for Calibrated Decisions)的训练方法,但是没有公布网络结构、参数量和训练数据等细节。[2]
官方给出的端到端响应时间是 70ms—500ms,并宣称在 System One 类型任务上,相比同等智能水平的 LLM 可以快 40—200 倍。TypeSafe 同时说明,部分演示使用了较短、信息密度较高的输入,对 Jev 相对有利;官网中 193.6 倍速度和 444.6 倍成本的数据来自收益较高的一组工作流,不能直接当成所有任务的通用结果。[1]
关于 Jev 的三种输出类型。
Jev 当前提供 Choice、Score 和 Noul 三种问题类型。三种类型不是同一份返回结构换一个名字,字段也不完全相同。[1]
类型 | 用途 | 返回字段 |
Choice | 从多个无序候选中选择一个 |
|
Score | 在多个有序等级上进行评分 |
|
Noul | 判断一个命题为真的概率 |
|
Choice 最多支持 255 个选项。如果分类体系超过这个数量,官方文档建议使用分层分类。一次请求中还可以针对同一个 state 提出多个问题,不同问题相互独立,并行返回结果。[1][3]
从接口设计上看,Choice 和我们的分流模型最接近,都是给出运行时候选并返回候选分数。Score 更适合严重程度、用户情绪等有序等级。Noul 则可以理解成一个二分类概率,例如“用户是否在申请退款”。
从返回字段继续往下看,这三种输出其实都可以从候选 logits 计算出来。假设模型能够为每个选项或等级输出一个 logit,经过 softmax 得到概率分布后,Choice 取概率最大的选项作为 choice;Score 对各等级编号和对应概率做加权求和,官方文档中的示例就是 0 × 0.0 + 1 × 0.57 + 2 × 0.43 = 1.43;Noul 只有“是”和“否”两个结果,所以返回“是”的概率即可。Noul 也可以写成两个 logits 的 softmax,或者等价地对两个 logits 的差做 sigmoid。[1][8]
类型 | 如果从 logits 还原 | 其他字段 |
Choice |
|
|
Score |
|
|
Noul |
| 二元概率已经能完整表示结果,因此没有单独的 |
TypeSafe 没有公开 confidence 的具体计算公式,只说明它由 probabilities 的分布形态计算,分布越集中,confidence 越高。[8] 因此,三种输出的核心数值都可以从 logits 出发计算,但还不能逐字段复现 Jev 的返回结果:legend 是调用方传入的元数据,两个 confidence 也缺少公开公式。这个结论同样不能说明 Jev 底层使用的是普通字母 token、special token,还是独立的分类 head。
关于Jev 所说的“不产生幻觉”。
TypeSafe 在发布文章中强调 Jev 不生成字符串,因此不会发生类型错误,也不会返回定义范围以外的值。[2] 这里的“不产生幻觉”主要指输出结构和取值范围,而不是模型在语义判断上一定正确。
例如 Choice 的候选只有售前和售后,Jev 一定会返回其中一个,不会突然返回一段解释或一个不存在的标签。但是它仍然可能把售前判断成售后。open-bonsai-jev 的实验中也存在模型以 0.998 的置信度给出错误答案的情况。[5] 因此类型安全解决的是结果能不能直接被代码使用,准确率和概率是否可信仍然需要单独评测。
关于「为什么大家都在用 Jev 玩游戏和做 Computer Use」。
TypeSafe 官方展示了 Doom 和 Wikiracing。Doom 演示中模型每秒需要做多次动作判断,输入是结构化的文本状态,不是直接读取游戏画面;Wikiracing 则需要在每一步从页面链接中选择下一跳。[2]
游戏和 Computer Use 比较适合展示 Jev,主要有几个原因:
动作空间通常是有限的,可以直接转成 Choice。
每一步都需要快速响应,LLM 生成带来的延迟比较明显。
多步任务中,单步错误会逐渐累积,更容易观察模型的实际决策效果。
游戏和浏览器操作可以录成视频,传播效果也比较好。
这些领域不一定是 Jev 最有价值的商业场景,但比较容易展示高速决策相对于普通 LLM 的差异。TypeSafe 在 Use Case Map 中给出的实际方向还包括模型路由、LLM guardrail、搜索排序、客服分流、风险判断和大规模数据处理等。[7]
社区对 Jev 实现方式的猜测。
目前社区项目采用的方案主要可以分为两类。
第一类是直接读取生成模型候选 token 的 logits,SemIf 和 open-bonsai-jev 都属于这一类。
SemIf 不训练新模型,而是使用冻结的普通开源模型,把 state、问题和选项拼成 prompt,然后直接读取候选选项的 logits,不生成答案文本。SemIf 使用同一个冻结的 Qwen3.5-4B,在 RTX 3090 上测试同一 state 下的 21 个二元问题,直接读取 logits 的中位耗时为 1.023 秒,生成一个精简 JSON 数组的中位耗时为 5.332 秒。另一个 37 个 state、每个 state 包含 21 个 criterion 的实验中,共有 777 个判断。逐条执行需要 333.1 秒,使用 shared prefix 和 parallel suffix 后降低到 38.8 秒。[4]
open-bonsai-jev 使用的核心方案和 SemIf 基本相同。项目自己的说明是“SemIf direct 模式的独立重实现”,使用了不同的 prompt,也没有直接复用 SemIf 的代码。它同样使用普通的 A、B 等字母作为选项 token,关闭 thinking,让 assistant 的下一个 token 对应答案字母,再对候选字母的 next-token logits 做 softmax。[5]
两者的主要差异不在打分方式,而在模型和项目目标上。SemIf 更偏向一套完整的实验实现,包含普通 Qwen 模型、shared prefix、parallel suffix、多种推理后端和评测工具;open-bonsai-jev 则把相同机制应用到 PrismML 的 Bonsai 低比特模型上,重点验证 27B 模型能否以 5.95GB 的文件在本地设备上运行。由于两边使用的模型、prompt、硬件和推理环境不同,实验数字不能直接横向比较。[4][5]
第二类是把生成模型改造成判别式分类模型,AlexWortega/openjev 属于这一类。这个项目对 Qwen3.5 做 NLI 后训练,使用最后一个 token 的 hidden state 接分类 head,输出 entailment、contradiction、neutral 三类概率,并使用普通交叉熵训练。做多选题时,可以把每个候选改写成一个 hypothesis,再按照 entailment 分数排序。[6]
Laya:另一条编码器路线。
Laya 也支持 Choice、Score、Noul,不过底座换成了 ModernBERT-large 或多语言 mmBERT,再接一个针对选项打分的 decision head。它不做自回归生成。项目在 T4 上报告单问题约 33—40ms,模型和测量条件都与 Jev 的托管 API 不同,这个数字只说明它自己的推理开销。[9]
Laya 的结果也很能说明“通用决策模型”有多难。项目自己的 typed-decisions 测试里,英文基础模型的零样本准确率是 0.362,针对这套任务训练后的 checkpoint 才达到 0.766;同一份报告里,10 类客服工单分流只有约 0.50。作者也明确建议在具体领域继续训练,并指出它的 Jev 对比数字不是同条件实测。[9][10]
其他开发者的复测同样有任务差异。Necati Demir 用公开的仇恨言论数据集测试,原始 Laya 准确率为 22.10%,只训练原有决策 head 后达到 82.75%,但仇恨言论召回从 77.97% 降到 41.43%。另有开发者复现了项目的英语意图 benchmark,换成自己的论文段落和工作笔记后,零样本结果低于简单的 TF-IDF 分类器;他也说明后者使用了任务标注数据,不能当作同条件的模型胜负。[11][12] 这些实验的共同提醒是:响应快和输出格式稳定,并不自动带来新业务上的准确率。
这些项目实现的都是类似 Jev 的决策接口,并不是真正复现了 Jev 的模型结构。目前能看到三种路线:冻结生成模型读取候选 token logits、在生成模型上训练 NLI 分类 head,以及像 Laya 那样用编码器和选项打分 head。实现方式不同,不能用接口相似推断 Jev 的内部结构。
03
淘小蜜分流模型是怎么做的
我们做分流模型,主要围绕训练数据、模型训练、线上推理和 hardcase 回流迭代。真正花时间的地方,除了业务标准和数据质量,还有线上筛选难例、二阶段训练、让不同 epoch 看到不同选项映射,以及保证部署后的候选 logits 与离线评测一致。
历史版本的主要优化。
最早我们采用标签直出的方式,输入历史对话和当前 query,让模型直接生成“售前”或“售后”。用约 2.1 万条数据做 SFT 后,发现模型容易拟合标签比例、关键词和其他浅层特征,没见过的 case 上泛化效果不太好。
V1 把标签直出改成选择题。在 prompt 中明确四类标签定义,为每个标签分配 A、B、C、D 中的一个选项 token,训练目标只保留正确答案对应的单个 token。但是这一版的标签与字母映射、选项顺序都没有 shuffle。售前始终对应同一个字母、出现在同一个位置,业务标签的样本比例也就原样变成了答案字母的比例。除了答案缩短成一个 token,它和标签直出的训练任务基本一致,模型仍然可以依靠固定字母和位置拟合,泛化问题没有解决。
V2 做了两个调整:把可用的选项 token 从 4 个大写字母扩到 26 个,同时 shuffle 标签与字母的映射,以及选项在 prompt 中的顺序。同一个业务标签不再绑定固定字母和位置,各类样本都可以把任意字母作为正确答案,答案 token 的分布也更均衡。只计算标签到四个字母的对应关系,只有 24 种映射;扩展字母池后,模型会看到更多映射,需要结合当次选项内容判断,而不能一直记住“某个词对应 A”。
V3 和 V6 使用 std_sigmoid(logits) 辅助筛选 hardcase 并回流训练。std_sigmoid 会先对单个样本内的候选 logits 做标准化,再执行 sigmoid:
z_i = (logit_i - mean(logits)) / std(logits)score_i = sigmoid(z_i)
我们在线上记录第一名和第二名的分差,从低分差样本中筛选 hardcase,标注后回流训练。直接对候选 logits 做 softmax,在 logit 差距较大时很容易得到接近 0 和 1 的结果,筛选边界样本不太方便。例如四个 logits 是 [10, 0, 0, 0],softmax 第一名约为 0.9999,std_sigmoid 则约为 0.85。标准化后再做 sigmoid,主要看候选在本次选项组内相对高低;它对 logits 整体平移和正比例缩放不敏感。这个处理不会改变候选排序,后面表格中的准确率提升来自数据回流和训练。std_sigmoid 的分数不合计为 1,也会抹掉 logits 整体缩放造成的绝对间距变化,我们把它作为挖掘难例的相对分数使用。[5]
我们还在 V3 上试过多 pattern 投票:对同一个 case 构造多组选项映射,再对结果投票。两组实验的整体准确率分别为 92.42% 和 91.97%,都没有超过单 pattern 的 92.76%,所以当时没有采用。调试时也观察到,同一条“退运费”消息换了几组字母和选项顺序,仍然能正确判为售后;但另一些边界 case 会随映射变化。这说明模型已经能处理部分没见过的映射,稳定性仍然有优化空间。
我们当时在 884 条 benchmark 上得到的单 pattern 结果如下。这组使用的是当时的标签标准和评测口径,和后面这次迭代分别看。
版本 | 主要优化 | Goodcase(685) | Badcase(199) | 整体(884) | 较上一有效版本变化 |
V1 | 四选一,但字母映射和选项顺序均固定 | 72.70% | 69.85% | 72.06% | — |
V2 | 扩展到 26 个字母,shuffle 字母映射和选项顺序 | 97.23% | 69.35% | 90.95% | +18.89pp |
V3 |
| 97.96% | 74.87% | 92.76% | +1.81pp |
V6 | 继续增加 hardcase 训练 | 97.52% | 80.40% | 93.67% | +0.91pp |
V1 到 V2 的提升最大,但不能只归因于选项字母从 4 个变成 26 个。更关键的变化是映射和顺序终于打乱了,固定标签的输出先验和位置捷径被削弱。后续我们主要通过线上筛选 hardcase、标注回流再训练来提升效果,收益更多集中在 Badcase。
我们在 Jev 发布前一年左右,就把这套候选 logits 打分方案用于客服 Agent 的生产分流了。去年 7 月 19 日,旧链路的准确率和召回率分别为 92.02% 和 84.73%;新模型逐步放量,到 9 月 3 日推全时,两项指标分别为 96.17% 和 94.24%。期间我们也修过推理 bug、调整过流量和分流标准,所以这组变化反映的是整套方案迭代的效果。至少对客服分流这个任务,我们已经验证了大模型做分类可以兼顾效果和线上效率。
为什么这里继续用生成模型。
我们当时没有用传统 BERT 分类器,主要由于除了四个标签以外,还需要读对话历史、判断最新消息是否覆盖旧意图,以及理解不断补充的业务边界。常见的 BERT 加固定分类 head 方案,输出维度与训练标签绑定;只改 prompt 加一条新规则,分类边界未必跟着改变。我们更希望复用指令模型读规则和候选描述的能力,也方便用 zero-shot 或 few-shot 快速验证新标准。Laya 说明编码器也能学习运行时候选,但同样要专门训练这个能力。[9]
我们需要的也不只是识别句子里的关键词。比如同样问“退差价”,需要结合前文判断是质量不符,还是普通价差;用户只说“是的”,还要判断他确认的是哪个诉求。选择生成模型,是希望利用它已有的上下文理解和指令遵循能力。我们没有做过同数据、同训练预算的 BERT 对照实验,所以这里更多是方案选择的考虑。
我们用同一句「这物流为啥往回返了?」做了两次调试:先按原来的四分类规则,把发货物流归入售后,模型返回 B,对应 B. 售后;再修改 prompt,把发货物流从售后中单独拆出来,增加 H. 发货物流,模型就返回了 H。两次都没有对话历史,这个 case 展示了模型跟随当前分类标准和候选集合判断的能力,而不是把“物流”固定对应到某个标签。当然,单个 case 不能代表整体泛化效果,新规则仍然需要成组样本验证。
原四分类:物流归入售后,返回 | 新增发货物流类别:返回 |
|
|
因此,我们没有给 7B 底座再接一个四分类 head,而是沿用自回归训练目标,只让它预测正确字母。这样能复用已有的 SFT 训练、Whale 部署和候选 token logits 接口;标签和字母的映射可以每条样本、每个 epoch 改变,推理时也能把新标签描述放进 prompt。固定四维分类 head 如果换了标签含义,需要补充数据重新训练;增减类别时通常还要调整输出层。如果改成逐候选打分或运行时候选 head,又是另一套需要训练和部署的方案。这里只计算一个位置的候选 logits,不生成长答案,自回归底座的额外生成开销很小,但模型参数量仍然是 7B,速度和成本不一定优于专门训练的编码器。[6][9]
线上推理时,Whale 请求只保留当前选项对应的候选 token,并限制模型只生成一个 token:
generate_config= {"return_logits": True,"select_tokens_id": select_tokens_id,"return_output_ids": True,"max_new_tokens": 1,"top_k": 1,}
服务获取候选 token 的 logits 后,取最大值对应的字母,再根据当前请求的选项映射还原成业务标签。
最新一轮优化。
九月底我们针对分流模型做了一次优化,这次我们重新实现了不同 epoch 间的动态映射,并对比固定映射和动态映射的效果。下面的 V4、V5 是本轮迭代使用的版本名。
我们重新检查了 20000+ 条训练样本,修正 24 条高置信度错误标签,另外整理了 7000+ 条 hardcase 用于 Stage 2 训练。评测仍使用 600+ 条 Goodcase 和近 200 条历史 Badcase,再加上 20 条最新专项 badcase。
每条训练数据包含对话历史、用户最新消息、分类规则和四个候选选项。模型需要根据对话内容选择正确的选项字母。例如:
Q. 售前M. 售后F. 其他问题W. 意图不清
训练目标只保留正确答案对应的一个字母。推理时同样只生成一个 token,因此生成长度固定,不需要解析长文本。
这次训练数据分别按固定映射和动态映射构建。

本轮的固定映射,是同一个 case 在不同 epoch 中使用同一组选项;不同 case 之间仍然随机映射,不是 V1 那种所有样本共用同一张字母表。动态映射则让同一个 case 在不同 epoch 中也换一组选项映射,并作为新的训练数据。我们是在构造数据时生成不同映射的版本,再调整训练数据的组织方式,让每个 epoch 读到对应版本。
如果把四个业务标签分别映射到 26 个字母中的不同字母,只计算标签和字母的对应关系,理论上可以得到:
26 × 25 × 24 × 23 = 358,800种映射。如果再把四行选项在 prompt 中的排列顺序单独计算,完整的 prompt pattern 是 358,800 × 4! = 8,611,200 种。实际训练不需要覆盖所有组合,动态映射主要是避免模型把业务标签和某个固定字母绑定。例如固定使用 A=售前 时,模型可能同时学习业务语义和字母先验;动态映射后,同一个售前 case 在不同训练数据中可能对应 A、Q、M 等不同字母,模型需要更多依赖输入和选项内容进行判断。
我们也给同一份验证数据构造了三组不同映射,观察同一个 case 换一组字母后是否仍然得到相同的业务标签。这次还没有单独统计三组映射的一致率,后面可以继续补充。
两阶段训练。
第一阶段使用通用分流数据训练,主要学习整体业务标准。第二阶段使用历史 badcase 和新业务边界 case 继续训练,重点处理退款权益、红包、物流赔付、上下文继承和意图不清等问题。
不同方案的结果如下:
模型版本 | 四分类准确率 | 线上实际分流准确率 | 最新专项 badcase(四分类) |
V4 Stage 1 | 79.41% | 93.55% | 4 / 20 |
V4 基线(Stage 2) | 80.20% | 94.57% | 5 / 20 |
V5 固定映射 Stage 1 | 79.07% | 93.89% | 18 / 20 |
V5 动态映射 Stage 1 | 79.86% | 93.78% | 19 / 20 |
V5 固定映射 Stage 2 | 79.19% | 95.48% | 20 / 20 |
V5 动态映射 Stage 2 | 82.35% | 95.81% | 20 / 20 |
我们使用的 V4 基线已经是 Stage 2 模型,所以分析训练收益时,要把 Stage 1 和 Stage 2 分开看。V4 从 Stage 1 到 Stage 2,四分类和实际分流分别提升 0.79pp 和 1.02pp;V5 固定映射分别提升 0.12pp 和 1.59pp;V5 动态映射分别提升 2.49pp 和 2.03pp。
同阶段比较,Stage 1 的动态映射相对固定映射,四分类提升 0.79pp,实际分流下降 0.11pp;Stage 2 的四分类提升 3.16pp,实际分流提升 0.33pp。这次重新实现后,动态映射与 hardcase Stage 2 的组合取得了最好的效果,尤其是四分类指标。我们目前只跑了这一轮训练,还需要重复实验,确认这个收益是否稳定。
两组准确率差异比较大,是因为我们线上最终只有售前 Agent 和售后 Agent 两个承接方。售前进入售前 Agent,售后、其他问题和意图不清都进入售后 Agent。后三类之间预测错误会影响四分类准确率,但不会改变实际路由。所以我们一直保留两组指标:四分类看模型是否理解业务标准,实际分流看最终有没有交给正确的 Agent。
部署精度问题。
这次部署时,我们发现同一个 checkpoint 在 RTX PRO 5000 上的评测结果与单测、H20 不一致,V4、V5 多个 checkpoint 都受到影响。切回 H20 后才稳定复现,所以最后统一在 H20 上做对比。
这个坑对单 token 分类特别直接。LLM 生成文本时,某一步的 token 排序变了,后面还有继续生成的空间,有时能靠上下文把意思“圆”回来,最终表达未必有明显变化。当然,这不是说生成任务不受精度影响,只是中间某个 token 的变化不一定直接改变最终结论。我们的分流没有这个余地:取的就是第一个输出位置的候选 logits,最大值对应哪个选项,就走哪个业务分支。候选排序一旦翻转,分类结果也就变了,没有后续 token 可以补救。排查下来,不能只确认 checkpoint 相同,还得对齐卡型、推理引擎、量化配置、prompt 模板、候选 token 和并发方式。
这套 7B 分流模型经过两次双十一压测,均能稳定支撑千级 QPS,平均响应时间约 55ms,P99 约 150ms,能够满足客服链路高并发、低延迟的分流需求。
04
从分流模型的视角再看 Jev
从公开接口看,Jev 和淘小蜜分流模型的共同点是:都把自然语言理解转换成有限候选上的打分问题,不依赖长文本生成,最终结果可以直接进入代码逻辑。
两者的差异也比较明显。分流模型针对固定的四类业务标签训练,领域范围比较窄;Jev 的目标是支持运行时定义的问题和候选,并且提供 Choice、Score、Noul 三种统一接口。分流模型返回的是业务标签和候选相对分数,Jev 还强调经过校准的 probabilities 和 confidence。[1][2]
关于 Jev 模型结构的判断。
结合我们的分流实践和社区复现,我个人更倾向于 Jev 沿用语言模型的候选 token logits 来计算结果,而没有再接一套单独的分类 head。这里说的 logits 特指已有 lm head 输出的 vocab token 分数;分类 head 也会输出 logits,真正的区别在于用哪个输出层,以及如何训练。
这个判断主要来自两个观察。首先,Choice、Score、Noul 的核心数值都能从候选分数计算出来;其次,SemIf 和 open-bonsai-jev 已经验证普通生成模型可以通过这条路线完成运行时候选判断,我们自己的分流训练也跑通了。[4][5] 在这个基础上,把单一业务的分类数据换成大量不同领域、不同候选和问题类型的通用分类任务,再用 RLCD 约束决策概率,是我觉得比较可能的一种方案。
不过这些是我的猜测。TypeSafe 目前公开的是新架构、并行 sampler 和 RLCD,没有公布输出层和训练配方。[2] Jev 的多问题并行能力也需要推理侧的专门设计,不能只靠“取一次 logits”解释全部效果。
候选分数和概率校准。
社区复现中比较值得关注的是校准问题。open-bonsai-jev 在 WANLI-256 上的实验显示,Bonsai 2 27B 的准确率为 74.6%,平均置信度为 89.9%,原始校准误差为 0.176。通过温度缩放,校准误差可以降低到 0.088,但准确率不会变化。[5]
这说明直接对候选 logits 做 softmax 可以得到一个总和为 1 的分布,但是这个分布不一定能直接解释成真实正确率。温度缩放可以让 0.8 更接近“同类样本中约 80% 正确”,但不能把错误答案改成正确答案。
我们目前用 std_sigmoid 和 top2 分差筛选 hardcase,更多是利用相对分数。后面如果要按分数决定是否转人工、是否再调用大模型,我们还需要单独做校准,验证每个分数区间的真实准确率。
动态选项映射还需要看什么。
这次我们已经实现不同 epoch 使用不同映射,验证集也准备了三组映射,接下来主要看预测是否稳定。字母 token 在基座模型中已有预训练先验,不同字母的初始概率可能不同;对于得分接近的边界 case,换一组字母仍然可能改变结果。
后面我们可以继续看几个方向:
在现有三组验证映射上增加一致率和最差映射准确率,而不只统计平均准确率。
对比线上固定映射和随机映射,确认随机映射是否真的带来收益。
对候选 logits 做温度校准,而不是直接把 softmax 或
std_sigmoid当成真实概率。对低 margin case 做二次判断或转交更大的模型。
如果后续实验发现普通字母偏置明显,再考虑扩展 special token 或独立分类 head,而不是提前假设一定需要修改词表。
从业务内的规则适配,到跨任务的泛化。
我们的分流模型并不是只能识别训练时固定的四个标签。前面的物流 case 就展示了,只改 prompt 中的规则和候选,也能把物流问题从售后中拆到新增类别。因此,调整业务标准不一定需要重训,可以先改 prompt,再用评测集验证;如果效果达不到要求,再补数据和训练。但目前我们验证得最充分的还是客服 Agent 分流,单个 case 的适配成功,不代表换到其他业务或任务后也能稳定工作。
Jev 想覆盖的范围更广:调用方在运行时给出 state、问题和选项,同一个模型既能做 Choice,也能做 Score、Noul,还能一次处理多个独立问题。[1][2] 我更佩服的是它想实现的跨任务泛化:不只是客服内调整分类边界,而是换到搜索排序、风险判断或游戏决策,也尽量不需要为每个任务单独训练。这是它的目标,不是所有场景都已经验证可用;Laya 在不同任务上的效果差异也提醒我们,接入时仍然要拿自己的业务数据测试。[9][10]
沿着上面的猜测,多任务训练应该很重要。我们的训练主要围绕客服四分类,随机映射能削弱固定字母和位置的捷径,但任务和领域的覆盖仍然有限。如果训练中混合大量通用分类任务,让候选数量、标签描述、问题类型和 state 都变化,模型就更有机会把“根据当前标准判断”的能力迁移到更多场景。我的理解是,RLCD 的目标还包括让模型更准确地表达不确定性,但多任务训练和 RLCD 各自对泛化贡献多少,仍要等官方训练细节。[2]
System One 模型可能带来的变化。
现在不少 Agent 把所有判断都交给负责回答的大模型:先读对话,再生成一段分类结果,随后决定查不查工具、要不要转人工,最后继续生成答案。每一步都让同一个模型展开推理,复杂问题确实需要这种能力;但“这句话是不是在催退款”“现在要不要中断输出”之类的判断,在高并发链路里反复消耗推理时间和输出 token。[7]
System One / System Two 的分工可以更具体:慢模型负责理解复杂诉求、规划步骤、生成最终答复;快模型在每轮对话和执行过程中处理分流、守卫、工具路由、打断和结果校验。对后者来说,输出只需有限选项和可用的分数。TypeSafe 报告 Jev 在其测试条件下端到端为 70—500ms,并给出较低的输入 token 单价;这些是官方报价和演示指标,不能直接推出我们链路上的节省比例。[2]
我们希望快模型能识别自己不确定的 case:稳定的简单 case 直接进入代码分支,低置信度的交给慢模型或人工。如果新业务没有学好,快模型先跑一遍,慢模型再重做一遍,RT 和成本反而增加。所以接入时,我们还会一起看准确率、概率校准、覆盖率、回退比例,以及整条 Agent 链路的 P99。
实时 UI 操作、游戏和机器人也可能采用类似分工:慢模型定目标,快模型在目标确定后判断继续、停止、重试或切换动作。不过 Doom 和浏览器演示说明的是这种接口能跑起来;它们尚不足以证明模型能接管开放环境中的完整规划。[2]
05
结合客服业务场景的思考
客服可能比游戏和 Computer Use 更适合这类模型,只是展示效果没有那么直观。用户发送一条消息后,系统往往需要先后完成分流、意图识别、双工判断、风险识别和工具选择,然后才进入回答生成。这里的大部分判断输出空间有限,但是每轮对话都可能执行,对响应时间和调用成本都比较敏感。
以小蜜现有模块为例,可以大致对应到 Jev 的三种接口:
客服判断 | 适合的输出 | 示例 |
Agent 分流 | Choice | 售前、售后、其他问题、意图不清 |
双工判断 | Choice |
|
意图或工具选择 | Choice | 查询订单、申请退款、修改地址、转人工 |
是否需要转人工 | Noul | 当前问题是否已经超出 Agent 能力范围 |
用户情绪、风险和问题复杂度 | Score | 从低到高的有序等级 |
双工判断是一个比较典型的例子。客服 Agent 在响应任务未完成时收到用户的新消息,需要很快判断是忽略、继续回答、中断当前回答、丢弃结果,还是强制执行新的动作。这类判断如果每次都调用一个需要生成 JSON 的通用 LLM,延迟和成本都比较高;如果写成规则,又很难覆盖口语、省略和上下文相关的表达。
一种可能的做法是让多个模块共用一个 System One 模型。请求中只传一次对话、订单和 Agent 状态,再并行提出多个问题:应该路由到哪个 Agent、用户是否打断了当前回答、当前意图是什么、是否需要转人工。TypeSafe 的接口本身支持对同一份 state 提出多个相互独立的问题,并把减少重复上下文计算作为主要能力之一。[1][7][8] 具体能减少多少延迟,还需要在客服的真实输入长度、并发量和部署环境中重新压测。

对我们来说,共享模型还能减少重复部署和上下文处理,方便统一回流 hardcase。不过一次更新也可能同时影响分流、双工和意图判断,所以我们仍然要给每个模块保留独立评测集、阈值、监控和回退方案。
从这个角度看,Jev 对客服的价值不一定是替代负责回答的 LLM,而是承接回答前后大量高频决策。LLM 继续处理知识查询、复杂推理和答案生成,System One 模型负责尽快判断“接下来应该做什么”。客服本来就是一个对 RT、成本和稳定性都比较敏感的场景,这部分能力可能比再换一个更大的回答模型更容易产生实际收益。
回到我们这一年的实践,用大模型做分类任务是可行的。把输出缩成一个 token 只是开始,真正影响效果的是标签标准、样本分布、字母和顺序 shuffle、线上难例回流,以及二阶段训练。这次重新实现动态映射后,又进一步提高了效果。
对 Jev,我更倾向于它也是从语言模型的候选 logits 出发,通过大量通用分类任务和 RLCD 把能力扩展到更多领域。如果这个判断接近实际,那么我们下一步值得尝试的,就是把分流、双工、意图判断等任务放在一起训练,看看能否用一个模型承担更多客服决策。
最后,感谢一起参与分流模型建设和迭代的同学。这篇文章主要聊算法背后的逻辑,但从业务标准到模型上线,离不开工程、产运和算法同学的共同投入。
参考资料
[1] TypeSafe AI. Primitives (Questions),Choice、Score、Noul 的定义、输出字段和多问题调用方式https://docs.typesafe.ai/primitives
[2] Diogo Almeida / TypeSafe AI. Introducing System One Models & Jevhttps://typesafe.ai/blog/introducing-system-one-models-and-jev
[3] TypeSafe AI. Choice,Choice 选项数量、返回字段和分层分类说明https://docs.typesafe.ai/primitives/choice
[4] TheoLeeCJ. SemIf,直接读取候选 logits、共享 prefix 和复现实验https://github.com/TheoLeeCJ/SemIf
[5] Nicolai Lassen. open-bonsai-jev,普通字母 token 的 next-token logits、WANLI-256 和概率校准实验https://github.com/NicolaiLassen/open-bonsai-jev
[6] AlexWortega. openjev,Qwen3.5 序列分类、NLI 训练和候选 rerank 方案https://huggingface.co/AlexWortega/openjev
[7] TypeSafe AI. Example use cases,模型路由、guardrail、客服、搜索和实时应用等用例https://docs.typesafe.ai/concepts/use-case-map
[8] Jev 中文文档,Choice、Score、Noul 与 confidence 的中文说明https://bald0wang.github.io/jev-docs-zh/
[9] NandhaKishorM. Laya,编码器底座、typed decisions 与使用边界https://github.com/NandhaKishorM/laya
[10] Laya 项目. Benchmarks,零样本、微调、客服分流与延迟实验https://github.com/NandhaKishorM/laya/blob/main/BENCHMARKS.md
[11] Necati Demir. I Tested Laya After the Jev Announcement. Then I Fine-Tuned It.https://n.demir.io/articles/testing-and-fine-tuning-laya/
[12] JhouCode. Laya fit check,独立复测代码与数据说明https://github.com/JhouCode/laya-fit-check


欢迎留言一起参与讨论~
本文转载自微信公众号「阿里技术」,查看原文。版权归原作者所有,如有侵权请联系删除。

