让 AI 当裁判——LLM Judge 语义评测进阶(规则查不到的「答非所问」,交给 AI 二审)

70 阅读20分钟

系列:AgentScope 2.0 学习笔记 · 第 011 篇

难度:进阶

适合谁:做 AI 客服/导购的开发者,以及给 Agent 做语义质检的人——被「答非所问但查不出毛病」困扰的团队

前置:建议先读 010《给 Agent 打个分——评测体系入门》

阅读收获:把「规则打不到的分」,交给一个轻模型当裁判去补上,同时守住成本红线

运行环境:WSL Ubuntu-24.04 + Python 3.11+(mock 模式零依赖零 Key;live 模式需 DEEPSEEK_API_KEY)


做 AI 客服,还有比「答错价」更阴的坑吗?有——「答非所问」,还偏偏挑不出毛病。

用户问「积雪草精华适合什么肤质」,客服回「积雪草精华主打美白淡斑,敏感肌用之前建议先做皮试」。态度挺好,成分也提了,唯独没回答人家的问题:到底适合什么肤质?你把它放上线,用户只觉得这客服「答了跟没答一样」,气都生不出来。

最麻烦的是,这种错规则质检根本查不出:价格没编、引用没错、工具没漏、关键词「敏感」也命中了——四维全满分,直接 PASS。010 篇那把「质检尺」抓「9 元买 268 元面霜」这种硬伤很在行,可「驴唇不对马嘴」这种软伤,靠 if 写不出来。

要抓它,得请一个会读语义的裁判。这一篇,我们就让 AI 来当这个裁判。


一、010 之后,规则打分的天花板

上一篇我们搭起了评测体系的地基:把「答得好不好」拆成忠实度 / 引用 / 工具 / 护栏四个维度,每个 0/1,规则打分、幻觉一票否决。

但四个月下来你很快会撞到一面墙:规则只能查「确定性」的错误,查不了「语义」的问题。

想想看,规则怎么判断下面这条回答好不好?

用户:「积雪草精华适合什么肤质?」 客服:「积雪草精华主打美白淡斑,敏感肌用之前建议先做皮试。」

规则一查:关键词「敏感」在、引用「敏感」在、没漏调工具、意图也对了——四个维度全满分,PASS。可你一眼就看出,这回答答非所问:人家问「适合什么肤质」,它绕弯子讲「美白淡斑」,核心问题一个没答。

规则抓得住「9 元买 268 元面霜」这种硬伤,抓不住「驴唇不对马嘴」这种软伤。因为后者不是「对错」,是「好坏」——好坏没法用 if 写出来。

所以我们需要一个「会读语义」的裁判。这就是** LLM Judge**:让一个大模型,去给另一个模型的回答打语义分。


二、让 AI 当裁判,怎么当才靠谱

让 AI 当裁判,最怕两件事:一是它不老实(给你一篇散文而不是一个分数),二是它不稳定(同一句话今天打 0.9 明天打 0.3)。

解法是一张「打分卡」。我们给裁判一个固定模板,逼它只吐 JSON:

你是评测裁判。根据用户问题与客服回答,评估回答质量。
只输出一个 JSON,不要任何解释,格式:
{"relevance":0到1, "hallucination":0到1, "completeness":0到1, "score":0到1}

三个关键设计:

  1. 只要 JSON,不要解释——方便程序直接 json.loads 解析,不用从散文里抠数字。
  2. temperature=0——关掉随机性,同一份卷子它打的分数基本一致,评测才可复现。
  3. 解析失败就记 0 分——宁可错杀,不能让坏样本因为「裁判没回 JSON」就溜过去。

裁判打四个分,我们逐一拆:

维度问的是方向
relevance 相关性切没切题?越高越好
hallucination 幻觉胡没胡编?越高越差
completeness 完整性解没解决问题?越高越好
score 综合分最终质量越高越好

