Skip to content

评测与可观测:如何证明它变好了 ​

这一篇决定你是「在优化」还是「在瞎改」。

一、为什么 AI 应用必须自建评测 ​

传统软件AI 应用
输入确定 → 输出确定同输入可能不同输出
单元测试断言相等无法断言字符串相等
覆盖率可度量「语义正确」难以度量
回归 = 跑测试回归 = 跑评测集 + 人工抽检

没有评测集的 AI 项目,本质上是在靠感觉开车。

二、评测金字塔 ​

层内容成本频率
L1 单点断言格式合法、必含字段、禁止词极低每次提交
L2 离线集100–500 条带期望的用例中每次改动
L3 人工评审抽样盲评打分高每次发版
L4 在线指标采纳率、任务成功率、留存低(需埋点)持续

L1 + L2 是底线,缺了就不用谈优化。

三、建一个真正能用的评测集 ​

四类样本(缺一不可) ​

类型占比作用
常规50%反映主流程
边界20%空输入、超长、多语言、歧义
对抗15%注入、诱导编造、越权、有害请求
回归15%历史上出过错的 case,防退化

每条用例的结构 ​

json
{
  "id": "refund-003",
  "type": "常规",
  "input": "我上周买的鞋子想退,还能退吗?",
  "context_docs": ["policy/refund.md"],
  "expected": {
    "must_contain": ["7 天", "未穿着"],
    "must_not_contain": ["30 天", "随时"],
    "format": "text",
    "must_cite": true
  },
  "notes": "考察退货时效,文档里有明确条款"
}

关键:期望必须可机器判定。 用「必须包含 / 必须不包含 / 结构断言 / 引用检查」,而不是「回答要好」。

自动评分 ​

python
def check_case(output: str, exp: dict) -> dict:
    o = output or ""
    r = {"pass": True, "reasons": []}
    for kw in exp.get("must_contain", []):
        if kw not in o:
            r["pass"] = False; r["reasons"].append(f"缺少必备信息: {kw}")
    for kw in exp.get("must_not_contain", []):
        if kw in o:
            r["pass"] = False; r["reasons"].append(f"出现错误信息: {kw}")
    if exp.get("must_cite") and not re.search(r"\[\d+\]", o):
        r["pass"] = False; r["reasons"].append("缺少引用标注")
    return r

def run_suite(suite, fn):
    stats = {"total": len(suite), "pass": 0, "fails": []}
    for c in suite:
        out = fn(c["input"])
        res = check_case(out, c["expected"])
        if res["pass"]:
            stats["pass"] += 1
        else:
            stats["fails"].append({"id": c["id"], "out": out, **res})
    stats["rate"] = stats["pass"] / stats["total"]
    print(f"通过率 {stats['pass']}/{stats['total']} = {stats['rate']:.1%}")
    return stats

四、LLM-as-Judge 的正确用法 ​

用于「语义质量」这类无法用关键词断言的维度。

python
JUDGE = """你是严格评审。评分 1-5:5=完全正确且完整,3=部分正确,1=错误或编造。

【问题】{q}
【参考资料】{ref}
【回答】{a}

只输出 JSON:{{"score": 0, "hallucination": true/false, "reason": "20字以内"}}"""

校准流程(不可跳过) ​

步骤做法
1抽 50 条人工打分(两名标注者)
2算人工间一致性(Cohen's kappa,>0.6 才可用)
3用 judge 打同一批
4算 judge 与人工的一致性;不一致就改 rubric 重来
5之后每次改 judge 都要重新校准

judge 的四个偏差

偏差表现缓解
长度偏好长答案分高明确「简洁不扣分」,或按字数归一
位置偏好A/B 对比时偏爱第一个交换顺序各评一次
自我偏好偏爱同族模型的输出用第三方模型做 judge
宽松倾向分数普遍偏高给锚点示例(1分/3分/5分各一例)

五、可观测:每次请求都要能回放 ​

必须记录的结构化 trace ​

json
{
  "trace_id": "req_7f3a",
  "ts": "2026-11-06T10:20:31Z",
  "user_id": "u_123",
  "session_id": "s_9",
  "steps": [
    {"type": "rewrite", "in": "那能退吗", "out": "上周购买的鞋子能否退货", "ms": 180},
    {"type": "retrieve", "query": "鞋子 退货 时效", "top_k": 8,
     "hits": [{"doc": "policy/refund.md#3", "score": 0.82}], "ms": 45},
    {"type": "rerank", "kept": 4, "ms": 120},
    {"type": "llm", "model": "qwen2.5-7b", "prompt_tokens": 1520,
     "out_tokens": 186, "ms": 2100, "cost": 0.0021}
  ],
  "output": "可以退。签收 7 天内且未穿着…[1]",
  "feedback": {"thumbs": "up"}
}
字段为什么必须有
检索命中 + 分数判断「答错」是检索问题还是生成问题
token 与成本成本归因、异常检测
每步耗时性能瓶颈定位
feedback把线上投诉变成评测用例

三个最小必需的监控面板 ​

面板指标
质量通过率、judge 均分、负反馈率、拒答率
性能P50/P95 延迟、TTFT、超时率
成本每千次成本、日成本、token 分布

告警阈值:负反馈率 > 5%、P95 延迟 > 8s、日成本 > 预算 120%。

六、线上 → 线下的闭环 ​

线上负反馈 / 差评 → 人工确认 → 加入回归评测集 → 下次改动必须跑过

这是 AI 产品持续变好的唯一可靠机制。没有这条链路,模型永远在原地打转。

python
def promote_to_regression(trace, correction):
    """把线上失败样本固化为评测用例。"""
    return {
        "id": f"reg-{trace['trace_id']}",
        "type": "回归",
        "input": trace["steps"][0].get("in") or trace["input"],
        "expected": {"must_contain": correction["must_contain"],
                     "must_not_contain": correction.get("must_not_contain", [])},
        "notes": f"来源线上 {trace['ts']},原输出问题:{correction['why']}",
    }

七、发版流程(AI 版) ​

阶段检查
改动前现有评测集通过率基线已记录
改一处只改一个变量
本地L1 + L2 全跑,通过率不低于基线
灰度5%–10% 流量,对比在线指标
观察负反馈率、延迟、成本、新出现的失败类型
全量 / 回滚超阈值立即回滚(Prompt 与模型都要版本化)

Prompt 也要版本管理

把 Prompt 存成文件、进 git、每次变更记 CHANGELOG + 评测结果。 靠界面上直接改 Prompt 且无记录的团队,一定会在某天无法解释「为什么昨天还好好的」。

通过标准 ​

下一步 ​

→ 部署与成本:上线一个能赚钱的 AI 应用

AI 学习路线 · 从入门到专家