Score 打分题:按你定义的量表打分
上一课的 Choice 是从固定选项里挑一个。但很多判断不是「挑哪个」,而是「到什么程度」:bug 多严重、客户多愤怒、候选人 Python 多熟练。
这类问题用 Score:你给出一张有序量表,Jev 把内容放到量表上的某个位置,连同每级概率和置信度一起返回。
其实你在第一个请求里已经见过它——工单示例里的 frustration 就是一道三级 Score 题,返回了 0.67。这节课把它讲透,全程 10 分钟。
学完你能做什么
- 用
criteria定义一张有序量表(建议至少两级、上限 10 级),让 Jev Score 按你的量表给任何内容打分 - 读懂返回的五个字段:
score、legend、probabilities、confidence、type - 说清 1.43 这种「落在两级之间」的分数是怎么算出来的
- 用 score 过阈值、用 confidence 决定要不要转人工
- 把多维度判断拆成多道 Score 问题,在代码里归一化加权合并
你现在的困境
- 让 GPT 给工单打 1–10 分,同一条工单这次 6 分、下次 8 分,「超过几分转人工」的阈值根本定不下来
- 评分标准是模型自由发挥的:我说的「中等严重」和它理解的对不上,换一版 prompt 历史分数全得重打
- 拿到一个 7 分就完了——不知道是十拿九稳的 7,还是 6 分 8 分各一半凑出来的 7,哪些该人工复核全靠猜
什么时候用这一招
当你需要:
- 给内容在光谱上定位:严重度、沮丧程度、技能水平、报告质量
- 分数能直接进代码:过阈值、排序、加权求和
- 每个等级的概率和整体置信度,作为「要不要人工看一眼」的信号
而且不想:
- 让聊天模型自由发挥「打个 1–10 分」,再写解析代码去抠它输出的文本
- 把评分标准混进 prompt,模型换版后标准跟着漂
- 在模型没把握的时候也放它自动执行
🎒 开始前的准备
- 完成了 State 状态:知道要打分的内容放在
state里(字符串、JSON 对象、文本数组都行) - 跑通过第一个请求:
.venv里装好了typesafe-sdk,TYPESAFE_API_KEY已在环境变量里
核心思路
Score 回答「到什么程度」。 官方给的适用场景:bug 多严重、客户多满意、候选人 Python 经验多少。答案在一段光谱上,而且你能把光谱逐级描述出来——这是用 Score 的前提。
量表就是 criteria。 一道 Score 题只有三个字段:
| 字段 | 写什么 | 例子 |
|---|---|---|
type | 固定 "score" | — |
instructions | 一句话说清评什么 | How severe is the reported issue? |
criteria | 有序等级列表,从低到高,每级一条描述 | 见第 1 步的三级量表 |
等级的编号就是数组下标,从 0 开始:三级量表就是 0、1、2。模型看到的只有每级的文字描述——它看不到级号,也看不到相邻等级。
返回五个字段。
| 字段 | 是什么 |
|---|---|
score | 量表上的位置,0 到最高级号;可以落在两级之间,比如 1.43 |
legend | 级号 → 等级描述的映射,帮你解读分数 |
probabilities | 每个等级的概率,加起来约为 1 |
confidence | 0–1;概率越集中在一级,越高 |
type | "score" |
score 是算出来的,不是拍出来的。 每个级号乘以它的概率再求和:0×0.0 + 1×0.57 + 2×0.43 = 1.43。
三种题型怎么选。
| 题型 | 答案形态 | 代码里的用法 |
|---|---|---|
| Choice | 固定选项挑一个,选项之间没有顺序 | 映射到 N 条代码路径 |
| Score(本课) | 光谱上的位置,每级你能描述 | 过阈值、排序 |
| Noul | 干净的是/否,概率本身是信号 | 一个 if |
官方判据:答案在光谱上、每级能描述 → Score;固定选项、无顺序 → Choice;干净是非 → Noul。两个都像时,选答案能被代码直接行动的那个。也别拿 Noul 问「候选人 Python 强不强」——「强」没定义时,noul 0.5 只是一半对一半错,不是「中等水平」;测水平,用 Score 的定义等级。
跟我做
第 1 步:定义你的 Jev Score 量表(criteria 有序等级)
为什么:模型判断时只拿得到你写的等级描述——它看不到级号、看不到相邻级。描述写成「情境」,模型才能把 state 对上去;写成数字或「中等严重」这类程度词,它就没有可对照的东西(后果见踩坑提醒第 1 条)。
本课用官方文档的 bug 严重度量表,三级:
0: Cosmetic; no impact to functionality
1: Broken or degraded feature, but workaround exists
2: Blocking issue; no workaround exists从低到高:0 级「外观问题,不影响功能」、1 级「功能坏了但有替代方案」、2 级「彻底阻塞,没有替代方案」。
写量表的官方守则:
- 描述情境,不描述程度:「功能坏了但有替代方案」可以对照设定,「中等严重」不行
- 能描述清楚几级就写几级,上限 10 级;三级很常用
- 一道题只测一个维度——「守时、聪明、有经验」是三道题(见踩坑提醒第 2 条)
- 量表顶端有需要特殊处置的罕见情形,单独给一级(见踩坑提醒第 4 条)
你应该看到:三条等级描述,每条都是一个能直接拿去和 bug 报告对照的具体情境。
- 我的每级描述都是情境,没有「轻/中/重」式程度词,也没有裸数字
第 2 步:用 typesafe-sdk 发出第一个 Score 打分请求
为什么:先把官方单题示例原样跑通,再换成自己的量表和逻辑——排错时永远有「已知正确」的基线。
新建 score_bug.py,贴入官方示例:
from typesafe_sdk import Score, TypeSafeClient
with TypeSafeClient() as client:
response = client.system_one(
state="The export button crashes the settings page in Safari. It works in Chrome, but a few of our customers only use Safari.",
questions={
"bug_severity": Score(
instructions="How severe is the reported issue?",
criteria=[
"Cosmetic; no impact to functionality",
"Broken or degraded feature, but workaround exists",
"Blocking issue; no workaround exists",
],
),
},
)
print(response.answers["bug_severity"].score)运行它:
.venv/bin/python score_bug.py你应该看到:
1.431.43 落在 1 级和 2 级之间。官方对这个例子的解读:导出在 Safari 里崩了,多数客户可以用 Chrome 绕过去(1 级),但只用 Safari 的客户绕不过去(2 级)——模型在两级之间分裂,偏向 1 级。示例值可能随 Jev 版本变化,不必纠结小数点后的差异。
- 我看到了一个落在两级之间的数(示例值是 1.43)
💡 中文内容能不能打分
可以。官方说明:英语是主要训练语言、准确度最好,包括中文在内的其他语言能用但准确度较低。中文场景上线前,先用自己的数据跑一批看效果,重点关注 confidence 分布。
第 3 步:读懂返回的 score、legend 与概率分布
为什么:真实项目里分数从来不是单独用的——legend 帮你解读,probabilities 和 confidence 告诉你这个分数有多「实」。
官方示例的完整返回:
{
"model": "jev-1.13.0",
"answers": {
"bug_severity": {
"type": "score",
"score": 1.43,
"confidence": 0.35,
"legend": {
"0": "Cosmetic; no impact to functionality",
"1": "Broken or degraded feature, but workaround exists",
"2": "Blocking issue; no workaround exists"
},
"probabilities": {
"0": 0.0,
"1": 0.57,
"2": 0.43
}
}
},
"usage": {
"input_tokens": 332,
"output_tokens": 18
}
}你应该看到:答案对象里有五个字段,score 和你 print 出来的 1.43 一致,legend 把 0/1/2 映射回你写的那三条等级描述。示例里的 "model": "jev-1.13.0" 是官方录制示例时的版本;你现在用 jev-latest 跑,这个字段显示的是当前模型版本。
逐个拆:
| 字段 | 本例的值 | 怎么读 |
|---|---|---|
score | 1.43 | 0×0.0 + 1×0.57 + 2×0.43:概率加权的位置 |
legend | 0 → 外观,1 → 有替代方案,2 → 阻塞 | 级号映射回等级描述 |
probabilities | 1 级 0.57、2 级 0.43 | 模型在两级之间分裂 |
confidence | 0.35 | 概率铺在两级上,所以低 |
HTTP 返回里 legend 和 probabilities 的键是字符串 "0"/"1"/"2";Python SDK 已经把它们转成整数键(answer.legend[1]、answer.probabilities[1]),ScoreAnswer 的字段都是类型化的。
同一个问题、五条不同工单(官方文档的对照示例):
| 工单内容 | score | confidence | 概率(0/1/2 级) |
|---|---|---|---|
| 导出按钮错位了几个像素 | 0.0 | 1.0 | 1.0 / 0.0 / 0.0 |
| PDF 导出点了没反应;还能导 CSV 自己转,但很费时间 | 1.0 | 1.0 | 0.0 / 1.0 / 0.0 |
| 导出一直转圈不结束;部分同事 CSV 还能用,部分也坏了 | 1.11 | 0.84 | 0.0 / 0.89 / 0.11 |
| Safari 崩、Chrome 正常,有客户只用 Safari | 1.43 | 0.35 | 0.0 / 0.57 / 0.43 |
| 全组从今早起登不进系统,每次都 500 | 2.0 | 1.0 | 0.0 / 0.0 / 1.0 |
两个关键认识:
- 同样的分数可能来自不同的分布。 1.0 可以是「全部押 1 级」,也可以是「0 级和 2 级各一半」——分数一样,含义完全不同。所以要连着
probabilities和confidence一起读。 - confidence 1.0 描述的是分布,不是「答案正确」的保证。 分布全押一级时它是 1.0;模型分不清等级时它会掉下来。
小数 score 就是个位置:可以直接拿来排序(严重度排队);代码需要一个明确档位时,四舍五入到最近的等级再行动——搜索与匹配场景页里有「取整到最近等级」做决策的实战例子。
第 4 步:按 score 和 confidence 设阈值,自动处理还是转人工
为什么:分数要变成行动才算用起来。官方的模式:score 过阈值走自动流程;confidence 低说明模型没把握,转人工。
接着第 2 步的 response 写:
answer = response.answers["bug_severity"]
if answer.score >= 1.5:
action = "P1:立即处理"
elif answer.confidence < 0.5:
action = "转人工复核"
else:
action = "进正常队列"
print(action)你应该看到(对 Safari 那条工单):
转人工复核score 1.43 没过 1.5,confidence 0.35 又低于 0.5——模型在两级之间分裂,正是该让人看一眼的信号。
1.5 和 0.5 是示意值。官方的三档用法:高 confidence 直接自动执行;中等就确认、标记或补信息;低就不动,转人工或回退。
门槛按风险缩放:官方例子里 0.5 是兜底线,approve_transfer 这类高风险操作要 > 0.9 才无人值守执行。完整公式和示例在 Confidence 置信度 课。
第 5 步:拆成多个原子 Score 问题,在代码里加权合并
为什么:「这条工单要不要优先处理」是多维度判断——严重度、客户情绪、报告质量各占一点。官方做法:一个维度一道 Score,一次请求并行发出,代码里加权合并。改权重就是改代码,不用重调任何 prompt。
from typesafe_sdk import Score, TypeSafeClient
TRIAGE_QUESTIONS = {
"severity": Score(
instructions="How severe is the reported issue?",
criteria=[
"Cosmetic; no impact to functionality",
"Broken or degraded feature, but workaround exists",
"Blocking issue; no workaround exists",
],
),
"frustration": Score(
instructions="How frustrated is the customer?",
criteria=[
"Calm, just stating facts",
"Frustrated but civil",
"Very angry, strong language or threatening to leave",
],
),
"report_quality": Score(
instructions="How much does the report give an engineer to work with?",
criteria=[
"No detail; just says something is broken",
"Names the feature but no steps or environment",
"Steps to reproduce or environment, but not both",
"Steps to reproduce and environment",
],
),
}
def normalized(answers, question_id: str) -> float:
"""Put a score on 0 to 1 by dividing by its top level number."""
top_level = len(TRIAGE_QUESTIONS[question_id].criteria) - 1
return answers[question_id].score / top_level
def priority(ticket: str) -> float:
with TypeSafeClient() as client:
response = client.system_one(
state=ticket,
questions=TRIAGE_QUESTIONS,
)
answers = response.answers
severity = normalized(answers, "severity")
frustration = normalized(answers, "frustration")
report_quality = normalized(answers, "report_quality")
# A detailed report helps an engineer investigate, so it raises priority a little.
return 0.6 * severity + 0.3 * frustration + 0.1 * report_quality两个细节:
- 先归一化再合并。 三级量表的满分是 2,四级是 3——不归一化的话,四级题天然更重。每题除以自己的最高级号
len(criteria) - 1,全部落到 0–1,权重才有意义:权重 0.6 的 severity 恰好是 0.3 的 frustration 的两倍。 - 加题不加请求。 官方示例(就是第 3 步那条「转圈」工单加了更多上下文)返回:severity 1.24(confidence 0.64)、frustration 1.28(0.58)、report_quality 3.0(1.0);归一化后 0.62 / 0.64 / 1.0,优先级 =
0.6×0.62 + 0.3×0.64 + 0.1×1.0 = 0.66。多道题并行评估,几乎不增加响应时间,只多花一点问题 token。
你应该看到:priority() 返回一个 0–1 的数;官方示例工单算出来是 0.66。之后觉得排序不对,只调权重重跑就行;要加新维度,往 TRIAGE_QUESTIONS 里添一道题,请求数不变。
这套「拆原子分、代码加权」就是官方的 Composite scoring(组合打分)模式,完整展开在 组合打分 课。
检查点 ✅
- 我知道等级编号就是 criteria 的数组下标,从 0 开始
- 我跑出了 1.43,能手工验算:
0×0.0 + 1×0.57 + 2×0.43 - 我知道同样的分数可能来自不同分布,所以要连 probabilities 和 confidence 一起读
- 我的量表每级都是情境描述,一题只测一个维度
- 我知道多维度判断要归一化(÷ 最高级号)后再加权合并
踩坑提醒
❌ 量表里只写数字
instructions: "Rate severity from 0 to 2, where 2 is worst"
criteria: ["0", "1", "2"]
→ score 0.55, confidence 0.33, probabilities 0: 0.45, 1: 0.55, 2: 0.0官方做过这个实验:同一条「按钮错位」工单,纯数字量表打出 0.55、confidence 0.33——概率在 0、1 两级间乱分;换成三级情境描述后,score 0.0、confidence 1.0。
模型只拿描述去对照 state,「打个 1–10 分」这种问法连 Jev 自己都做不好。正确做法:每级写一个能对照的情境,也不要指望 instructions 里的数字起作用。
❌ 一道题测好几件事
等级描述写成「守时、聪明、有经验」,这道题就在同时测三样东西——一项高、一项低的输入没位置放,confidence 掉下来,score 的含义也变浑。正确做法:一件事一道 Score,结果在代码里合并(第 5 步的做法)。
❌ 拿到分数就用,不看分布
score 1.0 可能是全押 1 级(confidence 高),也可能是 0 级和 2 级各一半(confidence 低)。官方还给出了分裂位置影响 confidence 的对照:三级量表上概率 (0, 0.5, 0.5) 的 confidence 是 0.25,(0.5, 0, 0.5) 是 0——分裂在相邻两级还轻些,分裂在光谱两端更重。
正确做法:score 连着 probabilities 和 confidence 读。confidence 低通常说明等级有重叠、问题测了不止一件事、或者 state 信息不够——转人工或补信息,别硬自动执行。
❌ 罕见的极端情形没有自己的等级
情绪量表顶端是「非常愤怒」,辱骂和威胁的消息也挤在顶端附近——光看 score 分不开,而这恰恰是最需要特殊处置的消息。官方做法:给罕见极端情形单独一级,比如「非常愤怒」之上再加「辱骂或威胁」。
更多失败模式(字面理解、数数不可靠、日期比较要做在代码里)见 Jev 1.13 踩坑手册。
进阶技巧(可选)
等级可以写成对象。 如果模型总在你认为清楚的输入上打在两级之间,就把每级从字符串换成对象——一个字段说这级覆盖什么,一个字段给几个例子情形(每级的字段名保持一致):
"1": {
"what": "Broken or degraded feature, but workaround exists",
"examples": ["export fails in one browser but works in another"]
}官方用同一条 Safari 工单做过对照:纯字符串时 score 1.43、confidence 0.35;加上贴合的例子(「导出在一个浏览器失败、另一个正常」)后变成 1.03、0.96;加的例子与浏览器无关时,还是 1.43、0.35。
例子必须长得像你的真实输入才有用;confidence 变高也不等于答案对——调整等级描述后,拿另外的输入再测一遍再定稿。
不写代码先试量表。 控制台的 Playground(https://console.typesafe.ai/playground)里贴上 state、加上问题,免代码体验。
绕过 SDK 直连 API。 POST https://api.typesafe.ai/v1/systemone,score 问题的原始 JSON 长这样(官方示例):
{
"model": "jev-latest",
"state": "I was charged twice for my subscription this month. Please refund the extra charge.",
"questions": {
"urgency": {
"type": "score",
"instructions": "How urgent is this message?",
"criteria": ["Can wait", "Needs attention this week", "Needs attention today"]
}
}
}字段约束的完整定义(criteria 数组的项数上限、答案五字段)见 API 速查。
本课小结
✅ Jev Score 的用法:criteria 里定义有序量表(建议至少两级、上限 10 级),Jev 把内容放到量表上,返回五个字段。
✅ 五个字段:score(概率加权的位置,可落在两级之间)、legend、probabilities、confidence、type。
✅ 分数进代码:过阈值、排序;confidence 低转人工,不硬自动执行。
✅ 复杂判断拆成单维度 Score:归一化(÷ 最高级号)后加权合并——这就是组合打分模式。
关键配置字段回顾:
| 字段 | 推荐写法 | 说明 |
|---|---|---|
type | "score" | 固定值 |
instructions | 一句话说清评什么 | 如 How severe is the reported issue? |
criteria | 情境描述,从低到高;建议 ≥ 2 级,上限 10 级 | 级号 = 数组下标,从 0 起;一题一个维度 |
| 答案访问 | response.answers["id"].score | SDK 里 legend / probabilities 按整数级号为键 |
想看 Score 在真实场景里怎么用:搜索与匹配(用 Score 重排序、取整到最近等级);用题型组合把关内容进上下文的思路,见 RAG 段落把关。
下一课预告
光谱的另一头是干净的是非:Noul 是非题:拿到 0 到 1 的真实概率。
你会学到:
noul是 0–1 的概率,答案里没有单独的 confidence- 0.5 代表五五开,不是「中等程度」——程度要用本课的 Score 测
- 起点阈值:yes ≥ 0.7、no ≤ 0.3
- 什么时候把 Score 换成 Noul,什么时候两题一起问