初见 JEV(上)
初见 Jev(上):模型会说还不够,程序需要明确判断
开场
一个客服系统收到这样的消息:
我的信用卡被扣了两次。我已经提交过工单,但一直没有解决,可以直接帮我转人工吗?
人读完这句话,很快就能抓住几个重点:用户遇到了重复扣款,对问题迟迟未解决感到不满,还明确提出要转人工。客服系统接下来要做的,就是分配处理团队、评估不满程度,再判断是否进入人工队列。
如果把消息交给大语言模型,它很可能这样分析:用户遇到了重复扣款,对处理进度不满,希望与人工客服沟通。这样的回答适合人读,但程序还得从中提取处理部门、不满等级和转人工请求,才能继续执行后面的流程。
开发者通常会继续约束输出:“只返回 JSON,不要解释。”JSON 方便程序解析字段,但程序最终需要的仍是几个明确的判断结果。如果模型读完消息后,直接返回“账单问题”“不满程度较高”“用户要求人工”,后续代码就不必再理解一遍模型的回答。
Jev 处理的正是这类任务。开发者先明确软件需要哪些判断,Jev 再根据给定内容逐项回答。程序拿到结果后,可以直接分类、排序、路由或转交人工,不必再分析模型到底“说了什么”。
这篇文章暂不展开 SDK 和接口参数,只从判断任务入手,说明 Jev 是什么、适合用在哪里,以及哪些事情不该交给它。
1、Jev 到底是什么?
Jev 是 TypeSafe 推出的 System One 模型。一次请求包含model、state和questions三个顶层字段:model指定模型,state保存待判断的材料,questions是一组带名称的问题。返回的答案沿用这些问题名称,代码可以据此找到每项判断对应的结果。
一次判断由 State、Question 和 Answer 三部分组成。
State是模型实际能看到的材料,也限定了这次判断的证据范围。它可以是一段字符串,也可以是包含多个字段的 JSON 对象或数组。在客服案例中,最简单的 State 只有用户消息;如果还要参考订单、历史工单或退款规则,可以把相关材料放进同一个对象,用字段名说明它们之间的关系。如果 State 中没有某项事实,就不该让模型替系统补齐。
Question不是宽泛的分析要求,而是一项边界明确的判断。与其问“请分析这名用户并告诉我应该怎么办”,不如拆成“应该交给哪个团队”“用户有多不满”“用户是否明确要求人工处理”。每个问题都有开发者指定的 ID。这个 ID 只供代码匹配问题和答案,不参与模型判断;真正影响回答的是问题类型、instructions和criteria。
Answer是程序最终拿到的结构化结果,可能是从候选项中选出的部门、位于几个等级之间的分数,或某件事成立的概率。程序按照问题 ID 读取答案后就能进入后续逻辑,不必再从解释文字中寻找结论。
同一份 State 可以同时对应多个问题,每个问题各自完成一项判断。以前面的客服消息为例,系统可以一次询问:
| 要判断的问题 | 适合的问题类型 | 程序希望得到什么 |
|---|---|---|
| 应该交给哪个团队 | Choice | 从账单、物流、账户等选项中选择一个 |
| 用户有多不满 | Score | 在一组有顺序的等级上给出分数 |
| 用户是否要求人工处理 | Noul | 返回“是”成立的概率 |
这三种类型解决的是不同问题。
Choice 用于固定选项。它的criteria是一组“选项名称—选项说明”。选项名称供代码使用,例如billing;选项说明告诉模型哪些情况属于该选项,例如“扣款、账单、发票或支付问题”。返回结果包含选中的名称、每个候选项的概率,以及这次选择的置信度。如果选项说明相互重叠,即使格式完全正确,模型也可能难以区分。
Score 用于有顺序的等级。它的criteria是一个从低到高排列的描述数组,数组位置从 0 开始编号。例如,四个情绪等级分别对应 0、1、2、3。Jev 会返回每一级的概率,并根据这组分布计算分数,因此结果可能是 1.7 或 2.3,不一定正好落在某个整数等级上。程序既可以保留连续分数,也可以按照业务规则将其映射为普通、高优先级或紧急工单。
Noul 用于真假判断。它返回一个 0 到 1 之间的数值,表示“是”成立的概率。以“用户是否明确要求人工处理”为例,数值越接近 1,模型越倾向于认为这件事成立。Noul 可以只写instructions,也可以在criteria中分别说明什么算“是”、什么算“否”。它不会像 Choice 和 Score 那样另行返回 confidence,因为这个概率本身就是判断信号。
Choice 和 Score 的 confidence 由完整概率分布计算而来。概率越集中在某个选项或等级上,confidence 越高;分布越分散,confidence 越低。它表示这次分布是否集中,不等同于经过统计验证的单次正确率。
理解 Jev 时,不必先死记这三个名字。它的基本工作方式是:开发者先定义答案的形状,模型再针对 State 完成判断。代码不用等待一段自由文本,也不用猜哪句话才是最终结论。
上篇先讲 Choice、Score 和 Noul,这三种类型已经足以说明 System One 模型与常见生成模型的差别。
换个更小的场景会更直观。假设电商平台收到评价:“充满电只能用半天,其他方面还可以。”这段评价就是 State。系统可以设置一个 Choice,判断主要问题属于续航、屏幕还是性能;再设置一个 Noul,判断用户是否明确提出退货。程序根据前一个 Answer 将评价计入电池问题统计,再根据后一个 Answer 决定是否进入退货意图处理流程。模型只负责判断评价表达了什么,商品信息查询和售后资格校验仍由其他程序完成。
2、Jev 为什么不以生成文本为主要目标?
大语言模型擅长生成文本。写邮件、总结资料、解释概念、生成代码,都需要模型根据上下文组织内容,答案可以很长,表达方式也不止一种。
程序处理判断任务时,关心的通常不是一段解释,而是结果属于哪个类别。客服消息被判断为账单问题,就进入账单流程;属于账户访问问题,就交给另一套处理逻辑。这里需要的是稳定的类别名称,而不是意思相近、措辞却可能变化的说明。
有些任务不能只看类别,还要判断风险、严重程度或匹配程度。例如,两条消息都表达了不满,但一条只是在询问处理进度,另一条已经多次投诉并要求立即升级。系统要安排优先级,就需要可比较的等级或分数。
程序还会关心某个条件是否成立,例如用户是否提出退款、是否要求人工处理。拿到判断后,系统仍要决定能否自动执行。如果几个候选结果十分接近,说明模型没有形成明显倾向,可能是信息不足、选项重叠,也可能是输入本身存在歧义。此时应该补充上下文、检查问题设计或转交人工,而不是强行采用概率最高的结果。
如果用生成模型完成这类任务,常见流程是:
输入内容 → 生成文本或 JSON → 校验格式 → 解析字段 → 进入程序分支
Jev 的流程更接近:
输入 State 和类型化问题 → 返回结构化判断 → 进入程序分支
两者的差别不只是少写一段解析代码。现在的 LLM 也能通过结构化输出、JSON Schema 或工具调用返回固定格式,所以**“能不能生成合法 JSON”并不是 Jev 与 LLM 的核心分界**。
真正的区别在任务接口。LLM 的结构化输出通常要求模型生成符合 Schema 的内容,而 Jev 的接口直接由 Choice、Score 和 Noul 这些判断类型组成。Choice 返回所有候选项的概率,Score 返回各等级的概率和据此计算的连续分数,Noul 返回“是”成立的概率。程序拿到的不只是格式正确的最终标签,还能看到其他候选答案各占多少概率,以及这次判断是否集中。结果不够明确时,代码可以暂停自动处理,补充上下文、调用其他模型或交给人工复核。
对判断系统来说,解释得流畅不等于结果容易使用。一段很有说服力的文字,程序仍可能无从下手;类型清楚、带有概率的结果,更容易接入实际工作流。这正是 Jev 不以生成解释为主要目标的原因。
例如,邮件系统收到一句“请不要再给我发送每周资讯”。生成模型可能回复:“用户希望停止接收订阅邮件,建议将其从邮件列表中移除。”这段话没有错,但程序还要从中提取“取消订阅”这个动作。如果改用 Noul 提问“用户是否明确要求停止接收资讯”,系统会直接拿到该命题成立的概率。后续程序先检查用户身份和订阅状态,再执行取消操作,不必解析模型生成的说明文字。
3、Jev 与我们熟悉的大语言模型有什么区别?
Jev 和 LLM 都能理解自然语言输入,但它们服务的任务不同。
| 维度 | 大语言模型 | Jev |
|---|---|---|
| 主要任务 | 生成、总结、解释和开放式推理 | 分类、评分和真假判断 |
| 常见输出 | 自然语言、代码或工具调用 | 类型化答案、概率和部分问题类型的置信度 |
| 答案范围 | 可以开放生成 | 由问题类型和判断标准约束 |
| 主要使用者 | 人、Agent 或其他模型 | 软件控制流 |
| 适合的位置 | 内容生成和复杂任务处理 | 路由、筛选、判断和复核节点 |
例如,用户问“请解释为什么这笔费用不合理”,LLM 更适合根据材料组织回答。系统问“这条消息是否提出退款要求”,Jev 更适合返回一个真假概率。
判断和生成可以放在同一条流程中。系统可以先让 Jev 判断请求属于哪一类,再由代码选择相应的 LLM;也可以先让 LLM 生成答复,再用结构化判断检查是否遗漏关键条件。具体怎样组合留到第三篇展开,这里先记住:Jev 和 LLM 不是同一个位置上的竞争者。
Jev 和 LLM 之外,普通代码仍要负责确定性操作。金额比较、权限校验、数据库查询、库存检查等结果明确的操作,应继续由代码完成。模型适合处理非结构化信息中的语义判断,不该接管所有控制逻辑。
假设用户说:“我换了手机以后一直登录不上去,能帮我处理吗?”Jev 可以将其判断为账户访问问题;LLM 根据排查步骤生成用户能读懂的回复;代码负责检查账户是否存在、验证码是否有效,以及当前账号是否具备相应权限。三者处理同一条请求,但职责不同:Jev 判断请求该进入哪条流程,LLM 组织沟通内容,代码读取真实状态并执行操作。
4、Jev 适用场景
判断一个任务是否适合 Jev,可以先问三个问题:
- 答案能否被定义成固定选项、有序等级或真假判断?
- 模型能否根据给定 State 在较短时间内完成这个判断?
- 程序拿到答案后,是否会据此执行分类、排序、路由或复核?
三个问题大致都能回答“是”,通常就值得考虑 Jev。还可以换个更直观的问法:一个了解上下文的人,能否迅速作出这个判断?如果任务需要搜索外部资料、完成多步计算、制定计划或写长篇解释,就不该硬塞进一个 Jev 问题。可以把其中能够快速判断的环节拆出来,其余部分继续交给代码、工具或生成模型。
固定选项
工单应该交给账单、物流还是账户团队,商品属于哪个类别,请求应该交给哪个模型,这些问题都有预先定义的答案集合,适合使用 Choice。关键不在于“能列出几个选项”,而在于程序会根据选中的答案进入不同分支。
以工单路由为例,billing、shipping和account不只是给模型看的标签,还要对应代码中的处理器。模型返回billing后,系统才能把工单交给账单流程。因此,选项名称应该保持稳定,选项说明也要写清边界:重复扣款属于账单问题,包裹迟迟未到属于物流问题,无法登录属于账户问题。
对于“发票上的公司名称写错了,请帮我修改”这条工单,Choice 可以返回billing,代码再把它交给发票处理队列。如果billing的说明只写成含义模糊的“其他财务问题”,它就可能与退款、扣款等类别重叠,后续路由也会变得不稳定。
Choice 默认是在候选项中选出一个最可能的答案。如果一条消息可以同时属于多个类别,就不能用一个 Choice 把它们硬做成互斥选项。开发者可以把问题改成选择“主要处理团队”,也可以将多个类别拆成独立的 Noul 问题。具体怎么设计,取决于代码需要单选结果,还是需要保留多个同时成立的标签。
有序评分
风险、严重程度、匹配程度和用户情绪通常不能简单地用“是”或“否”表示,而是有从低到高的顺序,适合使用 Score。
例如,客服系统可以定义“平静、轻微不满、明显不满、强烈不满”四个等级。等级顺序要有实际含义,相邻两级也要能够区分。“明显不满”可以要求消息中出现问题持续未解决、重复投诉等信号;“强烈不满”则可以要求出现立即升级、停止服务或向监管机构投诉等更强烈的表达。如果只写“低、中、高、非常高”,却不说明各级对应哪些证据,即使模型返回了分数,开发者也很难判断问题出在哪里。
Score 不只是选中某个整数等级。假设模型认为第 2 级最可能,但第 3 级也有不小的概率,最终分数就会落在 2 和 3 之间。代码可以用这个连续分数排序,也可以结合置信度决定是否自动提高优先级。分数回答“结果大致位于哪里”,置信度回答“这组等级是否形成了清楚的倾向”,两者不能互相替代。
例如,用户写道:“这是我第三次反馈同一个问题,如果今天还不能解决,请立即升级处理。”这句话既提到多次反馈,也明确要求升级,结果可能落在“明显不满”和“强烈不满”两个相邻等级之间。程序可以根据连续分数安排处理顺序,同时查看置信度;如果几个等级的概率过于分散,就先保留原优先级,交给人工复核。
是非判断
“用户是否要求退款”“文档是否包含个人信息”“当前请求是否明确要求人工介入”,这些问题适合使用 Noul。
Noul 的问题最好写成一个可以根据 State 判断真假的命题。“用户是否明确要求人工处理”比“要不要转人工”更合适:前者只判断消息中是否有明确请求,后者还混入了客服资源、服务时间和升级政策等业务规则。
Noul 不会直接替程序作出最终决定。它给出“是”成立的概率:接近 1 表示更倾向于成立,接近 0 表示更倾向于不成立,接近 0.5 则说明证据不足,或正反信号接近。哪些结果可以自动处理,哪些需要用户确认或人工复核,仍要根据业务风险和实际测试来定。
关键词不能代替命题判断。“先别给我退款,我想等技术人员再看一下”虽然出现了“退款”,表达的却是否定意图。如果问题写成“消息中是否出现退款相关词”,结果会偏离业务需要;写成“用户是否正在要求退款”,模型才能结合否定词和上下文判断真实意图。
一份内容,多个独立判断
实际系统往往要同时获得多项判断。客服消息既要分类,也要评估严重程度,还要检查退款和人工升级信号。Jev 可以让这些问题针对同一份 State 独立判断,再由代码组合结果。
这里的“多个问题”并不等于让模型替系统做一整套决策。部门分类、不满评分和人工请求可以共享同一条消息,但每项答案仍对应一个明确问题。代码可以规定:分类结果明确时自动路由,不满程度较高时提升优先级,用户明确要求人工时进入人工队列。哪项判断出了错、哪条标准需要调整、哪个动作必须增加复核,都可以单独检查。
如果后一个问题必须依赖前一个问题的结果,例如先确定合同类型,再按该类型查询规则,最后判断是否允许退款,就不该把它们塞进一次“综合判断”。这是一个存在前后依赖的流程,需要代码或 Agent 负责查询和编排;Jev 只处理各个步骤中边界清楚的语义判断。
例如,对于“包裹还没到,我已经等了一周,能直接找人工吗?”这条消息,Jev 可以分别判断:主要问题属于物流,用户表现出明显不满,并且明确要求人工处理。代码再组合这些结果,把工单交给物流团队、提高处理优先级并加入人工队列。Jev 不必再回答“最终应该怎么办”,因为后续动作已经写在系统规则中。
下篇预告
Jev 能对消息分类或评分,不代表程序可以据此直接执行操作。模型可以看出用户在要求退款,却不能证明账户真的发生过重复扣款;它可以判断用户希望转人工,却不能代替系统检查客服是否在线,也不能确认当前账号是否有权发起操作。
下篇会继续使用开头的客服消息,逐一拆开这些问题:哪些内容由 Jev 判断,哪些事实必须查询数据库,哪些条件应该写进代码。接着再看程序如何读取 Choice、Score 和 Noul 的结果,什么时候自动路由,什么时候提高工单优先级,什么时候因为答案不够明确而转交人工。最后会用一份完整的请求和响应,把这些环节串成一条实际流程。
结束语
读到这里,可以先把Jev 理解成一个专门回答判断题的模型。程序把用户消息、文档或其他材料交给它,并写清需要回答的问题。Jev 不负责生成一段供人阅读的解释,而是直接返回程序可以使用的答案。
程序需要从账单、物流和账户中选出一个部门时,可以使用 Choice;需要判断风险或不满程度时,可以使用 Score;只关心某件事是否成立时,可以使用 Noul。同一份内容也能同时回答多个问题,再由代码决定接下来走哪条流程。
判断是否需要 Jev,可以先看最终答案是给人读,还是给程序用。用户最终想要的是一封回复、一篇文章或一段解释,就交给生成模型;程序只是想知道“属于哪一类、程度有多高、这件事是否成立”,Jev 才有用武之地。