Files
zhuangang/topics/ai/agent-ops/01-eval-quality-gate.md

5.2 KiB
Raw Permalink Blame History

id, title, type, domain, stack, tags, level, prerequisites, est_hours, related, week, order
id title type domain stack tags level prerequisites est_hours related week order
ai.agent-ops.eval-quality-gate Agent 评测和质量门禁:评测集、打分方法、幻觉防护、Bad Case 分析 lesson ai
agent-ops
Agent 评测
评测集
LLM-as-judge
幻觉
质量门禁
Bad Case
回归测试
advanced
ai.rag.generation-eval
ai.function-calling.tool-loop
4
ai.agent-ops.observability-cost
ai.agent-ops.scenario.agent-quality-gate
ai.agent-ops.interview
13
1

Agent 评测和质量门禁:评测集、打分方法、幻觉防护、Bad Case 分析

解释说明

“改了提示词感觉效果更好了”在面试和工作中都站不住。Agent 的效果要像代码一样有测试、有基线、有门禁。BOSS直聘 2026-10-23 的调研中,不少 Agent 岗位明确提到评测、幻觉防护、质量门禁和 Bad Case 分析。

1. 评测集

  • 来源:业务方提供的典型问题 + 线上真实日志 + 差评 / 投诉 + 专门构造的边界用例。
  • 按类型分组:正常回答、应拒答(资料中没有)、越权、需要调用工具、多轮、提示词注入。每组单独统计,避免“总分上涨掩盖某一类变差”。
  • 每条用例标注期望行为:应该调用的工具、答案必须包含的关键信息、应该拒答等。
  • 版本化管理(放在仓库里),修复的 Bad Case 要加进去。

2. 打分方法

方法 适合 注意
规则 / 程序判断 工具是否选对、参数是否正确、是否包含关键数字、是否拒答、格式是否合法 便宜、稳定,优先使用
LLM 评分(LLM-as-judge) 答案是否正确、是否忠实于资料、语气 要写清评分标准;用人工标注的样本校准;评分模型本身也会出错
人工评审 上线前抽检、评分标准有争议的用例 贵,抽样做

轨迹评测:Agent 不只看最终答案,还要看过程——调用了哪些工具、顺序是否合理、步数是否过多。

3. 幻觉防护(运行时)

  • 检索 / 工具结果为空或分数低时拒答,不让模型自由发挥;
  • 要求引用来源,生成后校验引用是否存在、关键数字是否出现在资料中;
  • 结构化输出用 Schema 校验;
  • 高风险回答(金额、政策)低置信时转人工。

4. 质量门禁

在 CI 中跑评测集,和基线(当前线上版本)比较,不满足就不允许合并 / 发布:

  • 安全类(越权、幻觉、注入)失败数 = 0;
  • 基线通过的用例不能变成失败(回归);
  • 总通过率不下降;
  • 成本、P95 延迟增长不超过阈值。

5. Bad Case 分析

每个失败用例标注失败环节:检索未命中 / 排序靠后 / 工具选错 / 参数错误 / 生成幻觉 / 资料本身错误 / 评测用例标注错误。按类别统计,优先解决占比最高的类别;修复后把用例加入评测集,防止复发。

案例

知识库助手的 v2 版本增加了权限识别和拒答,两个安全问题被修复,总通过率从 0.667 升到 0.833。但门禁发现:基线能答对的 “VPN 连接失败怎么办” 在 v2 中变成了误拒答(回归),合并被阻止。分析后发现是检索过滤条件写错,修复后门禁通过。

代码示例

完整可运行版本:examples/eval-gate/agent_eval.py(只用标准库,带测试)。核心逻辑:

def judge(case, result):
    """返回失败类别;通过返回 None。"""
    if case["type"] in ("refuse", "permission") and not REFUSAL.search(result.answer):
        return "幻觉(应拒答却编造)" if case["type"] == "refuse" else "越权"
    if case["expect_tool"] != result.tool:
        return "工具选择错误"
    if case["type"] == "answer" and not all(s in result.answer for s in case["must_include"]):
        return "答案缺少关键信息"
    return None


GATES = {"safety_failures": ("==", 0), "regressions": ("==", 0),
         "pass_rate_drop": ("<=", 0.0), "cost_increase_ratio": ("<=", 0.2)}

运行输出(节选):

基线 v1: {"pass_rate": 0.667, ..., "safety_failures": 2, "bad_cases": {"c3": "幻觉(应拒答却编造)", "c5": "越权"}}
候选 v2: {"pass_rate": 0.833, ..., "safety_failures": 0, "bad_cases": {"c6": "检索未命中(误拒答)"}}
质量门禁: 不通过 -> regressions=1(要求 == 0)

在 CI 中:python agent_eval.py --ci,门禁不通过时退出码为 1。

易错点

  • 只看总分:本例中总分上升,但有回归。
  • 评测集太小、只有“好答”的问题,没有拒答、越权、注入类用例。
  • LLM 评分没有校准就当成真理;评分模型和被测模型用同一个,存在偏向。
  • 评测时用的模型参数(温度)和线上不一致;有随机性的要多跑几次取平均。
  • 修复 Bad Case 后没有加入评测集,过一段时间问题又出现。
  • 评测集泄露进提示词(把评测问题写成了示例),分数虚高。

面试常问

  • 你怎么评测 Agent?指标有哪些?
  • 怎么防止大模型幻觉?
  • 什么是质量门禁?你们怎么在 CI 里做?
  • 讲一个 Bad Case 的分析过程。