Agent 工程学习站 做棵大树 出品 · beatree.cn 免费 · 无需登录 · 进度存本机
III 版 · 评测工程 第 04 章 Judging Insight
III · 评测工程 04 / 22 深入

洞察型评分与 LLM-as-Judge

Judging Insight
预计阅读 34 分钟
难度 深入
关键词 多维评分 · Rubric
本机状态 未读

「洞察好不好」能不能评?能,但前提是先把维度拆开——方向相关性、证据充分性、可操作性、表达清晰度。四维分开之后,每一维都能写出可判定的评分标准。随后的问题更棘手:怎么让机器打分可信?答案是必须先认清机器打分的四类偏差。

编辑部注 · 本章的 Rubric 设计与偏差控制是评测工程的深水区。第 1 题和第 3 题是面试中的高频追问。

办事型任务的评测有客观结果可依,洞察型任务的输出是一段分析、一份建议、一个报告。它没有唯一的正确答案,所以「好不好」看起来只能靠人判断。但「看起来只能靠人判断」不等于「无法系统化」——关键在于把模糊的总评拆成若干个可分别判断的维度。

一、把「有洞察」拆成四个维度

「这篇分析很有洞察」是一个整体印象。要让它可评,必须拆到每一维都能独立回答「是/否」的程度。

洞察型输出的四维 Rubric
维度回答什么问题5 分(优秀)3 分(合格)1 分(不合格)
方向相关性 是否回答了用户真正关心的问题? 直击核心问题,且发现了用户没明说但更重要的那个问题 回答了明确提出的问题 答非所问,或只复述了数据没有回应问题
证据充分性 每条结论是否有可核验的依据? 每个结论都有具体数据/来源支撑,且给出了量级或对比基线 主要结论有依据,个别结论为推测但已标注 结论无依据,或用了「显著」「大幅」等无量化词
可操作性 用户看完能做什么? 给出了具体动作、执行主体、判断标准,用户可直接排期 给出方向性建议,但未细化到可执行 只有现象描述,没有下一步
表达清晰度 信息是否结构化、可快速定位? 结构清晰、有摘要、长短得当、关键数字突出 结构基本清楚,篇幅略长或重点不突出 大段文字堆砌,找不到重点
四维分开评,再合成 同一个问题,两份输出的得分差异(5 分制) 输出 A 总评 4.5(可交付) 方向相关性 5 证据充分性 4 可操作性 5 表达清晰度 4 四维都高 → 可以直接交付给业务方 特征:有结论、有依据、有动作、结构清楚 输出 B 总评 3.0(不能交付) 方向相关性 4 证据充分性 3 可操作性 1 表达清晰度 4 平均分 3.0 看似「合格」,但可操作性只有 1 分 → 这类输出业务方看完不知道要做什么,实质无用 合成规则:不要简单求平均 规则一 一票否决:可操作性 < 2 分 → 总评为不合格,无论其他维度多高。    理由:洞察的最终价值在于「用户能据此行动」。没有动作的建议,写得再漂亮也没有价值。 规则二 权重差异:方向相关性权重最高(0.35),其余三维各 0.22 左右。    理由:方向错了,后面三项的努力全部作废——这是「南辕北辙」的量化表达。 警示:平均分掩盖短板。4/4/1/4 与 3/3/3/3 的平均分都是 3.0 上下,但前者实质无用,后者至少可读。
图 1 四维分开评的核心价值在于暴露短板。样本 B 的平均分看似合格,但可操作性只有 1 分——这类输出在业务上等于零价值。所以合成时必须有「一票否决」规则,不能简单求平均。

二、LLM-as-Judge:能用,但要认清它的偏差

让模型来打分是必要手段(人工成本太高),但它的四类偏差必须被系统性地处理。

