Jev 是 TypeSafe AI 推出的一款模型,主要用来帮助程序做分类、打分和判断。你提供待分析的内容,提前定义问题和答案类型,它就返回程序可以直接使用的结果。例如,判断一条消息是不是退款申请、应该交给哪个团队、是否需要优先处理。
TypeSafe 将这类模型称为 System One Model,强调快速、范围明确的判断。理解 Jev,可以先从软件里一个常见的需求入手:程序知道下一步有哪些操作,但需要先读懂用户的话,才能选出合适的操作。 下面用客服消息贯穿介绍,再看它怎样用于 Agent 和知识库问答。官方介绍
假设一个客服系统收到消息:
这个东西用不了,我也不想再折腾了,把钱退给我吧。
程序需要知道“用户是否正在要求退款”,才能决定是否进入退款咨询流程。最直接的办法是匹配关键词:
message = "这个东西用不了,我也不想再折腾了,把钱退给我吧。"
wants_refund = "退款" in message
print(wants_refund) # False用户说的是“把钱退给我”,没有出现“退款”两个字,所以这段代码漏判了。反过来,“我暂时不退款,先帮我修一下”包含关键词,却不应该进入退款流程。不断补充关键词和排除规则,很容易变成对各种表达的追赶。
Jev 可以根据语义回答“用户是否明确要求退款”,把判断结果交回代码。程序再根据结果分支:确定是在申请退款,就进入退款咨询;确定没有这个意图,就继续处理原问题;意思不清楚,就请用户补充说明。这就是官方所说的“智能 if 判断”的一种用法。官方应用场景
这里的分工很具体:模型理解用户表达,业务代码决定接下来执行什么。订单是否存在、是否已支付、是否超过退款期限,通常可以查询数据后按规则处理。识别出退款意图,也不代表用户已经满足退款条件。
普通聊天模型同样能识别意图,也能通过结构化输出返回分类结果。Jev 的特点是专门围绕这类判断设计接口,直接提供有限选项、评分和概率。它当前不生成自由文本,因此需要解释退款政策、撰写回复时,可以继续交给聊天模型。
| 当前要完成的工作 | 可以怎样处理 |
|---|---|
| 查询订单是否存在、计算距下单已经过了几天 | 数据库查询和普通代码 |
| 理解“把钱退给我”是否表达了退款意图 | Jev,或能完成分类的聊天模型 |
| 根据退款政策组织一段自然、清楚的回复 | 能生成文本的聊天模型 |
Jev 的设计目标包括降低这类判断的延迟和成本。是否值得引入,要看实际任务:如果已有模型一次调用就能完成分类和回复,再增加一道 Jev 调用也可能增加耗时;如果大量请求只需要分类后进入固定流程,专门的判断模型就更值得比较。官方性能数据有其测试条件,不能直接推算成整个应用的提速比例。官方产品说明与评测条件
使用 Jev 时,首先要分清待判断的内容和要问的问题。接口里对应的是 state 和 questions,另外用 model 指定模型。下面是一份识别退款意图的请求体:
{
"model": "jev-latest",
"state": "这个东西用不了,我也不想再折腾了,把钱退给我吧。",
"questions": {
"wants_refund": {
"type": "noul",
"instructions": "用户是否明确要求退款?仅询问退款政策不算申请退款。"
}
}
}state 提供本次判断的依据。这里一条消息已经够用;如果用户只说“那就按刚才说的办”,单看这句话就无法知道其意图,需要提供相关的前文。
questions 里每个问题都有一个名字,这里叫 wants_refund,用于在返回结果中找到对应答案。问题真正的含义写在 instructions 中;不能只起一个 wants_refund 的名字,就期待模型知道判断标准。type: "noul" 则告诉接口,这是一道“是不是”的题。请求结构
Jev 一共提供三种基本提问方式,可以先记成:Noul 问“是不是”,Choice 问“是哪一个”,Score 问“到什么程度”。
| 类型 | 用来问什么 | 客服场景中的例子 |
|---|---|---|
| Choice | 从预先定义的选项中选一个 | 这条消息属于支付问题、物流问题,还是产品使用问题? |
| Score | 按预先描述的等级评分 | 用户的情绪有多强烈?从平静、不满到非常愤怒。 |
| Noul | 判断一个问题的答案是否为“是” | 用户是否明确要求退款? |
先看上面使用的 Noul。下面是返回结果中与问题有关的部分,数值仅用于说明,实际调用可能不同:
{
"answers": {
"wants_refund": {
"type": "noul",
"noul": 0.97
}
}
}0.97 表示模型估计“用户明确要求退款”为真的概率是 97%。接近 1 时倾向“是”,接近 0 时倾向“否”,接近 0.5 时两种答案相近。Noul 没有另一个独立的 confidence 字段。
不要把这个值理解成“退款意愿强度”:0.5 不表示用户只想退一半的钱,也不直接表示他有一半程度的不满。它描述的是模型对这一命题的判断。像“这东西让我挺失望的”这样的表达,可能需要追问用户想要维修、换货还是退款。Noul 的含义
如果想知道消息应交给哪个团队,就可以使用 Choice。下面展示的是一个问题对象,可放在请求的 questions 中:
{
"department": {
"type": "choice",
"instructions": "这条消息应优先交给哪个团队处理?",
"criteria": {
"after_sales": "退货、退款申请、换货等售后诉求",
"technical": "希望获得产品使用或故障排查帮助",
"shipping": "查询物流进度、配送延迟或包裹丢失",
"other": "其他情况,或信息不足以判断"
}
}
}criteria 定义允许选择的选项,每个选项都有业务含义。返回的 choice 是选中的选项,probabilities 给出各选项的概率。例如,下面是假设的一组概率:
{
"after_sales": 0.88,
"technical": 0.08,
"shipping": 0.01,
"other": 0.03
}此时 choice 会是 after_sales。模型依然认为技术支持有一定可能性,因为用户也提到“东西用不了”。如果公司规定“只要明确要求退款,就优先交给售后”,应该把这个规则补进问题或选项说明,让模型知道业务边界。
Choice 是从选项中选一个。需要同时判断“是否有故障”和“是否要求退款”时,可以问两道 Noul,保留两个结果。也可以给 Choice 增加 other,避免把所有消息都硬塞进并不合适的部门。Choice 文档
如果关心情绪程度,可以使用 Score。关键是先把等级写清楚,再让模型评分:
{
"frustration": {
"type": "score",
"instructions": "仅根据消息措辞,评价用户表达出的不满程度。",
"criteria": [
"语气平静,主要在陈述问题,没有明显抱怨",
"明确表达失望、不耐烦或抱怨,但语气仍然克制",
"表达强烈愤怒,出现辱骂或强烈指责"
]
}
}这里的等级按数组顺序从 0 开始编号,所以分数范围是 0 到 2。如果返回 1.2,可以理解为落在“不满但克制”和“强烈愤怒”之间,更靠近前者。这个数值可以有小数,不能按“满分 100 分”去解读。
Score 还会返回每个等级的概率和等级说明。分数是等级编号按概率加权后的结果。例如,等级 0、1、2 的概率分别为 0.1、0.6、0.3,分数就是 0 × 0.1 + 1 × 0.6 + 2 × 0.3 = 1.2。分数的意义来自你定义的等级;只写“低、中、高”,往往不如描述具体表现清楚。Score 文档
Choice 和 Score 都有 confidence,用于概括概率分布有多集中。例如,一个部门明显领先,比几个部门的概率差不多时更确定。它由概率分布计算,不能直接当成所选答案的概率,也不能把 confidence = 0.9 解读成“这次判断有 90% 的正确率”。置信度说明
这一区别影响程序怎么处理结果:Choice 可能已经选出了一个部门,但如果几个部门的概率很接近,程序仍可以转人工分流;Score 得到一个中间分数,也可能是模型在不同等级之间犹豫。输出格式可靠,不保证语义判断正确。 即使返回的选项一定在允许范围内,也仍可能选错。
熟悉输入和输出后,就可以实际试一次。最省准备工作的入口是官方 Playground:
想体验时,可以从官方 Playground 开始:
- 打开 TypeSafe Playground,登录并按页面提示获取访问权限。
- 把上面的客服消息填入
state,添加一个 Noul 问题:“用户是否明确要求退款?” - 在问题说明中补上“仅询问退款政策不算申请退款”,运行后查看返回的
noul值。 - 保持问题不变,换几条消息再运行,观察结果是否符合预期。
可以从下面这组消息开始。表中是按照本例定义应识别出的含义,不是模型实测结果:
| 消息 | 应区分出的含义 |
|---|---|
| 这个东西用不了,把钱退给我吧。 | 明确要求退款 |
| 我暂时不退款,先帮我修一下。 | 明确否定退款意图 |
| 如果不好用,可以退款吗? | 询问政策,没有提出当前退款申请 |
| 上周申请的退款,怎么还没到账? | 查询已有退款的进度,需要与新的申请区分 |
| 太失望了,真的不想再折腾。 | 表达不满,具体诉求仍不明确 |
第四条尤其适合用来检查问题定义:你的系统是否把“查询退款进度”也算退款意图?如果只是决定进入售后流程,可以合并;如果要创建新的退款申请,就必须区分。模型的回答能否满足需求,取决于这道题有没有问到真正需要判断的事情。
需要接入程序时,可以使用官方 Python SDK。以下示例要求 Python 3.10 或以上,以及具有调用权限的 API Key。先在一个示例项目目录中创建虚拟环境,再安装 SDK:
python3 -m venv .venv
source .venv/bin/activate
python -m pip install typesafe-sdk将下面代码保存为 jev_refund_demo.py。运行时通过隐藏输入读取 API Key,再放入当前进程的环境变量,SDK 会自动读取 TYPESAFE_API_KEY。官方 Quick Start
import os
from getpass import getpass
from typesafe_sdk import Noul, TypeSafeClient
def choose_next_step(probability: float) -> str:
# 演示阈值,实际项目需要用自己的样例调整。
if probability >= 0.9:
return "进入退款咨询流程,继续核对订单和退款条件"
if probability <= 0.1:
return "继续处理原问题,不创建退款申请"
return "请用户澄清:您希望申请退款,还是继续排查问题?"
if __name__ == "__main__":
if not os.environ.get("TYPESAFE_API_KEY"):
os.environ["TYPESAFE_API_KEY"] = getpass("TypeSafe API Key: ")
message = input("请输入客服消息:").strip()
if not message:
raise SystemExit("消息不能为空")
with TypeSafeClient() as client:
response = client.system_one(
model="jev-latest",
state=message,
questions={
"wants_refund": Noul(
instructions=(
"用户是否明确提出当前的退款申请?"
"仅询问退款政策、查询已有退款进度,"
"或明确表示暂不退款,都不算。"
)
)
},
)
probability = response.answers["wants_refund"].noul
print(f"退款申请概率:{probability:.3f}")
print(f"下一步:{choose_next_step(probability)}")在同一终端执行:
python jev_refund_demo.py输入 API Key 和客服消息后,程序会调用 Jev,再打印概率和下一步建议。如果实际返回 0.97,代码就会输出:
退款申请概率:0.970
下一步:进入退款咨询流程,继续核对订单和退款条件这段程序里,client.system_one() 发出请求;response.answers["wants_refund"].noul 取出这道题的结果;choose_next_step() 决定如何处理。示例只打印下一步建议,没有执行退款操作。jev-latest 是模型别名;后续要做可重复的效果对比时,应记录实际返回的模型版本。
这里刻意保留了三个分支:概率接近 1,按“是”处理;接近 0,按“否”处理;中间留给澄清。对 Noul 来说,很低的值可以表示模型很确定答案为“否”,不能把所有低值都当成“不确定”。0.9 和 0.1 只是演示阈值,需要根据误判代价和实际样例调整。
调用失败时也没有概率可以使用。如果报错,应根据错误信息检查凭据、访问权限、请求参数或网络。接入真实业务后,需要给 API 失败单独安排重试、提示或人工处理路径,不能把失败默认转换成“没有退款意图”。
当客服流程需要更多信息时,可以把 wants_refund、department 和 frustration 放进同一次请求的 questions。它们共享同一个 state,分别回答自己的问题。按官方说明,这些问题独立、并行评估;同一请求中的一道题不会先读到另一道题的答案。因此,“先根据部门决定后面问什么”这样的依赖关系,应由代码在拿到结果后安排。多个问题的评估方式
理解这个客服例子后,其他场景就比较容易对应了。最适合优先尝试的任务,是答案范围明确、需要理解内容、结果容易核对,而且会重复发生的判断。 工单分类、意图识别和固定流程的分流都符合这些特点。可以先让 Jev 给出分类建议,与人工结果对照,再决定哪些情况能够自动处理。
在 Agent 中,一个常见用法是入口路由。假设应用有普通问答、知识库查询、联网搜索三个处理流程,Jev 可以用 Choice 判断请求属于哪类,再由代码调用对应流程:
flowchart LR A[用户请求] --> B[Jev 判断处理类型] B --> C[普通问答] B --> D[知识库查询] B --> E[联网搜索] B --> F[不确定时澄清或转人工] C --> G[组织回复] D --> G E --> G
这里的“路由”就是选择交给谁处理。例如,“根据产品手册解释退款规则”可以进入知识库查询,“查一下今天发布的新政策”可能需要联网搜索。类似地,也可以把请求分给不同模型或专门的 Agent。官方意图路由示例
不过,选中 web_search 并不意味着已经得到搜索关键词,更不意味着已经完成搜索。选择处理流程、准备工具参数、执行工具、组织回复,是不同的工作。 Jev 可以负责其中范围明确的选择,参数准备则由代码或具备相应能力的模型完成。多意图请求也要单独考虑:一句话同时要求查询政策和修改订单时,只选一个流程可能丢掉一部分诉求。
在 RAG,也就是先检索资料再生成答案的系统里,Jev 可以放在检索与生成之间,检查候选文档能否支持回答。比如用户问“退款多久到账”,检索结果可能同时包含“申请退款的条件”和“退款到账时间”。两段内容都与退款有关,但只有后者直接回答到账时间。可以把问题和每段候选资料一起交给 Jev,判断“这段内容是否提供回答该问题所需的信息”。官方 RAG 筛选示例
这样,检索负责从大量资料中找出候选,Jev 帮助筛选候选,生成模型利用保留下来的资料回答。是否增加这一步,要比较回答质量、漏掉有用资料的情况,以及新增耗时和费用。如果筛完没有足够证据,流程也应允许继续检索或说明资料不足。相关性判断本身不会补出缺失的知识。
还有一类用法是检查输出。例如,把客服回复和相关政策一起提供给 Jev,问“回复是否包含政策没有支持的退款承诺”。这种问题比笼统地问“回答好不好”更容易定义,也更容易人工核对。它仍是一次模型判断;如果要检查金额是否相等、JSON 是否符合结构、必填字段是否齐全,优先使用直接的程序校验。
开始做第一个小项目时,可以沿用本文的退款例子,先收集一小批明确申请、否定申请、政策咨询和含糊表达的消息,人工写下期望结果。保持问题定义一致,查看 Jev 哪些地方判断对了、哪些地方混淆,再调整提问和阈值。除了看分类是否正确,还要看多少请求被送去澄清,以及加入判断后整个流程是否更有效。高置信度样例也应该抽查,避免只看到模型“很确定”,却没有发现它理解错了业务标准。