注意看表格里有个反直觉的:hallucination 幻觉分是反向的——越高越差。这是最容易踩的坑。很多新手一看到「幻觉分 0.9」以为是优秀,其实那是「九成在胡说」。务必和 score 区分开。


三、成本红线:规则先行,LLM 兜底

现在有个现实问题:LLM Judge 要花钱。每请裁判打一次分,就是一次 API 调用。一个评测集几千条样本,全量过一遍 LLM,账单够你喝一壶。

回想一下这个系列的省钱哲学——008 篇路由、009 篇投票、010 篇规则打分,全都是同一个味道:便宜的先上,贵的兜底。 这篇也不例外,落地成一个开关:

judge:
  enabled: true
  only_on_rule_fail: true   # 仅对规则未满分样本触发 LLM,控制成本

only_on_rule_fail: true 的意思是:规则先跑一遍,满分的直接放行,一分钱 LLM 不花;只有规则揪出问题的样本,才花一次 LLM 的钱做「二审」。

为什么这样是安全的?因为规则满分 = 没有确定性硬伤(没编造、没漏调、没越界)。剩下的疑问只是「语义好不好」,而语义问题大多藏在「规则没满分的样本」里——要么漏调了工具,要么关键词对不上,本身就可疑。先让免费的规则把「可疑分子」筛出来,再让贵的裁判只审这批可疑分子,钱就花在刀刃上了。

本篇 demo 里 5 条样本,3 条规则满分直接放行,只有 2 条进了 LLM 二审——60% 的样本没花 LLM 的钱。


四、省钱是有代价的:only_on_rule_fail 的盲区

上面这套方案看着很美,但有个必须讲透的代价——「规则满分但答非所问」的样本会漏网。

回到开篇那条「积雪草精华」的回答:它规则全满分,于是被直接放行;又因为 only_on_rule_fail 只在「规则未满分」时才调 LLM,它根本没进裁判的抽检范围,答非所问就这么溜过去了。

这正是 demo 里第 4 条故意埋的「陷阱」样本——你看输出,它照样 ✅ 放行。

这就是「省钱」的代价。生产上有三条路可选,是个明摆着的权衡:

  • only_on_rule_fail: true(最省):只审规则未满分样本,但「规则满分却答非所问」会漏。
  • 全量走 LLM(最贵):一条不落,语义问题全抓,账单也最狠。
  • 折中(推荐):规则满分样本抽样 5% 走 LLM,既守住大部分语义质量,成本只涨一点点。

没有标准答案,看你的场景对「漏网」的容忍度。关键是知道这个盲区存在,而不是用了 only_on_rule_fail 就以为万无一失。


五、运行环境

  • 系统:WSL Ubuntu-24.04
  • Python:3.11+(无需虚拟环境、无需任何第三方库)
  • 依赖:纯标准库(urllib 直接调接口,不需要 openai 包)
  • API Key:mock 模式不需要;live 模式需设置 DEEPSEEK_API_KEY 环境变量
wsl -d Ubuntu-24.04
cd /2026_Study/agentscope/second/   # 或任意目录,脚本不挑地方

# mock 模式(离线,验证控制流,推荐先跑这个)
python 011_llm_judge.py

# live 模式(真实调 DeepSeek 当裁判)
export DEEPSEEK_API_KEY=sk-xxxx
python 011_llm_judge.py --live

六、完整代码(单文件自包含)

保存为 011_llm_judge.py。规则打分器(四个确定性维度)+ LLM Judge(mock/live 双模式)+ 主流程(规则先行、LLM 兜底、成本统计),最后用 5 条 canned 样例演示控制流,其中故意埋了一条「规则满分却答非所问」的陷阱。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
AgentScope 2.0 · 让 AI 当裁判——LLM Judge 语义评测进阶
========================================================
接 010 篇《评测体系入门》:规则打分只能查「确定性错误」(价格编造 / 引用越界 /
工具漏调),查不了「答非所问」「废话连篇」这类语义质量问题。