机器打分的四类偏差与缓解手段
偏差表现成因缓解手段
位置偏差 在 A/B 对比中偏向先出现的那一个 注意力对前文更敏感 交换顺序跑两次,两次结论一致才采纳;不一致则标记为「平局」
长度偏差 更长、更啰嗦的回答得分更高 长度与「详尽」在训练语料里高度相关 Rubric 里明确写「简洁且信息密度高得高分」,并单独统计长度与得分的相关性
自我偏好 评审模型偏袒与自己风格相似的输出 同源模型的表达习惯一致 用不同家族/不同规模的模型做评审;关键样本用人工复核
格式偏好 结构化、带小标题、带 emoji 的输出得分更高 排版特征被当成质量信号 评分前统一格式(去掉 Markdown 装饰),或把「格式」单列一维
判断机器打分是否可信的三步校准
  1. 一致性检查:同一份输出打两次,分数差异超过 1 分的样本占比应低于 10%。超过说明 Rubric 描述不清。
  2. 与人工对齐:抽 30-50 条人工打分,计算与机器打分的相关性。同向率低于 75% 就不能直接用机器分数做决策。
  3. 反例注入:故意放入几条明显很差(如空输出、答非所问)的输出,看机器是否能给低分。给不出低分说明评分尺度整体偏松。

三、动手:可校准的评分器

insight_judge.pypython
import json, re
from dataclasses import dataclass
RUBRIC = """
你是评审员。请对下面这份分析输出按四个维度打分(1-5 的整数),
并给出理由。评分标准:
【方向相关性】5=直击核心问题且发现了用户未明说但更重要的问题;
 3=回答了明确提出的问题;1=答非所问或只复述数据。
【证据充分性】5=每个结论都有具体数据/来源,并给出量级或对比基线;
 3=主要结论有依据,个别为推测但已标注;1=结论无依据或使用无量化词。
【可操作性】5=给出具体动作、执行主体、判断标准,可直接排期;
 3=给出方向性建议但未细化;1=只有现象描述没有下一步。
【表达清晰度】5=结构清晰、有摘要、关键数字突出;3=结构基本清楚;
 1=大段文字堆砌找不到重点。
注意:
· 不要因为篇幅长而给高分,信息密度高才给高分。
· 不要因为排版漂亮而给高分,格式不计入表达清晰度之外的维度。
· 如果某维度确实无法判断,给 0 并在理由里说明。
只输出 JSON:
{"direction":n,"evidence":n,"actionable":n,"clarity":n,
 "reason":"一句话理由","blocking":"最严重的短板维度名或 null"}
"""
@dataclass
class Verdict:
    direction: int
    evidence: int
    actionable: int
    clarity: int
    reason: str
    blocking: str | None = None
    @property
    def weighted(self) -> float:
        """加权:方向相关性权重最高——方向错了,其余努力全部作废"""
        w = {"direction": 0.35, "evidence": 0.22, "actionable": 0.25, "clarity": 0.18}
        return (self.direction * w["direction"] + self.evidence * w["evidence"]
                + self.actionable * w["actionable"] + self.clarity * w["clarity"])
    def passed(self) -> bool:
        """一票否决:可操作性过低 → 直接判定不合格,不用平均分"""
        if self.actionable <= 2:
            return False
        return self.weighted >= 3.5
    def explain(self) -> str:
        return (f"方向 {self.direction} 证据 {self.evidence} "
                f"动作 {self.actionable} 表达 {self.clarity} "
                f"加权 {self.weighted:.2f} "
                f"{'通过' if self.passed() else '不通过'}"
                f"{f'(卡在 {self.blocking})' if self.blocking else ''}")
def judge(output: str, call_model) -> Verdict:
    raw = call_model(RUBRIC, output, temperature=0)
    data = parse_lenient(raw)
    return Verdict(**{k: data[k] for k in
                      ("direction", "evidence", "actionable", "clarity", "reason")},
                   blocking=data.get("blocking"))
