6.3 评分与复合打分


6.3 评分与复合打分

本节摘要:评分模式的铁律:一个 Score 只测一个维度——混维度的"综合分"等级描述必然自相矛盾,是新手第一大坑。正确姿势是复合评分(composite scoring):把"严重度、影响面、紧急度"各做成一个单维 Score/Noul,一次请求并行求值,然后在代码里按业务权重加权合成。模型负责单维度落位(它擅长的语义判断),权重与组合留在代码里(可审计、可调参、可回归测试)。本节内嵌完整的故障优先级脚本:两个 Score 加一个 Noul,加权合成 0~4 的复合分,再按阈值分级动作。

学习目标

阅读完本节,你应当能够:

  1. 解释"一个 Score 混多维度"为什么必然失败。
  2. 按复合评分模式拆解一个综合判断需求。
  3. 运行内嵌的复合评分脚本并调整权重。

一、为什么综合分必须拆

试着给"严重性和影响面综合分"写等级 2 的描述:

"比较严重,或者影响面比较大,或者都比较中等……" ❌

两个维度混在一条标尺上,等级描述只能写成模糊的折中——模型没有稳定的落位依据,回归集也无法判定对错("严重但影响小"到底算 2 还是 3?)。维度拆开后,每个等级都能写成具体情形(第 3.3 节准则一),每张标尺都可独立测试。

二、复合评分模式

state ──┬──> Score: severity (多严重?5 级) ├──> Score: blast_radius (波及多广?5 级) ├──> Noul: urgency (要求立即处理吗?) │ ↑ 三问并行,一次请求返回(第 5.1 节) ▼ 代码加权:composite = 0.5×(4−sev) + 0.3×(4−blast) + 0.2×urgent ▼ 阈值分级:≥3.0 拉响 P1 / ≥1.5 当日处理 / 其余常规

权重的三个来源(都比"让模型给综合分"好):业务约定(SLA 定义)、历史数据的回归拟合、事后校准(第 9.3 节调的就是这些数)。权重改动只碰代码——不重跑模型、不重跑回归集(回归集守护的是每张单维标尺)。

三、完整实现

以下脚本即本教程的 03_score_composite_severity.py,完整内嵌于此:

# 03_score_composite_severity.py —— 多维评分 + 代码加权复合 import os import sys import requests API_URL = "https://api.typesafe.ai/v1/systemone" # 一次请求问完所有维度(并行求值,见第 5.1 节"投机性扇出") QUESTIONS = { # Score:criteria 是"有序"等级数组,等级 0 最严重;每级描述具体情形而非程度词 "severity": { "type": "score", "instructions": "评估该线上故障报告的影响严重度", "criteria": [ "核心功能完全不可用,且没有任何绕过办法", "核心功能受损,但存在临时绕过办法", "次要功能异常,核心功能完好", "仅界面或文案瑕疵,功能完好", "无实际问题", ], }, "blast_radius": { "type": "score", "instructions": "评估该故障波及的用户范围", "criteria": [ "全部用户受影响", "多数用户受影响", "部分用户受影响", "个别用户受影响", "未波及任何用户", ], }, "urgency": { "type": "noul", "instructions": "报告的措辞明确要求立即处理(如 on-call、现在、马上)", }, } # 权重是你的业务知识 —— 不要外包给模型 W_SEVERITY, W_BLAST, W_URGENCY = 0.5, 0.3, 0.2 def evaluate(incident: dict) -> float: resp = requests.post( API_URL, headers={"Authorization": f"Bearer {os.environ['TYPESAFE_API_KEY']}"}, json={"model": "jev-latest", "state": incident, "questions": QUESTIONS}, timeout=10, ) resp.raise_for_status() a = resp.json()["answers"] sev = a["severity"]["score"] # 0(最严重)~4(无问题),概率加权的连续值 blast = a["blast_radius"]["score"] # 同上 urgent = a["urgency"]["noul"] # 0~1 # 等级越小越严重,统一换算成"越大越要紧"再加权 composite = ( W_SEVERITY * (len(QUESTIONS["severity"]["criteria"]) - 1 - sev) + W_BLAST * (len(QUESTIONS["blast_radius"]["criteria"]) - 1 - blast) + W_URGENCY * urgent ) print(f" severity={sev:.2f} blast={blast:.2f} urgency={urgent:.2f}" f" -> 复合优先级 {composite:.2f}/4.0") return composite def main() -> None: if not os.environ.get("TYPESAFE_API_KEY"): sys.exit("请先设置环境变量 TYPESAFE_API_KEY") incidents = [ {"title": "支付页全白", "report": "PC 和 App 支付页面全部打不开,无法下单,客服电话被打爆"}, {"title": "导出按钮歪了", "report": "报表导出按钮图标错位了几像素,功能本身正常"}, {"title": "搜索偶发超时", "report": "约一成用户搜索要等 10 秒,可以刷新重试,麻烦尽快看看"}, ] for inc in incidents: print(f"\n故障:{inc['title']}") score = evaluate(inc) if score >= 3.0: print(" 动作 -> 立刻拉响 P1 告警") elif score >= 1.5: print(" 动作 -> 进入当日处理队列") else: print(" 动作 -> 排入常规迭代") if __name__ == "__main__": main()

读代码的四个要点:

  1. state 用对象{"title": ..., "report": ...})——比揉成一句话稳(第 8.1 节);
  2. 三问一次请求——QUESTIONS 里三个问题并行求值,延迟≈问一个;
  3. 方向翻转在代码里——4 - sev 把"0=最严重"翻成"大=要紧",标尺方向不动、语义翻转显式可见;
  4. 权重集中常量——调权即改三行,不碰请求、不碰回归集。

💡 想加第四个维度?(如"是否在高峰时段"——但注意时段该由代码算,第 10.1 节)加一个 Noul 进 QUESTIONS、加一个权重——复合模式的扩展是线性的,综合大 prompt 的扩展是灾难性的。

四、适用边界

场景 复合评分合适吗
内容风险分级(暴力/色情/诈骗多维) ✅ 各维一个 Noul/Score,加权出总风险
线索质量打分(意向/预算/时间线) ✅ 经典组合
RAG 检索相关性 ✅ 单维 Score 即可,无需复合
"这条线索值多少钱" ❌ 开放数值,先改档位 Choice(第 2.2 节)

本节要点回顾

  1. 铁律:一个 Score 一个维度;混维度 = 等级描述自相矛盾 = 不可回归测试。
  2. 模式:单维 Score×K + 代码加权;权重是业务知识,改动不碰请求与回归集。
  3. 实现:内嵌脚本三问并行、方向翻转显式、权重集中常量——可直接跑、可直接改。

评分输出的是"每个候选的分",把多个候选按同一把标尺打分再排序——就是下一章的第一个模式:排名。


作者与出处
原作者: 灏天文库
整理: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天文库 转发
评论区 (0)
U