本篇补上「LLM Judge」:请一个轻模型当裁判,对规则没满分的样本做语义二审。
核心是「规则先行、LLM 兜底」的成本红线——规则满分的直接放行,不花一分钱;
只有规则揪出问题的样本,才花一次 LLM 的钱做「二审」。

双模式:
  mock 模式(默认,离线):用一个「假裁判」替代真实 LLM,验证控制流,零依赖零 Key。
  live 模式(真实调 DeepSeek):需要 DEEPSEEK_API_KEY 环境变量 + 网络。

运行命令:
  python 011_llm_judge.py            # mock 模式,离线
  python 011_llm_judge.py --live     # live 模式,真实调 DeepSeek

运行环境:WSL Ubuntu-24.04 + Python 3.11+(纯标准库,无第三方依赖)
"""
import json
import os
import sys
import urllib.request

# ───────── ① 规则打分器:确定性匹配,零成本、可复现 ─────────
# 这四个维度全部是「布尔判断题」,跑一万遍结果都一样,一分钱不花。
# 它们对应 010 篇的四维度思想,只是按 P1_QA 的命名重新组织:
#   意图路由 / 工具调用 / 引用检索 / 关键词命中


def rule_score(case, actual):
    """对一条实际输出做规则打分,返回各维度是否达标(bool)。

    case   标准答案:{expected_role, expected_tools, expected_refs, answer_keywords}
    actual 实际输出:{role, answer, tools, citations}

    规则是「弱判定」:某维度若标准答案里没要求(expected 为空),直接算通过,
    不冤枉被测系统。
    """
    out = {}

    # ① 意图路由准确率:期望的 agent 角色是否命中
    if case.get("expected_role"):
        out["intent_ok"] = (actual.get("role") == case["expected_role"])

    # ② 工具调用准确率:期望工具必须全部被调用(漏调一个即失败)
    actual_tools = set(actual.get("tools", []))
    expected_tools = set(case.get("expected_tools", []))
    out["tool_ok"] = expected_tools.issubset(actual_tools) if expected_tools else True

    # ③ 引用/检索准确率:期望引用的关键词需出现在 citations 或 answer 里
    hay = " ".join(actual.get("citations", [])) + " " + (actual.get("answer") or "")
    out["ref_ok"] = (
        all(kw in hay for kw in case["expected_refs"])
        if case.get("expected_refs") else True
    )

    # ④ 关键词命中(端到端解决率的辅助信号):回答里要出现关键信息词
    out["keyword_ok"] = (
        all(kw in (actual.get("answer") or "") for kw in case["answer_keywords"])
        if case.get("answer_keywords") else True
    )
    return out


def rule_all_pass(rule_result):
    """规则是否「全部维度满分」。满分才不需要 LLM Judge,这是省钱的关键。"""
    return all(rule_result.values())


# ───────── ② LLM Judge:对规则未满分样本做语义二审 ─────────
# 裁判打四个语义分(0~1):
#   relevance     相关性   :是否切题
#   hallucination 幻觉     :是否胡编(注意:越高越差!)
#   completeness  完整性   :是否真正解决用户问题
#   score         综合质量分:由上面三个汇总的最终分


JUDGE_PROMPT = (
    "你是评测裁判。根据用户问题与客服回答,评估回答质量。\n"
    "只输出一个 JSON,不要任何解释,格式:\n"
    '{"relevance":0到1, "hallucination":0到1, "completeness":0到1, "score":0到1}\n'
    "用户问题:{query}\n"
    "客服回答:{answer}\n"
    "说明:relevance=是否切题;hallucination=是否胡编(越高越差);"
    "completeness=是否解决用户问题;score=综合质量分。"
)


def mock_judge(case, actual):
    """假裁判(mock 模式):离线演示「控制流」,不真的调用模型。

    真实语义判断是 live 模式的活;这里固定返回一个「看起来像裁判打的分」,
    目的是让读者看清:哪条样本触发了 LLM 二审、哪条被规则直接放行。
    """
    return {
        "relevance": 0.88,
        "hallucination": 0.10,
        "completeness": 0.85,
        "score": 0.86,
        "_mock": True,
    }


def llm_judge_live(case, actual, api_key,
                   base_url="https://api.deepseek.com/chat/completions",
                   model="deepseek-chat"):
    """真裁判(live 模式):用 urllib 调 DeepSeek 的 OpenAI 兼容接口。

    temperature=0.0 保证输出稳定;max_tokens=200 足够返回一段 JSON。
    全程只依赖标准库,不需要 openai 包。
    """
    prompt = JUDGE_PROMPT.format(query=case.get("query", ""),
                                 answer=actual.get("answer", ""))
    body = {
        "model": model,
        "messages": [{"role": "user", "content": prompt}],
        "temperature": 0.0,
        "max_tokens": 200,
    }
    req = urllib.request.Request(
        base_url,
        data=json.dumps(body).encode("utf-8"),
        headers={
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json",
        },
    )
    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            data = json.loads(resp.read().decode("utf-8"))
        content = data["choices"][0]["message"]["content"]
        # 模型偶尔会在 JSON 外面套 ```json ... ``` 围栏,剥掉
        content = content.strip().strip("`")
        if content.lower().startswith("json"):
            content = content[4:].strip()
        parsed = json.loads(content)
        parsed.setdefault("score", 0.0)
        return parsed
    except Exception as e:
        # 网络失败 / JSON 解析失败:宁可记 0 分(错杀),也不能让坏样本溜过去
        return {
            "relevance": 0.0, "hallucination": 1.0, "completeness": 0.0,
            "score": 0.0, "parse_error": str(e),
        }


# ───────── ③ 主流程:规则先行 + LLM 兜底 + 成本统计 ─────────

def evaluate(cases, mode="mock", api_key=None, quality_threshold=0.85):
    """跑一批 (case, actual) 样例,输出逐条判定 + 汇总报告。

    cases : [(case, actual), ...] 每个 case 是标准答案、actual 是实际输出。
    mode  : "mock"(离线)或 "live"(调 DeepSeek)。
    """
    stats = {
        "total": 0,         # 样本总数
        "rule_pass": 0,     # 规则直接放行的条数
        "llm_called": 0,    # 触发 LLM 二审的条数
        "llm_skipped": 0,   # 被规则放行、省下 LLM 调用的条数
        "llm_fail": 0,      # LLM 二审后仍不达标的条数
    }

    print("=" * 64)
    print("  LLM Judge 语义评测(规则先行 + LLM 兜底)")
    print(f"  模式:{'mock 离线假裁判' if mode == 'mock' else 'live 真实调 DeepSeek'}")
    print("=" * 64)

    for i, item in enumerate(cases, 1):
        # 每条样例允许是 (case, actual) 或 (case, actual, note) 三元组
        case, actual = item[0], item[1]
        note = item[2] if len(item) > 2 else None
        stats["total"] += 1
        rules = rule_score(case, actual)
        print(f"\n[{i}] {case.get('query', '')}")
        print(f"    规则打分:{rules}")
        if note:
            print(f"    {note}")

        if rule_all_pass(rules):
            # 规则满分 → 直接放行,不花 LLM 的钱
            stats["rule_pass"] += 1
            stats["llm_skipped"] += 1
            print("    → ✅ 规则满分,跳过 LLM(省 1 次调用)")
            continue

        # 规则未满分 → 触发 LLM Judge 二审
        stats["llm_called"] += 1
        print("    → ⚠️ 规则未满分,触发 LLM Judge 二审")
        if mode == "live":
            judge = llm_judge_live(case, actual, api_key)
        else:
            judge = mock_judge(case, actual)
        tag = "(mock)" if judge.get("_mock") else ""
        print(f"    → 裁判{tag}打语义分:relevance={judge['relevance']} "
              f"hallucination={judge['hallucination']} "
              f"completeness={judge['completeness']} score={judge['score']}")
        if judge["score"] >= quality_threshold:
            print(f"    → ✅ 综合分 {judge['score']} ≥ {quality_threshold},达标")
        else:
            stats["llm_fail"] += 1
            print(f"    → ❌ 综合分 {judge['score']} < {quality_threshold},不达标")

    # ───────── 汇总报告 ─────────
    print("\n" + "-" * 64)
    print("  汇总报告")
    print(f"    样本总数:{stats['total']}")
    print(f"    规则直接放行:{stats['rule_pass']}(省 {stats['llm_skipped']} 次 LLM 调用)")
    print(f"    LLM 二审:{stats['llm_called']} 次(其中不达标 {stats['llm_fail']} 条)")
    if stats["llm_called"]:
        save = stats["llm_skipped"] / stats["total"] * 100
        print(f"    成本节省:{save:.0f}% 的样本没花 LLM 的钱(被规则直接放行)")
    print("-" * 64)


# ───────── ④ demo:一批 canned 样例,演示控制流 + 一个陷阱 ─────────

def demo(mode="mock"):
    # 5 条样例:(标准答案 case, 实际输出 actual, 教学注释 note)
    # 设计意图:c001/c003 规则满分(跳过 LLM);c002/c005 规则未满分(触发 LLM);
    #          c004 是「陷阱」——规则满分却答非所问,展示 only_on_rule_fail 的盲区。
    samples = [
        # c001 规则满分:工具、关键词都对 → 跳过 LLM
        (
            {"query": "这款面霜多少钱",
             "expected_role": "presale", "expected_tools": ["query_price"],
             "expected_refs": [], "answer_keywords": ["元", "价格"]},
            {"role": "presale", "tools": ["query_price"],
             "answer": "玻尿酸保湿霜 268 元,价格实惠", "citations": []},
            None,
        ),
        # c002 规则未满分:漏调 query_order → 触发 LLM 二审
        (
            {"query": "我的订单 AS-001 到哪了",
             "expected_role": "aftersale", "expected_tools": ["query_order"],
             "expected_refs": ["订单"], "answer_keywords": ["物流", "状态"]},
            {"role": "aftersale", "tools": [],
             "answer": "您的订单已发货,物流状态正常", "citations": ["订单 AS-001"]},
            None,
        ),
        # c003 规则满分:引用、关键词都对 → 跳过 LLM
        (
            {"query": "你们支持哪些支付方式",
             "expected_role": "presale", "expected_tools": [],
             "expected_refs": ["支付"], "answer_keywords": ["微信", "支付宝"]},
            {"role": "presale", "tools": [],
             "answer": "支持微信支付和支付宝,也可以用银行卡", "citations": ["支付方式说明"]},
            None,
        ),
        # c004 陷阱:规则满分,但答非所问(问肤质,却在讲美白淡斑)
        (
            {"query": "积雪草精华适合什么肤质",
             "expected_role": "presale", "expected_tools": [],
             "expected_refs": ["敏感"], "answer_keywords": ["敏感"]},
            {"role": "presale", "tools": [],
             "answer": "积雪草精华主打美白淡斑,敏感肌用之前建议先做皮试",
             "citations": ["积雪草精华适合敏感肌"]},
            "⚠️ 陷阱:规则满分,但实际「答非所问」——只绕弯说美白淡斑,没正面回答适合什么肤质",
        ),
        # c005 规则未满分:引用关键词「切分」缺失 + 关键词「chunk/窗口」不在 → 触发 LLM
        (
            {"query": "RAG 怎么切分文本",
             "expected_role": "tech", "expected_tools": [],
             "expected_refs": ["切分"], "answer_keywords": ["chunk", "窗口"]},
            {"role": "tech", "tools": [],
             "answer": "把长文档按语义边界切成小块", "citations": ["RAG 基础"]},
            None,
        ),
    ]

    evaluate(samples, mode=mode,
             api_key=os.environ.get("DEEPSEEK_API_KEY"))

    # 陷阱样本的盲区说明(只在 mock/live 跑完后统一点破一次)
    print("\n  关键点:")
    print("    ① c001/c003 规则满分 → 直接放行,一分钱 LLM 没花。")
    print("    ② c002/c005 规则未满分 → 触发 LLM 二审,把语义质量补上。")
    print("    ③ c004 是「规则满分却答非所问」的盲区:")
    print("       only_on_rule_fail 模式下它被规则放行、也没进 LLM 抽检,")
    print("       语义问题漏网。这就是「省钱」的代价——生产要么全量走 LLM(贵),")
    print("       要么对规则满分样本做 5% 抽样二审(折中)。")
    print("    ④ 幻觉分 hallucination 是反向的:越高越差,别和 score 搞混。")
    print("=" * 64)


if __name__ == "__main__":
    mode = "live" if "--live" in sys.argv else "mock"
    demo(mode=mode)

七、代码拆解:三个关键点

① 规则是「弱判定」,不该扣的分不扣。 rule_score 里每个维度都先看标准答案里有没有要求——expected_tools 为空就不查工具、expected_refs 为空就不查引用。评测最怕「一刀切」,把没要求的分也扣了,分数就没了公信力。这和 010 篇 need_cite 的「该不该查引用」是同一套心法。

② LLM Judge 的稳,靠「只要 JSON + temperature=0 + 失败兜底」。 裁判的 prompt 死死框住输出格式;temperature=0 关掉随机性;try/except 里解析失败就返回「全 0 分 + parse_error」——让坏样本宁可被错杀,也不能因为裁判没回 JSON 而溜过去。三招合起来,AI 裁判才敢真正上线。

③ 成本控制是显式统计的,不是嘴上说说。 evaluate 里专门埋了 llm_skipped 计数器,汇总时打出「省了多少次调用、省了百分之多少」。省不省钱不是感觉,是数字。这套「规则先行、LLM 兜底」和 008 路由、009 投票、010 规则打分是同一根成本红线贯穿下来的。


八、运行结果(mock 模式真实输出)

以下为 mock 模式真实运行输出(WSL Ubuntu-24.04 + Python 3.14(venv)实跑;脚本纯标准库、离线无 API,任意 Python 3.11+ 环境输出完全一致):

================================================================
  LLM Judge 语义评测(规则先行 + LLM 兜底)
  模式:mock 离线假裁判
================================================================

[1] 这款面霜多少钱
    规则打分:{'intent_ok': True, 'tool_ok': True, 'ref_ok': True, 'keyword_ok': True}
    → ✅ 规则满分,跳过 LLM(省 1 次调用)

[2] 我的订单 AS-001 到哪了
    规则打分:{'intent_ok': True, 'tool_ok': False, 'ref_ok': True, 'keyword_ok': True}
    → ⚠️ 规则未满分,触发 LLM Judge 二审
    → 裁判(mock)打语义分:relevance=0.88 hallucination=0.1 completeness=0.85 score=0.86
    → ✅ 综合分 0.86 ≥ 0.85,达标

[3] 你们支持哪些支付方式
    规则打分:{'intent_ok': True, 'tool_ok': True, 'ref_ok': True, 'keyword_ok': True}
    → ✅ 规则满分,跳过 LLM(省 1 次调用)

[4] 积雪草精华适合什么肤质
    规则打分:{'intent_ok': True, 'tool_ok': True, 'ref_ok': True, 'keyword_ok': True}
    ⚠️ 陷阱:规则满分,但实际「答非所问」——只绕弯说美白淡斑,没正面回答适合什么肤质
    → ✅ 规则满分,跳过 LLM(省 1 次调用)

[5] RAG 怎么切分文本
    规则打分:{'intent_ok': True, 'tool_ok': True, 'ref_ok': False, 'keyword_ok': False}
    → ⚠️ 规则未满分,触发 LLM Judge 二审
    → 裁判(mock)打语义分:relevance=0.88 hallucination=0.1 completeness=0.85 score=0.86
    → ✅ 综合分 0.86 ≥ 0.85,达标

----------------------------------------------------------------
  汇总报告
    样本总数:5
    规则直接放行:3(省 3 次 LLM 调用)
    LLM 二审:2 次(其中不达标 0 条)
    成本节省:60% 的样本没花 LLM 的钱(被规则直接放行)
----------------------------------------------------------------

  关键点:
    ① c001/c003 规则满分 → 直接放行,一分钱 LLM 没花。
    ② c002/c005 规则未满分 → 触发 LLM 二审,把语义质量补上。
    ③ c004 是「规则满分却答非所问」的盲区:
       only_on_rule_fail 模式下它被规则放行、也没进 LLM 抽检,
       语义问题漏网。这就是「省钱」的代价——生产要么全量走 LLM(贵),
       要么对规则满分样本做 5% 抽样二审(折中)。
    ④ 幻觉分 hallucination 是反向的:越高越差,别和 score 搞混。
================================================================

这份输出里,最值得盯着看的是第 4 条——它规则满分、被放行,可实际上答非所问。这就是全文想让你记住的那句话:only_on_rule_fail 省钱,但「规则满分却答非所问」的样本会漏网,生产上要么全量走 LLM,要么对满分样本抽样二审。

mock 模式验证的是「控制流」对不对(谁触发 LLM、谁跳过、省了多少次)。要验证「语义判断力」,得跑 live 模式让 DeepSeek 真当裁判——它会给出真实的 relevance/hallucination 分数,而不是 mock 的固定值。

这也是我给项目做质检的固定顺序:先用 mock 把流程跑顺、把样例攒够,确认控制流没毛病,再切 live 让模型真当裁判——离线阶段一分钱不花,临上线才花钱买「真判断」。省钱不是目的,把钱花在该花的地方才是。


九、总结与下一步

这一篇,你在评测体系上又补了一块:

规则打分(010)= 查确定性错误,零成本
LLM Judge(本篇)= 补语义质量,规则先行、LLM 兜底

核心就两句:规则能查的用规则(免费),规则查不了的交给 LLM 当裁判(花钱),只对规则未满分的样本花这份钱。 以及那句必须刻进脑子里的提醒——幻觉分 hallucination 是反向的,越高越差;only_on_rule_fail 有盲区,别以为万无一失。

到这一篇,评测体系这条线完整了:四维度打分、软硬一票否决、LLM 语义二审、成本控制,四样齐了。下一篇我们该把视角拉回「怎么让 Agent 干得更好」——预告《AgentScope 2.0 学习笔记:从评测到进化——把评测结果喂回 Prompt》。敬请期待。


十、写在最后:评测不是终点,是 Agent 进化的方向盘

写到最后,想把这套「规则 + LLM 裁判」的双层质检为什么值,再往透里说一层。

给 Agent 做质检,难的不是写规则、不是调裁判,而是让评测结果有人信。你自己知道模型换过、提示词改过,可怎么证明改完变好了?一份报告拍出来:规则通过率、LLM 语义分、省了多少次调用——数字不会撒谎,客户看完心里有底,团队改代码也有了方向。这也是我判断「要不要搭评测」的标准:改完 Agent,你能不能拿出比上次更好的分数? 拿不出,改动就只是「感觉」。

到 010、011 这两篇,评测的四件套齐了:四维打分、一票否决、LLM 二审、成本控制。这套框架我在自己做的护肤品类 AI 导购项目里一直在用——上线前跑评测、改完提示词重跑评测,报告直接当交付物给客户。如果你正在做 AI 客服、导购这类面向真实用户的 Agent,卡在「裁判的 prompt 怎么写才不跑偏」「幻觉分反向怎么跟团队讲清楚」「满分样本的 5% 抽样怎么定」这些细节上,欢迎来评论区讨论。下一篇「把评测结果喂回 Prompt」见。


本文为「AgentScope 2.0 学习笔记」系列第 011 篇,代码已通过 py_compile 语法校验,运行环境见第五节。

GitHub 仓库

系列 : 《AgentScope 2.0 学习笔记》