def parse_lenient(raw: str) -> dict:
    """宽容解析:模型常把 JSON 包在代码块里,或带尾随逗号"""
    text = raw.strip()
    text = re.sub(r"^```(?:json)?|```$", "", text, flags=re.M).strip()
    text = re.sub(r",(\s*[}\]])", r"\1", text)     # 去掉尾随逗号
    if "{" in text:
        text = text[text.index("{"): text.rindex("}") + 1]
    return json.loads(text)
def judge_stable(output: str, call_model, repeats: int = 2) -> tuple[Verdict, dict]:
    """
    稳定性检查:同一份输出多次打分。
    方差大的样本不能进入自动决策 —— 它们必须转人工。
    """
    verdicts = [judge(output, call_model) for _ in range(repeats)]
    scores = [v.weighted for v in verdicts]
    spread = max(scores) - min(scores)
    meta = {
        "spread": spread,
        "reliable": spread <= 0.8,     # 分差超过 0.8 视为不可靠
        "verdicts": [v.explain() for v in verdicts],
    }
    # 取中位数(比均值更抗单次异常)
    scores_sorted = sorted(scores)
    median = scores_sorted[len(scores_sorted) // 2]
    best = min(verdicts, key=lambda v: abs(v.weighted - median))
    return best, meta
def pairwise_stable(a: str, b: str, call_model) -> dict:
    """
    两两对比必须交换顺序跑两次。
    两次结论不一致 → 判平局,而不是选一个。
    """
    first = call_model(RUBRIC + "\n请判断 A 与 B 哪个更好。", f"【A】{a}\n【B】{b}", temperature=0)
    second = call_model(RUBRIC + "\n请判断 A 与 B 哪个更好。", f"【A】{b}\n【B】{a}", temperature=0)
    # 解析出「选了谁」,交换后应指向同一个原始样本
    pick1 = "A" if "A" in first[:20] else "B"
    pick2 = "B" if "A" in second[:20] else "A"      # 第二次的位置已交换
    return {
        "consistent": pick1 == pick2,
        "winner": pick1 if pick1 == pick2 else "tie",
        "note": "两次顺序一致的结论才可采信;否则记为平局",
    }
一个必须提防的循环论证

如果用 A 模型生成洞察、又用 A 模型做评审,你会得到一组很漂亮且很一致的分数——但它是自证。这类系统在换用户之后会突然「失灵」,因为真实用户的偏好与 A 模型不一致。

要求:评审模型与生成模型不同源;并且每轮评测都要抽样人工复核,用人工结论定期校准机器结论。机器打分是用来降低人工成本的,不是用来替代人的判断的。

四、自测

本章自测第 1、3 题为高频追问
Q1为什么洞察型评分不应简单取四个维度的平均分?
C。平均分的本质缺陷是允许维度之间互相补偿。但洞察的价值结构不是可补偿的——一份方向对、证据足、但完全没说「该做什么」的分析,业务方拿到手里毫无用处。所以合成规则要包含一票否决与权重差异,而不是简单加总。
Q2「长度偏差」指的是什么,怎么缓解?
B。长度偏差是最普遍、最难察觉的一类——因为它与「详尽」在训练语料里高度相关,模型学到了这个隐含关联。缓解的关键是显式反向声明 + 量化监控:不仅要在 Rubric 里写明,还要实际统计「长度 vs 得分」的相关系数,确认没有正相关。
Q3两两对比(A vs B)时,为什么必须交换顺序各跑一次?
D。位置偏差是 LLM-as-Judge 最稳定的偏差之一——即使内容完全相同,只交换顺序,结论也可能翻转。处理方式不是「校正偏移量」,而是「用一致性做过滤」:两次一致才采信,不一致就判平局。这也顺便解决了一部分「模型本身分不清优劣」的问题。

五、小结

议题结论
维度拆分方向相关性 / 证据充分性 / 可操作性 / 表达清晰度,四维正交
打分标准每维给出 5 / 3 / 1 分的具体描述,标准要能回答「是/否」
合成规则权重差异(方向相关性最高)+ 一票否决(可操作性过低直接不合格)
四类偏差位置 / 长度 / 自我偏好 / 格式偏好,各有对应的缓解手段
可信度校准一致性检查、与人工对齐、反例注入三步
一票否决示例可操作性 < 2 分 → 不合格,不管其他维度多高
必须避免生成模型与评审模型同源(循环论证)

机器打分是用来降低人工成本的,不是用来替代人的判断的。这两件事在长期看差别巨大。本刊编辑部

下一章把前面所有测评工作接成闭环:怎么让评测真正影响线上质量,而不是变成一份没人看的报告。

面试官会怎么问

共 3 条 · 其中 2 条高频 · 先自己答一遍,再展开对照

洞察型 Agent 的"内容质量"怎么评? 高频
先把"好不好"拆成可独立判断的维度,每个维度给可操作的 rubric:
① 方向相关性——产出的分析是否落在问题上,有没有跑偏到无关角度;
② 证据充分性——结论是否有可溯源的数据支撑,还是只是合理推测;
③ 可操作性——是否给出了能落地的判断或建议,而不是正确的废话;
④ 表达清晰度——结构是否清楚、重点是否突出、有没有冗余。
每个维度用 3–5 级量表并写清每级的判定标准(rubric 的关键是让不同评分者得出接近的结果)。
最重要的设计是:维度分不是用来算总分的,而是用来做归因的——低分出现在"证据充分性",说明是检索没召回;出现在"表达清晰度",说明是提示或组织问题。只有能定位到环节,评分才有迭代价值。

追问链

  1. 维度之间高度相关怎么办?
  2. 怎么知道评分标准本身是合理的?
加分点:"维度分用于归因而非总分"这一点,是评判体系设计成熟度的标志。
LLM-as-Judge 有哪些偏差?怎么控制? 高频
四类主要偏差与对策:
① 位置偏差——倾向给排在前面的答案更高分。对策:交换顺序各评一次,取一致结论;不一致就判为平局或人工介入。
② 长度偏差——倾向给更长、更"全面"的回答高分。对策:rubric 里显式区分"信息量"与"篇幅",加一条"冗余扣分";或对长度做归一化后再比较。
③ 自我偏好——偏爱自己(同族模型)生成的文本。对策:用不同模型评判,或至少做交叉验证;关键评测用人工校准。
④ 格式/表述偏差——被排版、markdown 结构、自信的语气影响。对策:rubric 明确只看内容不看形式,或统一后处理格式再评。
此外必须有人工抽检校准:定期抽一批让真人评,与机器评分比对,一致率下降就说明评判标准漂了,要回去修 rubric。
加分点:"把机器评分与人工抽检的一致率作为监控指标"——这个做法能让面试官确认你不是在空谈。
为什么不能只看平均分?
因为平均分掩盖分布,而工程风险几乎全在尾部。
三种典型情况:① 平均分涨了但关键场景崩了(比如回答变得很长,平均分因信息量提升而上涨,但简短咨询类场景全部变糟);② 平均分不动但方差变大(一端显著变好、另一端显著变差,稳定性实际下降);
③ 高分样本挤占(某些原本满分的场景现在稳定扣一点分,被其他场景的涨幅掩盖)。
所以指标要成组看:均值 + 分位数(P5/P95)+ 关键场景单独看 + 最差类别。我在实践中会额外维护一份"绝不能退化的场景清单",无论平均分怎么涨,这些场景退化就是不能上线。
答这类题的通用结构

结论先行(一句话给出取舍)→ 机制(为什么是这样,涉及哪条链路)→ 代价或边界(这么做放弃了什么)→ 你的实践或数字(真实场景里怎么落地)。 只讲机制不讲代价,是背题;只讲取舍没有数字,是空谈。

本章收尾 · Wrap up
掌握度自评
点一下给自己打分;低于 3 分建议加入复习队列
个人笔记 · Notes